Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * JavaScript API.
9 */
11 #include "jsapi.h"
13 #include "mozilla/FloatingPoint.h"
14 #include "mozilla/PodOperations.h"
16 #include <ctype.h>
17 #include <stdarg.h>
18 #include <string.h>
19 #include <sys/stat.h>
21 #include "jsarray.h"
22 #include "jsatom.h"
23 #include "jsbool.h"
24 #include "jscntxt.h"
25 #include "jsdate.h"
26 #include "jsexn.h"
27 #include "jsfun.h"
28 #include "jsgc.h"
29 #include "jsiter.h"
30 #include "jslock.h"
31 #include "jsmath.h"
32 #include "jsnum.h"
33 #include "jsobj.h"
34 #include "json.h"
35 #include "jsprf.h"
36 #include "jsproxy.h"
37 #include "jsscript.h"
38 #include "jsstr.h"
39 #include "jstypes.h"
40 #include "jsutil.h"
41 #include "jswatchpoint.h"
42 #include "jsweakmap.h"
43 #ifdef JS_THREADSAFE
44 #include "jsworkers.h"
45 #endif
46 #include "jswrapper.h"
47 #include "prmjtime.h"
49 #if ENABLE_YARR_JIT
50 #include "assembler/jit/ExecutableAllocator.h"
51 #endif
52 #include "builtin/Eval.h"
53 #include "builtin/Intl.h"
54 #include "builtin/MapObject.h"
55 #include "builtin/RegExp.h"
56 #ifdef ENABLE_BINARYDATA
57 #include "builtin/SIMD.h"
58 #include "builtin/TypedObject.h"
59 #endif
60 #include "frontend/BytecodeCompiler.h"
61 #include "frontend/FullParseHandler.h" // for JS_BufferIsCompileableUnit
62 #include "frontend/Parser.h" // for JS_BufferIsCompileableUnit
63 #include "gc/Marking.h"
64 #include "jit/AsmJSLink.h"
65 #include "jit/JitCommon.h"
66 #include "js/CharacterEncoding.h"
67 #include "js/SliceBudget.h"
68 #include "js/StructuredClone.h"
69 #if ENABLE_INTL_API
70 #include "unicode/uclean.h"
71 #include "unicode/utypes.h"
72 #endif // ENABLE_INTL_API
73 #include "vm/DateObject.h"
74 #include "vm/Debugger.h"
75 #include "vm/ErrorObject.h"
76 #include "vm/Interpreter.h"
77 #include "vm/NumericConversions.h"
78 #include "vm/RegExpStatics.h"
79 #include "vm/Runtime.h"
80 #include "vm/Shape.h"
81 #include "vm/SharedArrayObject.h"
82 #include "vm/StopIterationObject.h"
83 #include "vm/StringBuffer.h"
84 #include "vm/TypedArrayObject.h"
85 #include "vm/WeakMapObject.h"
86 #include "vm/WrapperObject.h"
87 #include "vm/Xdr.h"
88 #include "yarr/BumpPointerAllocator.h"
90 #include "jsatominlines.h"
91 #include "jsfuninlines.h"
92 #include "jsinferinlines.h"
93 #include "jsscriptinlines.h"
95 #include "vm/Interpreter-inl.h"
96 #include "vm/ObjectImpl-inl.h"
97 #include "vm/String-inl.h"
99 using namespace js;
100 using namespace js::gc;
101 using namespace js::types;
103 using mozilla::Maybe;
104 using mozilla::PodCopy;
105 using mozilla::PodZero;
107 using js::frontend::Parser;
109 #ifdef HAVE_VA_LIST_AS_ARRAY
110 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
111 #else
112 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
113 #endif
115 /* Make sure that jschar is two bytes unsigned integer */
116 JS_STATIC_ASSERT((jschar)-1 > 0);
117 JS_STATIC_ASSERT(sizeof(jschar) == 2);
119 JS_PUBLIC_API(int64_t)
120 JS_Now()
121 {
122 return PRMJ_Now();
123 }
125 JS_PUBLIC_API(jsval)
126 JS_GetNaNValue(JSContext *cx)
127 {
128 return cx->runtime()->NaNValue;
129 }
131 JS_PUBLIC_API(jsval)
132 JS_GetNegativeInfinityValue(JSContext *cx)
133 {
134 return cx->runtime()->negativeInfinityValue;
135 }
137 JS_PUBLIC_API(jsval)
138 JS_GetPositiveInfinityValue(JSContext *cx)
139 {
140 return cx->runtime()->positiveInfinityValue;
141 }
143 JS_PUBLIC_API(jsval)
144 JS_GetEmptyStringValue(JSContext *cx)
145 {
146 return STRING_TO_JSVAL(cx->runtime()->emptyString);
147 }
149 JS_PUBLIC_API(JSString *)
150 JS_GetEmptyString(JSRuntime *rt)
151 {
152 JS_ASSERT(rt->hasContexts());
153 return rt->emptyString;
154 }
156 namespace js {
158 void
159 AssertHeapIsIdle(JSRuntime *rt)
160 {
161 JS_ASSERT(rt->heapState == js::Idle);
162 }
164 void
165 AssertHeapIsIdle(JSContext *cx)
166 {
167 AssertHeapIsIdle(cx->runtime());
168 }
170 }
172 static void
173 AssertHeapIsIdleOrIterating(JSRuntime *rt)
174 {
175 JS_ASSERT(!rt->isHeapCollecting());
176 }
178 static void
179 AssertHeapIsIdleOrIterating(JSContext *cx)
180 {
181 AssertHeapIsIdleOrIterating(cx->runtime());
182 }
184 static void
185 AssertHeapIsIdleOrStringIsFlat(JSContext *cx, JSString *str)
186 {
187 /*
188 * We allow some functions to be called during a GC as long as the argument
189 * is a flat string, since that will not cause allocation.
190 */
191 JS_ASSERT_IF(cx->runtime()->isHeapBusy(), str->isFlat());
192 }
194 JS_PUBLIC_API(bool)
195 JS_ConvertArguments(JSContext *cx, const CallArgs &args, const char *format, ...)
196 {
197 va_list ap;
198 bool ok;
200 AssertHeapIsIdle(cx);
202 va_start(ap, format);
203 ok = JS_ConvertArgumentsVA(cx, args, format, ap);
204 va_end(ap);
205 return ok;
206 }
208 JS_PUBLIC_API(bool)
209 JS_ConvertArgumentsVA(JSContext *cx, const CallArgs &args, const char *format, va_list ap)
210 {
211 unsigned index = 0;
212 bool required;
213 char c;
214 double d;
215 JSString *str;
216 RootedObject obj(cx);
217 RootedValue val(cx);
219 AssertHeapIsIdle(cx);
220 CHECK_REQUEST(cx);
221 assertSameCompartment(cx, args);
222 required = true;
223 while ((c = *format++) != '\0') {
224 if (isspace(c))
225 continue;
226 if (c == '/') {
227 required = false;
228 continue;
229 }
230 if (index == args.length()) {
231 if (required) {
232 if (JSFunction *fun = ReportIfNotFunction(cx, args.calleev())) {
233 char numBuf[12];
234 JS_snprintf(numBuf, sizeof numBuf, "%u", args.length());
235 JSAutoByteString funNameBytes;
236 if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
237 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
238 JSMSG_MORE_ARGS_NEEDED,
239 name, numBuf, (args.length() == 1) ? "" : "s");
240 }
241 }
242 return false;
243 }
244 break;
245 }
246 MutableHandleValue arg = args[index++];
247 switch (c) {
248 case 'b':
249 *va_arg(ap, bool *) = ToBoolean(arg);
250 break;
251 case 'c':
252 if (!ToUint16(cx, arg, va_arg(ap, uint16_t *)))
253 return false;
254 break;
255 case 'i':
256 case 'j': // "j" was broken, you should not use it.
257 if (!ToInt32(cx, arg, va_arg(ap, int32_t *)))
258 return false;
259 break;
260 case 'u':
261 if (!ToUint32(cx, arg, va_arg(ap, uint32_t *)))
262 return false;
263 break;
264 case 'd':
265 if (!ToNumber(cx, arg, va_arg(ap, double *)))
266 return false;
267 break;
268 case 'I':
269 if (!ToNumber(cx, arg, &d))
270 return false;
271 *va_arg(ap, double *) = ToInteger(d);
272 break;
273 case 'S':
274 case 'W':
275 str = ToString<CanGC>(cx, arg);
276 if (!str)
277 return false;
278 arg.setString(str);
279 if (c == 'W') {
280 JSFlatString *flat = str->ensureFlat(cx);
281 if (!flat)
282 return false;
283 *va_arg(ap, const jschar **) = flat->chars();
284 } else {
285 *va_arg(ap, JSString **) = str;
286 }
287 break;
288 case 'o':
289 if (arg.isNullOrUndefined()) {
290 obj = nullptr;
291 } else {
292 obj = ToObject(cx, arg);
293 if (!obj)
294 return false;
295 }
296 arg.setObjectOrNull(obj);
297 *va_arg(ap, JSObject **) = obj;
298 break;
299 case 'f':
300 obj = ReportIfNotFunction(cx, arg);
301 if (!obj)
302 return false;
303 arg.setObject(*obj);
304 *va_arg(ap, JSFunction **) = &obj->as<JSFunction>();
305 break;
306 case 'v':
307 *va_arg(ap, jsval *) = arg;
308 break;
309 case '*':
310 break;
311 default:
312 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_CHAR, format);
313 return false;
314 }
315 }
316 return true;
317 }
319 JS_PUBLIC_API(bool)
320 JS_ConvertValue(JSContext *cx, HandleValue value, JSType type, MutableHandleValue vp)
321 {
322 bool ok;
323 RootedObject obj(cx);
324 JSString *str;
325 double d;
327 AssertHeapIsIdle(cx);
328 CHECK_REQUEST(cx);
329 assertSameCompartment(cx, value);
330 switch (type) {
331 case JSTYPE_VOID:
332 vp.setUndefined();
333 ok = true;
334 break;
335 case JSTYPE_OBJECT:
336 if (value.isNullOrUndefined()) {
337 obj.set(nullptr);
338 } else {
339 obj = ToObject(cx, value);
340 if (!obj)
341 return false;
342 }
343 ok = true;
344 break;
345 case JSTYPE_FUNCTION:
346 vp.set(value);
347 obj = ReportIfNotFunction(cx, vp);
348 ok = (obj != nullptr);
349 break;
350 case JSTYPE_STRING:
351 str = ToString<CanGC>(cx, value);
352 ok = (str != nullptr);
353 if (ok)
354 vp.setString(str);
355 break;
356 case JSTYPE_NUMBER:
357 ok = ToNumber(cx, value, &d);
358 if (ok)
359 vp.setDouble(d);
360 break;
361 case JSTYPE_BOOLEAN:
362 vp.setBoolean(ToBoolean(value));
363 return true;
364 default: {
365 char numBuf[12];
366 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
367 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_TYPE, numBuf);
368 ok = false;
369 break;
370 }
371 }
372 return ok;
373 }
375 JS_PUBLIC_API(bool)
376 JS_ValueToObject(JSContext *cx, HandleValue value, MutableHandleObject objp)
377 {
378 AssertHeapIsIdle(cx);
379 CHECK_REQUEST(cx);
380 assertSameCompartment(cx, value);
381 if (value.isNullOrUndefined()) {
382 objp.set(nullptr);
383 return true;
384 }
385 JSObject *obj = ToObject(cx, value);
386 if (!obj)
387 return false;
388 objp.set(obj);
389 return true;
390 }
392 JS_PUBLIC_API(JSFunction *)
393 JS_ValueToFunction(JSContext *cx, HandleValue value)
394 {
395 AssertHeapIsIdle(cx);
396 CHECK_REQUEST(cx);
397 assertSameCompartment(cx, value);
398 return ReportIfNotFunction(cx, value);
399 }
401 JS_PUBLIC_API(JSFunction *)
402 JS_ValueToConstructor(JSContext *cx, HandleValue value)
403 {
404 AssertHeapIsIdle(cx);
405 CHECK_REQUEST(cx);
406 assertSameCompartment(cx, value);
407 return ReportIfNotFunction(cx, value);
408 }
410 JS_PUBLIC_API(JSString *)
411 JS_ValueToSource(JSContext *cx, HandleValue value)
412 {
413 AssertHeapIsIdle(cx);
414 CHECK_REQUEST(cx);
415 assertSameCompartment(cx, value);
416 return ValueToSource(cx, value);
417 }
419 JS_PUBLIC_API(bool)
420 JS_DoubleIsInt32(double d, int32_t *ip)
421 {
422 return mozilla::NumberIsInt32(d, ip);
423 }
425 JS_PUBLIC_API(int32_t)
426 JS_DoubleToInt32(double d)
427 {
428 return ToInt32(d);
429 }
431 JS_PUBLIC_API(uint32_t)
432 JS_DoubleToUint32(double d)
433 {
434 return ToUint32(d);
435 }
437 JS_PUBLIC_API(JSType)
438 JS_TypeOfValue(JSContext *cx, HandleValue value)
439 {
440 AssertHeapIsIdle(cx);
441 CHECK_REQUEST(cx);
442 assertSameCompartment(cx, value);
443 return TypeOfValue(value);
444 }
446 JS_PUBLIC_API(const char *)
447 JS_GetTypeName(JSContext *cx, JSType type)
448 {
449 if ((unsigned)type >= (unsigned)JSTYPE_LIMIT)
450 return nullptr;
451 return TypeStrings[type];
452 }
454 JS_PUBLIC_API(bool)
455 JS_StrictlyEqual(JSContext *cx, jsval value1, jsval value2, bool *equal)
456 {
457 AssertHeapIsIdle(cx);
458 CHECK_REQUEST(cx);
459 assertSameCompartment(cx, value1, value2);
460 bool eq;
461 if (!StrictlyEqual(cx, value1, value2, &eq))
462 return false;
463 *equal = eq;
464 return true;
465 }
467 JS_PUBLIC_API(bool)
468 JS_LooselyEqual(JSContext *cx, HandleValue value1, HandleValue value2, bool *equal)
469 {
470 AssertHeapIsIdle(cx);
471 CHECK_REQUEST(cx);
472 assertSameCompartment(cx, value1, value2);
473 JS_ASSERT(equal);
474 return LooselyEqual(cx, value1, value2, equal);
475 }
477 JS_PUBLIC_API(bool)
478 JS_SameValue(JSContext *cx, jsval value1, jsval value2, bool *same)
479 {
480 AssertHeapIsIdle(cx);
481 CHECK_REQUEST(cx);
482 assertSameCompartment(cx, value1, value2);
483 bool s;
484 if (!SameValue(cx, value1, value2, &s))
485 return false;
486 *same = s;
487 return true;
488 }
490 JS_PUBLIC_API(bool)
491 JS_IsBuiltinEvalFunction(JSFunction *fun)
492 {
493 return IsAnyBuiltinEval(fun);
494 }
496 JS_PUBLIC_API(bool)
497 JS_IsBuiltinFunctionConstructor(JSFunction *fun)
498 {
499 return fun->isBuiltinFunctionConstructor();
500 }
502 /************************************************************************/
504 /*
505 * SpiderMonkey's initialization status is tracked here, and it controls things
506 * that should happen only once across all runtimes. It's an API requirement
507 * that JS_Init (and JS_ShutDown, if called) be called in a thread-aware
508 * manner, so this variable doesn't need to be atomic.
509 *
510 * The only reason at present for the restriction that you can't call
511 * JS_Init/stuff/JS_ShutDown multiple times is the Windows PRMJ NowInit
512 * initialization code, which uses PR_CallOnce to initialize the PRMJ_Now
513 * subsystem. (For reinitialization to be permitted, we'd need to "reset" the
514 * called-once status -- doable, but more trouble than it's worth now.)
515 * Initializing that subsystem from JS_Init eliminates the problem, but
516 * initialization can take a comparatively long time (15ms or so), so we
517 * really don't want to do it in JS_Init, and we really do want to do it only
518 * when PRMJ_Now is eventually called.
519 */
520 enum InitState { Uninitialized, Running, ShutDown };
521 static InitState jsInitState = Uninitialized;
523 #ifdef DEBUG
524 static void
525 CheckMessageNumbering()
526 {
527 // Assert that the numbers associated with the error names in js.msg are
528 // monotonically increasing. It's not a compile-time check, but it's
529 // better than nothing.
530 int errorNumber = 0;
531 # define MSG_DEF(name, number, count, exception, format) \
532 JS_ASSERT(name == errorNumber++);
533 # include "js.msg"
534 # undef MSG_DEF
535 }
537 static unsigned
538 MessageParameterCount(const char *format)
539 {
540 unsigned numfmtspecs = 0;
541 for (const char *fmt = format; *fmt != '\0'; fmt++) {
542 if (*fmt == '{' && isdigit(fmt[1]))
543 ++numfmtspecs;
544 }
545 return numfmtspecs;
546 }
548 static void
549 CheckMessageParameterCounts()
550 {
551 // Assert that each message format has the correct number of braced
552 // parameters.
553 # define MSG_DEF(name, number, count, exception, format) \
554 JS_BEGIN_MACRO \
555 JS_ASSERT(MessageParameterCount(format) == count); \
556 JS_END_MACRO;
557 # include "js.msg"
558 # undef MSG_DEF
559 }
560 #endif /* DEBUG */
562 JS_PUBLIC_API(bool)
563 JS_Init(void)
564 {
565 MOZ_ASSERT(jsInitState == Uninitialized,
566 "must call JS_Init once before any JSAPI operation except "
567 "JS_SetICUMemoryFunctions");
568 MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
569 "how do we have live runtimes before JS_Init?");
571 #ifdef DEBUG
572 CheckMessageNumbering();
573 CheckMessageParameterCounts();
574 #endif
576 using js::TlsPerThreadData;
577 if (!TlsPerThreadData.initialized() && !TlsPerThreadData.init())
578 return false;
580 #if defined(JS_ION)
581 if (!jit::InitializeIon())
582 return false;
583 #endif
585 if (!ForkJoinContext::initialize())
586 return false;
588 #if EXPOSE_INTL_API
589 UErrorCode err = U_ZERO_ERROR;
590 u_init(&err);
591 if (U_FAILURE(err))
592 return false;
593 #endif // EXPOSE_INTL_API
595 jsInitState = Running;
596 return true;
597 }
599 JS_PUBLIC_API(void)
600 JS_ShutDown(void)
601 {
602 MOZ_ASSERT(jsInitState == Running,
603 "JS_ShutDown must only be called after JS_Init and can't race with it");
604 #ifdef DEBUG
605 if (JSRuntime::hasLiveRuntimes()) {
606 // Gecko is too buggy to assert this just yet.
607 fprintf(stderr,
608 "WARNING: YOU ARE LEAKING THE WORLD (at least one JSRuntime "
609 "and everything alive inside it, that is) AT JS_ShutDown "
610 "TIME. FIX THIS!\n");
611 }
612 #endif
614 #ifdef JS_THREADSAFE
615 WorkerThreadState().finish();
616 #endif
618 PRMJ_NowShutdown();
620 #if EXPOSE_INTL_API
621 u_cleanup();
622 #endif // EXPOSE_INTL_API
624 jsInitState = ShutDown;
625 }
627 #ifdef DEBUG
628 JS_FRIEND_API(bool)
629 JS::isGCEnabled()
630 {
631 return !TlsPerThreadData.get()->suppressGC;
632 }
633 #else
634 JS_FRIEND_API(bool) JS::isGCEnabled() { return true; }
635 #endif
637 JS_PUBLIC_API(JSRuntime *)
638 JS_NewRuntime(uint32_t maxbytes, JSUseHelperThreads useHelperThreads, JSRuntime *parentRuntime)
639 {
640 MOZ_ASSERT(jsInitState == Running,
641 "must call JS_Init prior to creating any JSRuntimes");
643 // Any parent runtime should be the topmost parent. This assert
644 // isn't required for correctness, but ensuring that the parent
645 // runtime is not destroyed before this one is more easily done
646 // for the main runtime in the process.
647 JS_ASSERT_IF(parentRuntime, !parentRuntime->parentRuntime);
649 JSRuntime *rt = js_new<JSRuntime>(parentRuntime, useHelperThreads);
650 if (!rt)
651 return nullptr;
653 if (!rt->init(maxbytes)) {
654 JS_DestroyRuntime(rt);
655 return nullptr;
656 }
658 return rt;
659 }
661 JS_PUBLIC_API(void)
662 JS_DestroyRuntime(JSRuntime *rt)
663 {
664 js_delete(rt);
665 }
667 JS_PUBLIC_API(bool)
668 JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_ICUFreeFn freeFn)
669 {
670 MOZ_ASSERT(jsInitState == Uninitialized,
671 "must call JS_SetICUMemoryFunctions before any other JSAPI "
672 "operation (including JS_Init)");
674 #if EXPOSE_INTL_API
675 UErrorCode status = U_ZERO_ERROR;
676 u_setMemoryFunctions(/* context = */ nullptr, allocFn, reallocFn, freeFn, &status);
677 return U_SUCCESS(status);
678 #else
679 return true;
680 #endif
681 }
683 JS_PUBLIC_API(void *)
684 JS_GetRuntimePrivate(JSRuntime *rt)
685 {
686 return rt->data;
687 }
689 JS_PUBLIC_API(void)
690 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
691 {
692 rt->data = data;
693 }
695 #ifdef JS_THREADSAFE
696 static void
697 StartRequest(JSContext *cx)
698 {
699 JSRuntime *rt = cx->runtime();
700 JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
702 if (rt->requestDepth) {
703 rt->requestDepth++;
704 } else {
705 /* Indicate that a request is running. */
706 rt->requestDepth = 1;
707 rt->triggerActivityCallback(true);
708 }
709 }
711 static void
712 StopRequest(JSContext *cx)
713 {
714 JSRuntime *rt = cx->runtime();
715 JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
717 JS_ASSERT(rt->requestDepth != 0);
718 if (rt->requestDepth != 1) {
719 rt->requestDepth--;
720 } else {
721 rt->conservativeGC.updateForRequestEnd();
722 rt->requestDepth = 0;
723 rt->triggerActivityCallback(false);
724 }
725 }
726 #endif /* JS_THREADSAFE */
728 JS_PUBLIC_API(void)
729 JS_BeginRequest(JSContext *cx)
730 {
731 #ifdef JS_THREADSAFE
732 cx->outstandingRequests++;
733 StartRequest(cx);
734 #endif
735 }
737 JS_PUBLIC_API(void)
738 JS_EndRequest(JSContext *cx)
739 {
740 #ifdef JS_THREADSAFE
741 JS_ASSERT(cx->outstandingRequests != 0);
742 cx->outstandingRequests--;
743 StopRequest(cx);
744 #endif
745 }
747 JS_PUBLIC_API(bool)
748 JS_IsInRequest(JSRuntime *rt)
749 {
750 #ifdef JS_THREADSAFE
751 JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
752 return rt->requestDepth != 0;
753 #else
754 return false;
755 #endif
756 }
758 JS_PUBLIC_API(void)
759 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback, void *data)
760 {
761 rt->cxCallback = cxCallback;
762 rt->cxCallbackData = data;
763 }
765 JS_PUBLIC_API(JSContext *)
766 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
767 {
768 return NewContext(rt, stackChunkSize);
769 }
771 JS_PUBLIC_API(void)
772 JS_DestroyContext(JSContext *cx)
773 {
774 JS_ASSERT(!cx->compartment());
775 DestroyContext(cx, DCM_FORCE_GC);
776 }
778 JS_PUBLIC_API(void)
779 JS_DestroyContextNoGC(JSContext *cx)
780 {
781 JS_ASSERT(!cx->compartment());
782 DestroyContext(cx, DCM_NO_GC);
783 }
785 JS_PUBLIC_API(void *)
786 JS_GetContextPrivate(JSContext *cx)
787 {
788 return cx->data;
789 }
791 JS_PUBLIC_API(void)
792 JS_SetContextPrivate(JSContext *cx, void *data)
793 {
794 cx->data = data;
795 }
797 JS_PUBLIC_API(void *)
798 JS_GetSecondContextPrivate(JSContext *cx)
799 {
800 return cx->data2;
801 }
803 JS_PUBLIC_API(void)
804 JS_SetSecondContextPrivate(JSContext *cx, void *data)
805 {
806 cx->data2 = data;
807 }
809 JS_PUBLIC_API(JSRuntime *)
810 JS_GetRuntime(JSContext *cx)
811 {
812 return cx->runtime();
813 }
815 JS_PUBLIC_API(JSRuntime *)
816 JS_GetParentRuntime(JSContext *cx)
817 {
818 JSRuntime *rt = cx->runtime();
819 return rt->parentRuntime ? rt->parentRuntime : rt;
820 }
822 JS_PUBLIC_API(JSContext *)
823 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
824 {
825 JSContext *cx = *iterp;
826 cx = cx ? cx->getNext() : rt->contextList.getFirst();
827 *iterp = cx;
828 return cx;
829 }
831 JS_PUBLIC_API(JSVersion)
832 JS_GetVersion(JSContext *cx)
833 {
834 return VersionNumber(cx->findVersion());
835 }
837 JS_PUBLIC_API(void)
838 JS_SetVersionForCompartment(JSCompartment *compartment, JSVersion version)
839 {
840 compartment->options().setVersion(version);
841 }
843 static const struct v2smap {
844 JSVersion version;
845 const char *string;
846 } v2smap[] = {
847 {JSVERSION_ECMA_3, "ECMAv3"},
848 {JSVERSION_1_6, "1.6"},
849 {JSVERSION_1_7, "1.7"},
850 {JSVERSION_1_8, "1.8"},
851 {JSVERSION_ECMA_5, "ECMAv5"},
852 {JSVERSION_DEFAULT, js_default_str},
853 {JSVERSION_DEFAULT, "1.0"},
854 {JSVERSION_DEFAULT, "1.1"},
855 {JSVERSION_DEFAULT, "1.2"},
856 {JSVERSION_DEFAULT, "1.3"},
857 {JSVERSION_DEFAULT, "1.4"},
858 {JSVERSION_DEFAULT, "1.5"},
859 {JSVERSION_UNKNOWN, nullptr}, /* must be last, nullptr is sentinel */
860 };
862 JS_PUBLIC_API(const char *)
863 JS_VersionToString(JSVersion version)
864 {
865 int i;
867 for (i = 0; v2smap[i].string; i++)
868 if (v2smap[i].version == version)
869 return v2smap[i].string;
870 return "unknown";
871 }
873 JS_PUBLIC_API(JSVersion)
874 JS_StringToVersion(const char *string)
875 {
876 int i;
878 for (i = 0; v2smap[i].string; i++)
879 if (strcmp(v2smap[i].string, string) == 0)
880 return v2smap[i].version;
881 return JSVERSION_UNKNOWN;
882 }
884 JS_PUBLIC_API(JS::RuntimeOptions &)
885 JS::RuntimeOptionsRef(JSRuntime *rt)
886 {
887 return rt->options();
888 }
890 JS_PUBLIC_API(JS::RuntimeOptions &)
891 JS::RuntimeOptionsRef(JSContext *cx)
892 {
893 return cx->runtime()->options();
894 }
896 JS_PUBLIC_API(JS::ContextOptions &)
897 JS::ContextOptionsRef(JSContext *cx)
898 {
899 return cx->options();
900 }
902 JS_PUBLIC_API(const char *)
903 JS_GetImplementationVersion(void)
904 {
905 return "JavaScript-C" MOZILLA_VERSION;
906 }
908 JS_PUBLIC_API(void)
909 JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback callback)
910 {
911 rt->destroyCompartmentCallback = callback;
912 }
914 JS_PUBLIC_API(void)
915 JS_SetDestroyZoneCallback(JSRuntime *rt, JSZoneCallback callback)
916 {
917 rt->destroyZoneCallback = callback;
918 }
920 JS_PUBLIC_API(void)
921 JS_SetSweepZoneCallback(JSRuntime *rt, JSZoneCallback callback)
922 {
923 rt->sweepZoneCallback = callback;
924 }
926 JS_PUBLIC_API(void)
927 JS_SetCompartmentNameCallback(JSRuntime *rt, JSCompartmentNameCallback callback)
928 {
929 rt->compartmentNameCallback = callback;
930 }
932 JS_PUBLIC_API(void)
933 JS_SetWrapObjectCallbacks(JSRuntime *rt, const JSWrapObjectCallbacks *callbacks)
934 {
935 rt->wrapObjectCallbacks = callbacks;
936 }
938 JS_PUBLIC_API(JSCompartment *)
939 JS_EnterCompartment(JSContext *cx, JSObject *target)
940 {
941 AssertHeapIsIdle(cx);
942 CHECK_REQUEST(cx);
944 JSCompartment *oldCompartment = cx->compartment();
945 cx->enterCompartment(target->compartment());
946 return oldCompartment;
947 }
949 JS_PUBLIC_API(JSCompartment *)
950 JS_EnterCompartmentOfScript(JSContext *cx, JSScript *target)
951 {
952 AssertHeapIsIdle(cx);
953 CHECK_REQUEST(cx);
954 GlobalObject &global = target->global();
955 return JS_EnterCompartment(cx, &global);
956 }
958 JS_PUBLIC_API(void)
959 JS_LeaveCompartment(JSContext *cx, JSCompartment *oldCompartment)
960 {
961 AssertHeapIsIdle(cx);
962 CHECK_REQUEST(cx);
963 cx->leaveCompartment(oldCompartment);
964 }
966 JSAutoCompartment::JSAutoCompartment(JSContext *cx, JSObject *target)
967 : cx_(cx),
968 oldCompartment_(cx->compartment())
969 {
970 AssertHeapIsIdleOrIterating(cx_);
971 cx_->enterCompartment(target->compartment());
972 }
974 JSAutoCompartment::JSAutoCompartment(JSContext *cx, JSScript *target)
975 : cx_(cx),
976 oldCompartment_(cx->compartment())
977 {
978 AssertHeapIsIdleOrIterating(cx_);
979 cx_->enterCompartment(target->compartment());
980 }
982 JSAutoCompartment::~JSAutoCompartment()
983 {
984 cx_->leaveCompartment(oldCompartment_);
985 }
987 JSAutoNullCompartment::JSAutoNullCompartment(JSContext *cx)
988 : cx_(cx),
989 oldCompartment_(cx->compartment())
990 {
991 AssertHeapIsIdleOrIterating(cx_);
992 cx_->enterNullCompartment();
993 }
995 JSAutoNullCompartment::~JSAutoNullCompartment()
996 {
997 cx_->leaveCompartment(oldCompartment_);
998 }
1000 JS_PUBLIC_API(void)
1001 JS_SetCompartmentPrivate(JSCompartment *compartment, void *data)
1002 {
1003 compartment->data = data;
1004 }
1006 JS_PUBLIC_API(void *)
1007 JS_GetCompartmentPrivate(JSCompartment *compartment)
1008 {
1009 return compartment->data;
1010 }
1012 JS_PUBLIC_API(void)
1013 JS_SetZoneUserData(JS::Zone *zone, void *data)
1014 {
1015 zone->data = data;
1016 }
1018 JS_PUBLIC_API(void *)
1019 JS_GetZoneUserData(JS::Zone *zone)
1020 {
1021 return zone->data;
1022 }
1024 JS_PUBLIC_API(bool)
1025 JS_WrapObject(JSContext *cx, MutableHandleObject objp)
1026 {
1027 AssertHeapIsIdle(cx);
1028 CHECK_REQUEST(cx);
1029 if (objp)
1030 JS::ExposeGCThingToActiveJS(objp, JSTRACE_OBJECT);
1031 return cx->compartment()->wrap(cx, objp);
1032 }
1034 JS_PUBLIC_API(bool)
1035 JS_WrapValue(JSContext *cx, MutableHandleValue vp)
1036 {
1037 AssertHeapIsIdle(cx);
1038 CHECK_REQUEST(cx);
1039 JS::ExposeValueToActiveJS(vp);
1040 return cx->compartment()->wrap(cx, vp);
1041 }
1043 JS_PUBLIC_API(bool)
1044 JS_WrapId(JSContext *cx, JS::MutableHandleId idp)
1045 {
1046 AssertHeapIsIdle(cx);
1047 CHECK_REQUEST(cx);
1048 jsid id = idp.get();
1049 if (JSID_IS_STRING(id))
1050 JS::ExposeGCThingToActiveJS(JSID_TO_STRING(id), JSTRACE_STRING);
1051 else if (JSID_IS_OBJECT(id))
1052 JS::ExposeGCThingToActiveJS(JSID_TO_OBJECT(id), JSTRACE_OBJECT);
1053 return cx->compartment()->wrapId(cx, idp.address());
1054 }
1056 /*
1057 * Identity remapping. Not for casual consumers.
1058 *
1059 * Normally, an object's contents and its identity are inextricably linked.
1060 * Identity is determined by the address of the JSObject* in the heap, and
1061 * the contents are what is located at that address. Transplanting allows these
1062 * concepts to be separated through a combination of swapping (exchanging the
1063 * contents of two same-compartment objects) and remapping cross-compartment
1064 * identities by altering wrappers.
1065 *
1066 * The |origobj| argument should be the object whose identity needs to be
1067 * remapped, usually to another compartment. The contents of |origobj| are
1068 * destroyed.
1069 *
1070 * The |target| argument serves two purposes:
1071 *
1072 * First, |target| serves as a hint for the new identity of the object. The new
1073 * identity object will always be in the same compartment as |target|, but
1074 * if that compartment already had an object representing |origobj| (either a
1075 * cross-compartment wrapper for it, or |origobj| itself if the two arguments
1076 * are same-compartment), the existing object is used. Otherwise, |target|
1077 * itself is used. To avoid ambiguity, JS_TransplantObject always returns the
1078 * new identity.
1079 *
1080 * Second, the new identity object's contents will be those of |target|. A swap()
1081 * is used to make this happen if an object other than |target| is used.
1082 *
1083 * We don't have a good way to recover from failure in this function, so
1084 * we intentionally crash instead.
1085 */
1087 JS_PUBLIC_API(JSObject *)
1088 JS_TransplantObject(JSContext *cx, HandleObject origobj, HandleObject target)
1089 {
1090 AssertHeapIsIdle(cx);
1091 JS_ASSERT(origobj != target);
1092 JS_ASSERT(!origobj->is<CrossCompartmentWrapperObject>());
1093 JS_ASSERT(!target->is<CrossCompartmentWrapperObject>());
1095 RootedValue origv(cx, ObjectValue(*origobj));
1096 RootedObject newIdentity(cx);
1098 {
1099 // Scope to make ~AutoMaybeTouchDeadZones do its GC before the return value is on the stack.
1100 AutoMaybeTouchDeadZones agc(cx);
1101 AutoDisableProxyCheck adpc(cx->runtime());
1103 JSCompartment *destination = target->compartment();
1105 if (origobj->compartment() == destination) {
1106 // If the original object is in the same compartment as the
1107 // destination, then we know that we won't find a wrapper in the
1108 // destination's cross compartment map and that the same
1109 // object will continue to work.
1110 if (!JSObject::swap(cx, origobj, target))
1111 MOZ_CRASH();
1112 newIdentity = origobj;
1113 } else if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
1114 // There might already be a wrapper for the original object in
1115 // the new compartment. If there is, we use its identity and swap
1116 // in the contents of |target|.
1117 newIdentity = &p->value().toObject();
1119 // When we remove origv from the wrapper map, its wrapper, newIdentity,
1120 // must immediately cease to be a cross-compartment wrapper. Neuter it.
1121 destination->removeWrapper(p);
1122 NukeCrossCompartmentWrapper(cx, newIdentity);
1124 if (!JSObject::swap(cx, newIdentity, target))
1125 MOZ_CRASH();
1126 } else {
1127 // Otherwise, we use |target| for the new identity object.
1128 newIdentity = target;
1129 }
1131 // Now, iterate through other scopes looking for references to the
1132 // old object, and update the relevant cross-compartment wrappers.
1133 if (!RemapAllWrappersForObject(cx, origobj, newIdentity))
1134 MOZ_CRASH();
1136 // Lastly, update the original object to point to the new one.
1137 if (origobj->compartment() != destination) {
1138 RootedObject newIdentityWrapper(cx, newIdentity);
1139 AutoCompartment ac(cx, origobj);
1140 if (!JS_WrapObject(cx, &newIdentityWrapper))
1141 MOZ_CRASH();
1142 JS_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
1143 if (!JSObject::swap(cx, origobj, newIdentityWrapper))
1144 MOZ_CRASH();
1145 origobj->compartment()->putWrapper(cx, ObjectValue(*newIdentity), origv);
1146 }
1147 }
1149 // The new identity object might be one of several things. Return it to avoid
1150 // ambiguity.
1151 return newIdentity;
1152 }
1154 /*
1155 * Recompute all cross-compartment wrappers for an object, resetting state.
1156 * Gecko uses this to clear Xray wrappers when doing a navigation that reuses
1157 * the inner window and global object.
1158 */
1159 JS_PUBLIC_API(bool)
1160 JS_RefreshCrossCompartmentWrappers(JSContext *cx, HandleObject obj)
1161 {
1162 return RemapAllWrappersForObject(cx, obj, obj);
1163 }
1165 JS_PUBLIC_API(bool)
1166 JS_InitStandardClasses(JSContext *cx, HandleObject obj)
1167 {
1168 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
1169 AssertHeapIsIdle(cx);
1170 CHECK_REQUEST(cx);
1172 cx->setDefaultCompartmentObjectIfUnset(obj);
1173 assertSameCompartment(cx, obj);
1175 Rooted<GlobalObject*> global(cx, &obj->global());
1176 return GlobalObject::initStandardClasses(cx, global);
1177 }
1179 #define CLASP(name) (&name##Class)
1180 #define OCLASP(name) (&name##Object::class_)
1181 #define TYPED_ARRAY_CLASP(type) (&TypedArrayObject::classes[ScalarTypeDescr::type])
1182 #define EAGER_ATOM(name) NAME_OFFSET(name)
1183 #define EAGER_CLASS_ATOM(name) NAME_OFFSET(name)
1185 static js::Class DummyClass;
1186 static js::Class SentinelClass;
1188 typedef struct JSStdName {
1189 size_t atomOffset; /* offset of atom pointer in JSAtomState */
1190 const Class *clasp;
1191 bool isDummy() const { return clasp == &DummyClass; };
1192 bool isSentinel() const { return clasp == &SentinelClass; };
1193 } JSStdName;
1195 static const JSStdName*
1196 LookupStdName(JSRuntime *rt, HandleString name, const JSStdName *table)
1197 {
1198 MOZ_ASSERT(name->isAtom());
1199 for (unsigned i = 0; !table[i].isSentinel(); i++) {
1200 if (table[i].isDummy())
1201 continue;
1202 JSAtom *atom = AtomStateOffsetToName(*rt->commonNames, table[i].atomOffset);
1203 MOZ_ASSERT(atom);
1204 if (name == atom)
1205 return &table[i];
1206 }
1208 return nullptr;
1209 }
1211 /*
1212 * Table of standard classes, indexed by JSProtoKey. For entries where the
1213 * JSProtoKey does not correspond to a class with a meaningful constructor, we
1214 * insert a null entry into the table.
1215 */
1216 #define STD_NAME_ENTRY(name, code, init, clasp) { EAGER_CLASS_ATOM(name), clasp },
1217 #define STD_DUMMY_ENTRY(name, code, init, dummy) { 0, &DummyClass },
1218 static const JSStdName standard_class_names[] = {
1219 JS_FOR_PROTOTYPES(STD_NAME_ENTRY, STD_DUMMY_ENTRY)
1220 { 0, &SentinelClass }
1221 };
1223 /*
1224 * Table of top-level function and constant names and the init function of the
1225 * corresponding standard class that sets them up.
1226 */
1227 static const JSStdName builtin_property_names[] = {
1228 { EAGER_ATOM(eval), &JSObject::class_ },
1230 /* Global properties and functions defined by the Number class. */
1231 { EAGER_ATOM(NaN), OCLASP(Number) },
1232 { EAGER_ATOM(Infinity), OCLASP(Number) },
1233 { EAGER_ATOM(isNaN), OCLASP(Number) },
1234 { EAGER_ATOM(isFinite), OCLASP(Number) },
1235 { EAGER_ATOM(parseFloat), OCLASP(Number) },
1236 { EAGER_ATOM(parseInt), OCLASP(Number) },
1238 /* String global functions. */
1239 { EAGER_ATOM(escape), OCLASP(String) },
1240 { EAGER_ATOM(unescape), OCLASP(String) },
1241 { EAGER_ATOM(decodeURI), OCLASP(String) },
1242 { EAGER_ATOM(encodeURI), OCLASP(String) },
1243 { EAGER_ATOM(decodeURIComponent), OCLASP(String) },
1244 { EAGER_ATOM(encodeURIComponent), OCLASP(String) },
1245 #if JS_HAS_UNEVAL
1246 { EAGER_ATOM(uneval), OCLASP(String) },
1247 #endif
1248 #ifdef ENABLE_BINARYDATA
1249 { EAGER_ATOM(SIMD), OCLASP(SIMD) },
1250 { EAGER_ATOM(TypedObject), OCLASP(TypedObjectModule) },
1251 #endif
1253 { 0, &SentinelClass }
1254 };
1256 #undef CLASP
1257 #undef TYPED_ARRAY_CLASP
1258 #undef EAGER_ATOM
1259 #undef EAGER_CLASS_ATOM
1260 #undef EAGER_ATOM_CLASP
1262 JS_PUBLIC_API(bool)
1263 JS_ResolveStandardClass(JSContext *cx, HandleObject obj, HandleId id, bool *resolved)
1264 {
1265 JSRuntime *rt;
1266 const JSStdName *stdnm;
1268 AssertHeapIsIdle(cx);
1269 CHECK_REQUEST(cx);
1270 assertSameCompartment(cx, obj, id);
1272 Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
1273 *resolved = false;
1275 rt = cx->runtime();
1276 if (!rt->hasContexts() || !JSID_IS_ATOM(id))
1277 return true;
1279 RootedString idstr(cx, JSID_TO_STRING(id));
1281 /* Check whether we're resolving 'undefined', and define it if so. */
1282 JSAtom *undefinedAtom = cx->names().undefined;
1283 if (idstr == undefinedAtom) {
1284 *resolved = true;
1285 return JSObject::defineProperty(cx, obj, undefinedAtom->asPropertyName(),
1286 UndefinedHandleValue,
1287 JS_PropertyStub, JS_StrictPropertyStub,
1288 JSPROP_PERMANENT | JSPROP_READONLY);
1289 }
1291 /* Try for class constructors/prototypes named by well-known atoms. */
1292 stdnm = LookupStdName(rt, idstr, standard_class_names);
1294 /* Try less frequently used top-level functions and constants. */
1295 if (!stdnm)
1296 stdnm = LookupStdName(rt, idstr, builtin_property_names);
1298 // If this class is anonymous, then it doesn't exist as a global
1299 // property, so we won't resolve anything.
1300 if (stdnm && !(stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)) {
1301 JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(stdnm->clasp);
1302 if (!GlobalObject::ensureConstructor(cx, global, key))
1303 return false;
1305 *resolved = true;
1306 return true;
1307 }
1309 // There is no such property to resolve. An ordinary resolve hook would
1310 // just return true at this point. But the global object is special in one
1311 // more way: its prototype chain is lazily initialized. That is,
1312 // global->getProto() might be null right now because we haven't created
1313 // Object.prototype yet. Force it now.
1314 if (!global->getOrCreateObjectPrototype(cx))
1315 return false;
1317 return true;
1318 }
1320 JS_PUBLIC_API(bool)
1321 JS_EnumerateStandardClasses(JSContext *cx, HandleObject obj)
1322 {
1323 AssertHeapIsIdle(cx);
1324 CHECK_REQUEST(cx);
1325 assertSameCompartment(cx, obj);
1326 MOZ_ASSERT(obj->is<GlobalObject>());
1327 Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
1328 return GlobalObject::initStandardClasses(cx, global);
1329 }
1331 JS_PUBLIC_API(bool)
1332 JS_GetClassObject(JSContext *cx, JSProtoKey key, MutableHandleObject objp)
1333 {
1334 AssertHeapIsIdle(cx);
1335 CHECK_REQUEST(cx);
1336 return GetBuiltinConstructor(cx, key, objp);
1337 }
1339 JS_PUBLIC_API(bool)
1340 JS_GetClassPrototype(JSContext *cx, JSProtoKey key, MutableHandleObject objp)
1341 {
1342 AssertHeapIsIdle(cx);
1343 CHECK_REQUEST(cx);
1344 return GetBuiltinPrototype(cx, key, objp);
1345 }
1347 JS_PUBLIC_API(JSProtoKey)
1348 JS_IdToProtoKey(JSContext *cx, HandleId id)
1349 {
1350 AssertHeapIsIdle(cx);
1351 CHECK_REQUEST(cx);
1353 if (!JSID_IS_ATOM(id))
1354 return JSProto_Null;
1355 RootedString idstr(cx, JSID_TO_STRING(id));
1356 const JSStdName *stdnm = LookupStdName(cx->runtime(), idstr, standard_class_names);
1357 if (!stdnm)
1358 return JSProto_Null;
1360 MOZ_ASSERT(MOZ_ARRAY_LENGTH(standard_class_names) == JSProto_LIMIT + 1);
1361 return static_cast<JSProtoKey>(stdnm - standard_class_names);
1362 }
1364 JS_PUBLIC_API(JSObject *)
1365 JS_GetObjectPrototype(JSContext *cx, HandleObject forObj)
1366 {
1367 CHECK_REQUEST(cx);
1368 assertSameCompartment(cx, forObj);
1369 return forObj->global().getOrCreateObjectPrototype(cx);
1370 }
1372 JS_PUBLIC_API(JSObject *)
1373 JS_GetFunctionPrototype(JSContext *cx, HandleObject forObj)
1374 {
1375 CHECK_REQUEST(cx);
1376 assertSameCompartment(cx, forObj);
1377 return forObj->global().getOrCreateFunctionPrototype(cx);
1378 }
1380 JS_PUBLIC_API(JSObject *)
1381 JS_GetArrayPrototype(JSContext *cx, HandleObject forObj)
1382 {
1383 CHECK_REQUEST(cx);
1384 assertSameCompartment(cx, forObj);
1385 Rooted<GlobalObject*> global(cx, &forObj->global());
1386 return GlobalObject::getOrCreateArrayPrototype(cx, global);
1387 }
1389 JS_PUBLIC_API(JSObject *)
1390 JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
1391 {
1392 AssertHeapIsIdle(cx);
1393 assertSameCompartment(cx, obj);
1394 return &obj->global();
1395 }
1397 extern JS_PUBLIC_API(bool)
1398 JS_IsGlobalObject(JSObject *obj)
1399 {
1400 return obj->is<GlobalObject>();
1401 }
1403 JS_PUBLIC_API(JSObject *)
1404 JS_GetGlobalForCompartmentOrNull(JSContext *cx, JSCompartment *c)
1405 {
1406 AssertHeapIsIdleOrIterating(cx);
1407 assertSameCompartment(cx, c);
1408 return c->maybeGlobal();
1409 }
1411 JS_PUBLIC_API(JSObject *)
1412 JS::CurrentGlobalOrNull(JSContext *cx)
1413 {
1414 AssertHeapIsIdleOrIterating(cx);
1415 CHECK_REQUEST(cx);
1416 if (!cx->compartment())
1417 return nullptr;
1418 return cx->global();
1419 }
1421 JS_PUBLIC_API(jsval)
1422 JS_ComputeThis(JSContext *cx, jsval *vp)
1423 {
1424 AssertHeapIsIdle(cx);
1425 assertSameCompartment(cx, JSValueArray(vp, 2));
1426 CallReceiver call = CallReceiverFromVp(vp);
1427 if (!BoxNonStrictThis(cx, call))
1428 return JSVAL_NULL;
1429 return call.thisv();
1430 }
1432 JS_PUBLIC_API(void *)
1433 JS_malloc(JSContext *cx, size_t nbytes)
1434 {
1435 AssertHeapIsIdle(cx);
1436 CHECK_REQUEST(cx);
1437 return cx->malloc_(nbytes);
1438 }
1440 JS_PUBLIC_API(void *)
1441 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1442 {
1443 AssertHeapIsIdle(cx);
1444 CHECK_REQUEST(cx);
1445 return cx->realloc_(p, nbytes);
1446 }
1448 JS_PUBLIC_API(void)
1449 JS_free(JSContext *cx, void *p)
1450 {
1451 return js_free(p);
1452 }
1454 JS_PUBLIC_API(void)
1455 JS_freeop(JSFreeOp *fop, void *p)
1456 {
1457 return FreeOp::get(fop)->free_(p);
1458 }
1460 JS_PUBLIC_API(JSFreeOp *)
1461 JS_GetDefaultFreeOp(JSRuntime *rt)
1462 {
1463 return rt->defaultFreeOp();
1464 }
1466 JS_PUBLIC_API(void)
1467 JS_updateMallocCounter(JSContext *cx, size_t nbytes)
1468 {
1469 return cx->runtime()->updateMallocCounter(cx->zone(), nbytes);
1470 }
1472 JS_PUBLIC_API(char *)
1473 JS_strdup(JSContext *cx, const char *s)
1474 {
1475 AssertHeapIsIdle(cx);
1476 return js_strdup(cx, s);
1477 }
1479 JS_PUBLIC_API(char *)
1480 JS_strdup(JSRuntime *rt, const char *s)
1481 {
1482 AssertHeapIsIdle(rt);
1483 size_t n = strlen(s) + 1;
1484 void *p = rt->malloc_(n);
1485 if (!p)
1486 return nullptr;
1487 return static_cast<char*>(js_memcpy(p, s, n));
1488 }
1490 #undef JS_AddRoot
1492 JS_PUBLIC_API(bool)
1493 JS::AddValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp)
1494 {
1495 AssertHeapIsIdle(cx);
1496 CHECK_REQUEST(cx);
1497 return AddValueRoot(cx, vp->unsafeGet(), nullptr);
1498 }
1500 JS_PUBLIC_API(bool)
1501 JS::AddStringRoot(JSContext *cx, JS::Heap<JSString *> *rp)
1502 {
1503 AssertHeapIsIdle(cx);
1504 CHECK_REQUEST(cx);
1505 return AddStringRoot(cx, rp->unsafeGet(), nullptr);
1506 }
1508 JS_PUBLIC_API(bool)
1509 JS::AddObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp)
1510 {
1511 AssertHeapIsIdle(cx);
1512 CHECK_REQUEST(cx);
1513 return AddObjectRoot(cx, rp->unsafeGet(), nullptr);
1514 }
1516 JS_PUBLIC_API(bool)
1517 JS::AddNamedValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp, const char *name)
1518 {
1519 AssertHeapIsIdle(cx);
1520 CHECK_REQUEST(cx);
1521 return AddValueRoot(cx, vp->unsafeGet(), name);
1522 }
1524 JS_PUBLIC_API(bool)
1525 JS::AddNamedValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp, const char *name)
1526 {
1527 return AddValueRootRT(rt, vp->unsafeGet(), name);
1528 }
1530 JS_PUBLIC_API(bool)
1531 JS::AddNamedStringRoot(JSContext *cx, JS::Heap<JSString *> *rp, const char *name)
1532 {
1533 AssertHeapIsIdle(cx);
1534 CHECK_REQUEST(cx);
1535 return AddStringRoot(cx, rp->unsafeGet(), name);
1536 }
1538 JS_PUBLIC_API(bool)
1539 JS::AddNamedObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp, const char *name)
1540 {
1541 AssertHeapIsIdle(cx);
1542 CHECK_REQUEST(cx);
1543 return AddObjectRoot(cx, rp->unsafeGet(), name);
1544 }
1546 JS_PUBLIC_API(bool)
1547 JS::AddNamedScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp, const char *name)
1548 {
1549 AssertHeapIsIdle(cx);
1550 CHECK_REQUEST(cx);
1551 return AddScriptRoot(cx, rp->unsafeGet(), name);
1552 }
1554 /* We allow unrooting from finalizers within the GC */
1556 JS_PUBLIC_API(void)
1557 JS::RemoveValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp)
1558 {
1559 CHECK_REQUEST(cx);
1560 RemoveRoot(cx->runtime(), (void *)vp);
1561 *vp = UndefinedValue();
1562 }
1564 JS_PUBLIC_API(void)
1565 JS::RemoveStringRoot(JSContext *cx, JS::Heap<JSString *> *rp)
1566 {
1567 CHECK_REQUEST(cx);
1568 RemoveRoot(cx->runtime(), (void *)rp);
1569 *rp = nullptr;
1570 }
1572 JS_PUBLIC_API(void)
1573 JS::RemoveObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp)
1574 {
1575 CHECK_REQUEST(cx);
1576 RemoveRoot(cx->runtime(), (void *)rp);
1577 *rp = nullptr;
1578 }
1580 JS_PUBLIC_API(void)
1581 JS::RemoveScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp)
1582 {
1583 CHECK_REQUEST(cx);
1584 RemoveRoot(cx->runtime(), (void *)rp);
1585 *rp = nullptr;
1586 }
1588 JS_PUBLIC_API(void)
1589 JS::RemoveValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp)
1590 {
1591 RemoveRoot(rt, (void *)vp);
1592 *vp = UndefinedValue();
1593 }
1595 JS_PUBLIC_API(void)
1596 JS::RemoveStringRootRT(JSRuntime *rt, JS::Heap<JSString *> *rp)
1597 {
1598 RemoveRoot(rt, (void *)rp);
1599 *rp = nullptr;
1600 }
1602 JS_PUBLIC_API(void)
1603 JS::RemoveObjectRootRT(JSRuntime *rt, JS::Heap<JSObject *> *rp)
1604 {
1605 RemoveRoot(rt, (void *)rp);
1606 *rp = nullptr;
1607 }
1609 JS_PUBLIC_API(void)
1610 JS::RemoveScriptRootRT(JSRuntime *rt, JS::Heap<JSScript *> *rp)
1611 {
1612 RemoveRoot(rt, (void *)rp);
1613 *rp = nullptr;
1614 }
1616 JS_PUBLIC_API(bool)
1617 JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
1618 {
1619 AssertHeapIsIdle(rt);
1620 return !!rt->gcBlackRootTracers.append(JSRuntime::ExtraTracer(traceOp, data));
1621 }
1623 JS_PUBLIC_API(void)
1624 JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
1625 {
1626 AssertHeapIsIdle(rt);
1627 for (size_t i = 0; i < rt->gcBlackRootTracers.length(); i++) {
1628 JSRuntime::ExtraTracer *e = &rt->gcBlackRootTracers[i];
1629 if (e->op == traceOp && e->data == data) {
1630 rt->gcBlackRootTracers.erase(e);
1631 break;
1632 }
1633 }
1634 }
1636 #ifdef DEBUG
1638 typedef struct JSHeapDumpNode JSHeapDumpNode;
1640 struct JSHeapDumpNode {
1641 void *thing;
1642 JSGCTraceKind kind;
1643 JSHeapDumpNode *next; /* next sibling */
1644 JSHeapDumpNode *parent; /* node with the thing that refer to thing
1645 from this node */
1646 char edgeName[1]; /* name of the edge from parent->thing
1647 into thing */
1648 };
1650 typedef HashSet<void *, PointerHasher<void *, 3>, SystemAllocPolicy> VisitedSet;
1652 class DumpingTracer
1653 {
1654 public:
1655 DumpingTracer(JSRuntime *rt, JSTraceCallback callback)
1656 : base(rt, callback)
1657 {}
1659 JSTracer base;
1660 VisitedSet visited;
1661 bool ok;
1662 void *startThing;
1663 void *thingToFind;
1664 void *thingToIgnore;
1665 JSHeapDumpNode *parentNode;
1666 JSHeapDumpNode **lastNodep;
1667 char buffer[200];
1668 };
1670 static void
1671 DumpNotify(JSTracer *trc, void **thingp, JSGCTraceKind kind)
1672 {
1673 JS_ASSERT(trc->callback == DumpNotify);
1675 DumpingTracer *dtrc = (DumpingTracer *)trc;
1676 void *thing = *thingp;
1678 if (!dtrc->ok || thing == dtrc->thingToIgnore)
1679 return;
1681 /*
1682 * Check if we have already seen thing unless it is thingToFind to include
1683 * it to the graph each time we reach it and print all live things that
1684 * refer to thingToFind.
1685 *
1686 * This does not print all possible paths leading to thingToFind since
1687 * when a thing A refers directly or indirectly to thingToFind and A is
1688 * present several times in the graph, we will print only the first path
1689 * leading to A and thingToFind, other ways to reach A will be ignored.
1690 */
1691 if (dtrc->thingToFind != thing) {
1692 /*
1693 * The startThing check allows to avoid putting startThing into the
1694 * hash table before tracing startThing in JS_DumpHeap.
1695 */
1696 if (thing == dtrc->startThing)
1697 return;
1698 VisitedSet::AddPtr p = dtrc->visited.lookupForAdd(thing);
1699 if (p)
1700 return;
1701 if (!dtrc->visited.add(p, thing)) {
1702 dtrc->ok = false;
1703 return;
1704 }
1705 }
1707 const char *edgeName = dtrc->base.getTracingEdgeName(dtrc->buffer, sizeof(dtrc->buffer));
1708 size_t edgeNameSize = strlen(edgeName) + 1;
1709 size_t bytes = offsetof(JSHeapDumpNode, edgeName) + edgeNameSize;
1710 JSHeapDumpNode *node = (JSHeapDumpNode *) js_malloc(bytes);
1711 if (!node) {
1712 dtrc->ok = false;
1713 return;
1714 }
1716 node->thing = thing;
1717 node->kind = kind;
1718 node->next = nullptr;
1719 node->parent = dtrc->parentNode;
1720 js_memcpy(node->edgeName, edgeName, edgeNameSize);
1722 JS_ASSERT(!*dtrc->lastNodep);
1723 *dtrc->lastNodep = node;
1724 dtrc->lastNodep = &node->next;
1725 }
1727 /* Dump node and the chain that leads to thing it contains. */
1728 static bool
1729 DumpNode(DumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
1730 {
1731 JSHeapDumpNode *prev, *following;
1732 size_t chainLimit;
1733 enum { MAX_PARENTS_TO_PRINT = 10 };
1735 JS_GetTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
1736 &dtrc->base, node->thing, node->kind, true);
1737 if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
1738 return false;
1740 /*
1741 * We need to print the parent chain in the reverse order. To do it in
1742 * O(N) time where N is the chain length we first reverse the chain while
1743 * searching for the top and then print each node while restoring the
1744 * chain order.
1745 */
1746 chainLimit = MAX_PARENTS_TO_PRINT;
1747 prev = nullptr;
1748 for (;;) {
1749 following = node->parent;
1750 node->parent = prev;
1751 prev = node;
1752 node = following;
1753 if (!node)
1754 break;
1755 if (chainLimit == 0) {
1756 if (fputs("...", fp) < 0)
1757 return false;
1758 break;
1759 }
1760 --chainLimit;
1761 }
1763 node = prev;
1764 prev = following;
1765 bool ok = true;
1766 do {
1767 /* Loop must continue even when !ok to restore the parent chain. */
1768 if (ok) {
1769 if (!prev) {
1770 /* Print edge from some runtime root or startThing. */
1771 if (fputs(node->edgeName, fp) < 0)
1772 ok = false;
1773 } else {
1774 JS_GetTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
1775 &dtrc->base, prev->thing, prev->kind,
1776 false);
1777 if (fprintf(fp, "(%p %s).%s",
1778 prev->thing, dtrc->buffer, node->edgeName) < 0) {
1779 ok = false;
1780 }
1781 }
1782 }
1783 following = node->parent;
1784 node->parent = prev;
1785 prev = node;
1786 node = following;
1787 } while (node);
1789 return ok && putc('\n', fp) >= 0;
1790 }
1792 JS_PUBLIC_API(bool)
1793 JS_DumpHeap(JSRuntime *rt, FILE *fp, void* startThing, JSGCTraceKind startKind,
1794 void *thingToFind, size_t maxDepth, void *thingToIgnore)
1795 {
1796 if (maxDepth == 0)
1797 return true;
1799 DumpingTracer dtrc(rt, DumpNotify);
1800 if (!dtrc.visited.init())
1801 return false;
1802 dtrc.ok = true;
1803 dtrc.startThing = startThing;
1804 dtrc.thingToFind = thingToFind;
1805 dtrc.thingToIgnore = thingToIgnore;
1806 dtrc.parentNode = nullptr;
1807 JSHeapDumpNode *node = nullptr;
1808 dtrc.lastNodep = &node;
1809 if (!startThing) {
1810 JS_ASSERT(startKind == JSTRACE_OBJECT);
1811 TraceRuntime(&dtrc.base);
1812 } else {
1813 JS_TraceChildren(&dtrc.base, startThing, startKind);
1814 }
1816 if (!node)
1817 return dtrc.ok;
1819 size_t depth = 1;
1820 JSHeapDumpNode *children, *next, *parent;
1821 bool thingToFindWasTraced = thingToFind && thingToFind == startThing;
1822 for (;;) {
1823 /*
1824 * Loop must continue even when !dtrc.ok to free all nodes allocated
1825 * so far.
1826 */
1827 if (dtrc.ok) {
1828 if (thingToFind == nullptr || thingToFind == node->thing)
1829 dtrc.ok = DumpNode(&dtrc, fp, node);
1831 /* Descend into children. */
1832 if (dtrc.ok &&
1833 depth < maxDepth &&
1834 (thingToFind != node->thing || !thingToFindWasTraced)) {
1835 dtrc.parentNode = node;
1836 children = nullptr;
1837 dtrc.lastNodep = &children;
1838 JS_TraceChildren(&dtrc.base, node->thing, node->kind);
1839 if (thingToFind == node->thing)
1840 thingToFindWasTraced = true;
1841 if (children != nullptr) {
1842 ++depth;
1843 node = children;
1844 continue;
1845 }
1846 }
1847 }
1849 /* Move to next or parents next and free the node. */
1850 for (;;) {
1851 next = node->next;
1852 parent = node->parent;
1853 js_free(node);
1854 node = next;
1855 if (node)
1856 break;
1857 if (!parent)
1858 return dtrc.ok;
1859 JS_ASSERT(depth > 1);
1860 --depth;
1861 node = parent;
1862 }
1863 }
1865 JS_ASSERT(depth == 1);
1866 return dtrc.ok;
1867 }
1869 #endif /* DEBUG */
1871 extern JS_PUBLIC_API(bool)
1872 JS_IsGCMarkingTracer(JSTracer *trc)
1873 {
1874 return IS_GC_MARKING_TRACER(trc);
1875 }
1877 #ifdef DEBUG
1878 extern JS_PUBLIC_API(bool)
1879 JS_IsMarkingGray(JSTracer *trc)
1880 {
1881 JS_ASSERT(JS_IsGCMarkingTracer(trc));
1882 return trc->callback == GCMarker::GrayCallback;
1883 }
1884 #endif
1886 JS_PUBLIC_API(void)
1887 JS_GC(JSRuntime *rt)
1888 {
1889 AssertHeapIsIdle(rt);
1890 JS::PrepareForFullGC(rt);
1891 GC(rt, GC_NORMAL, JS::gcreason::API);
1892 }
1894 JS_PUBLIC_API(void)
1895 JS_MaybeGC(JSContext *cx)
1896 {
1897 MaybeGC(cx);
1898 }
1900 JS_PUBLIC_API(void)
1901 JS_SetGCCallback(JSRuntime *rt, JSGCCallback cb, void *data)
1902 {
1903 AssertHeapIsIdle(rt);
1904 rt->gcCallback = cb;
1905 rt->gcCallbackData = data;
1906 }
1908 JS_PUBLIC_API(void)
1909 JS_SetFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb)
1910 {
1911 AssertHeapIsIdle(rt);
1912 rt->gcFinalizeCallback = cb;
1913 }
1915 JS_PUBLIC_API(bool)
1916 JS_IsAboutToBeFinalized(JS::Heap<JSObject *> *objp)
1917 {
1918 return IsObjectAboutToBeFinalized(objp->unsafeGet());
1919 }
1921 JS_PUBLIC_API(bool)
1922 JS_IsAboutToBeFinalizedUnbarriered(JSObject **objp)
1923 {
1924 return IsObjectAboutToBeFinalized(objp);
1925 }
1927 JS_PUBLIC_API(void)
1928 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32_t value)
1929 {
1930 switch (key) {
1931 case JSGC_MAX_BYTES: {
1932 JS_ASSERT(value >= rt->gcBytes);
1933 rt->gcMaxBytes = value;
1934 break;
1935 }
1936 case JSGC_MAX_MALLOC_BYTES:
1937 rt->setGCMaxMallocBytes(value);
1938 break;
1939 case JSGC_SLICE_TIME_BUDGET:
1940 rt->gcSliceBudget = SliceBudget::TimeBudget(value);
1941 break;
1942 case JSGC_MARK_STACK_LIMIT:
1943 js::SetMarkStackLimit(rt, value);
1944 break;
1945 case JSGC_HIGH_FREQUENCY_TIME_LIMIT:
1946 rt->gcHighFrequencyTimeThreshold = value;
1947 break;
1948 case JSGC_HIGH_FREQUENCY_LOW_LIMIT:
1949 rt->gcHighFrequencyLowLimitBytes = value * 1024 * 1024;
1950 break;
1951 case JSGC_HIGH_FREQUENCY_HIGH_LIMIT:
1952 rt->gcHighFrequencyHighLimitBytes = value * 1024 * 1024;
1953 break;
1954 case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX:
1955 rt->gcHighFrequencyHeapGrowthMax = value / 100.0;
1956 MOZ_ASSERT(rt->gcHighFrequencyHeapGrowthMax / 0.85 > 1.0);
1957 break;
1958 case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN:
1959 rt->gcHighFrequencyHeapGrowthMin = value / 100.0;
1960 MOZ_ASSERT(rt->gcHighFrequencyHeapGrowthMin / 0.85 > 1.0);
1961 break;
1962 case JSGC_LOW_FREQUENCY_HEAP_GROWTH:
1963 rt->gcLowFrequencyHeapGrowth = value / 100.0;
1964 MOZ_ASSERT(rt->gcLowFrequencyHeapGrowth / 0.9 > 1.0);
1965 break;
1966 case JSGC_DYNAMIC_HEAP_GROWTH:
1967 rt->gcDynamicHeapGrowth = value;
1968 break;
1969 case JSGC_DYNAMIC_MARK_SLICE:
1970 rt->gcDynamicMarkSlice = value;
1971 break;
1972 case JSGC_ALLOCATION_THRESHOLD:
1973 rt->gcAllocationThreshold = value * 1024 * 1024;
1974 break;
1975 case JSGC_DECOMMIT_THRESHOLD:
1976 rt->gcDecommitThreshold = value * 1024 * 1024;
1977 break;
1978 default:
1979 JS_ASSERT(key == JSGC_MODE);
1980 rt->setGCMode(JSGCMode(value));
1981 JS_ASSERT(rt->gcMode() == JSGC_MODE_GLOBAL ||
1982 rt->gcMode() == JSGC_MODE_COMPARTMENT ||
1983 rt->gcMode() == JSGC_MODE_INCREMENTAL);
1984 return;
1985 }
1986 }
1988 JS_PUBLIC_API(uint32_t)
1989 JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
1990 {
1991 switch (key) {
1992 case JSGC_MAX_BYTES:
1993 return uint32_t(rt->gcMaxBytes);
1994 case JSGC_MAX_MALLOC_BYTES:
1995 return rt->gcMaxMallocBytes;
1996 case JSGC_BYTES:
1997 return uint32_t(rt->gcBytes);
1998 case JSGC_MODE:
1999 return uint32_t(rt->gcMode());
2000 case JSGC_UNUSED_CHUNKS:
2001 return uint32_t(rt->gcChunkPool.getEmptyCount());
2002 case JSGC_TOTAL_CHUNKS:
2003 return uint32_t(rt->gcChunkSet.count() + rt->gcChunkPool.getEmptyCount());
2004 case JSGC_SLICE_TIME_BUDGET:
2005 return uint32_t(rt->gcSliceBudget > 0 ? rt->gcSliceBudget / PRMJ_USEC_PER_MSEC : 0);
2006 case JSGC_MARK_STACK_LIMIT:
2007 return rt->gcMarker.maxCapacity();
2008 case JSGC_HIGH_FREQUENCY_TIME_LIMIT:
2009 return rt->gcHighFrequencyTimeThreshold;
2010 case JSGC_HIGH_FREQUENCY_LOW_LIMIT:
2011 return rt->gcHighFrequencyLowLimitBytes / 1024 / 1024;
2012 case JSGC_HIGH_FREQUENCY_HIGH_LIMIT:
2013 return rt->gcHighFrequencyHighLimitBytes / 1024 / 1024;
2014 case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX:
2015 return uint32_t(rt->gcHighFrequencyHeapGrowthMax * 100);
2016 case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN:
2017 return uint32_t(rt->gcHighFrequencyHeapGrowthMin * 100);
2018 case JSGC_LOW_FREQUENCY_HEAP_GROWTH:
2019 return uint32_t(rt->gcLowFrequencyHeapGrowth * 100);
2020 case JSGC_DYNAMIC_HEAP_GROWTH:
2021 return rt->gcDynamicHeapGrowth;
2022 case JSGC_DYNAMIC_MARK_SLICE:
2023 return rt->gcDynamicMarkSlice;
2024 case JSGC_ALLOCATION_THRESHOLD:
2025 return rt->gcAllocationThreshold / 1024 / 1024;
2026 default:
2027 JS_ASSERT(key == JSGC_NUMBER);
2028 return uint32_t(rt->gcNumber);
2029 }
2030 }
2032 JS_PUBLIC_API(void)
2033 JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32_t value)
2034 {
2035 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2036 }
2038 JS_PUBLIC_API(uint32_t)
2039 JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key)
2040 {
2041 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2042 return 0;
2043 }
2045 static const size_t NumGCConfigs = 14;
2046 struct JSGCConfig {
2047 JSGCParamKey key;
2048 uint32_t value;
2049 };
2051 JS_PUBLIC_API(void)
2052 JS_SetGCParametersBasedOnAvailableMemory(JSRuntime *rt, uint32_t availMem)
2053 {
2054 static const JSGCConfig minimal[NumGCConfigs] = {
2055 {JSGC_MAX_MALLOC_BYTES, 6 * 1024 * 1024},
2056 {JSGC_SLICE_TIME_BUDGET, 30},
2057 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
2058 {JSGC_HIGH_FREQUENCY_HIGH_LIMIT, 40},
2059 {JSGC_HIGH_FREQUENCY_LOW_LIMIT, 0},
2060 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, 300},
2061 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, 120},
2062 {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 120},
2063 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
2064 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
2065 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
2066 {JSGC_ALLOCATION_THRESHOLD, 1},
2067 {JSGC_DECOMMIT_THRESHOLD, 1},
2068 {JSGC_MODE, JSGC_MODE_INCREMENTAL}
2069 };
2071 const JSGCConfig *config = minimal;
2072 if (availMem > 512) {
2073 static const JSGCConfig nominal[NumGCConfigs] = {
2074 {JSGC_MAX_MALLOC_BYTES, 6 * 1024 * 1024},
2075 {JSGC_SLICE_TIME_BUDGET, 30},
2076 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1000},
2077 {JSGC_HIGH_FREQUENCY_HIGH_LIMIT, 500},
2078 {JSGC_HIGH_FREQUENCY_LOW_LIMIT, 100},
2079 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX, 300},
2080 {JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN, 150},
2081 {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 150},
2082 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
2083 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
2084 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500},
2085 {JSGC_ALLOCATION_THRESHOLD, 30},
2086 {JSGC_DECOMMIT_THRESHOLD, 32},
2087 {JSGC_MODE, JSGC_MODE_COMPARTMENT}
2088 };
2090 config = nominal;
2091 }
2093 for (size_t i = 0; i < NumGCConfigs; i++)
2094 JS_SetGCParameter(rt, config[i].key, config[i].value);
2095 }
2098 JS_PUBLIC_API(JSString *)
2099 JS_NewExternalString(JSContext *cx, const jschar *chars, size_t length,
2100 const JSStringFinalizer *fin)
2101 {
2102 AssertHeapIsIdle(cx);
2103 CHECK_REQUEST(cx);
2104 JSString *s = JSExternalString::new_(cx, chars, length, fin);
2105 return s;
2106 }
2108 extern JS_PUBLIC_API(bool)
2109 JS_IsExternalString(JSString *str)
2110 {
2111 return str->isExternal();
2112 }
2114 extern JS_PUBLIC_API(const JSStringFinalizer *)
2115 JS_GetExternalStringFinalizer(JSString *str)
2116 {
2117 return str->asExternal().externalFinalizer();
2118 }
2120 static void
2121 SetNativeStackQuota(JSRuntime *rt, StackKind kind, size_t stackSize)
2122 {
2123 rt->nativeStackQuota[kind] = stackSize;
2124 if (rt->nativeStackBase)
2125 RecomputeStackLimit(rt, kind);
2126 }
2128 void
2129 js::RecomputeStackLimit(JSRuntime *rt, StackKind kind)
2130 {
2131 size_t stackSize = rt->nativeStackQuota[kind];
2132 #if JS_STACK_GROWTH_DIRECTION > 0
2133 if (stackSize == 0) {
2134 rt->mainThread.nativeStackLimit[kind] = UINTPTR_MAX;
2135 } else {
2136 JS_ASSERT(rt->nativeStackBase <= size_t(-1) - stackSize);
2137 rt->mainThread.nativeStackLimit[kind] =
2138 rt->nativeStackBase + stackSize - 1;
2139 }
2140 #else
2141 if (stackSize == 0) {
2142 rt->mainThread.nativeStackLimit[kind] = 0;
2143 } else {
2144 JS_ASSERT(rt->nativeStackBase >= stackSize);
2145 rt->mainThread.nativeStackLimit[kind] =
2146 rt->nativeStackBase - (stackSize - 1);
2147 }
2148 #endif
2150 // If there's no pending interrupt request set on the runtime's main thread's
2151 // jitStackLimit, then update it so that it reflects the new nativeStacklimit.
2152 //
2153 // Note that, for now, we use the untrusted limit for ion. This is fine,
2154 // because it's the most conservative limit, and if we hit it, we'll bail
2155 // out of ion into the interpeter, which will do a proper recursion check.
2156 #ifdef JS_ION
2157 if (kind == StackForUntrustedScript) {
2158 JSRuntime::AutoLockForInterrupt lock(rt);
2159 if (rt->mainThread.jitStackLimit != uintptr_t(-1)) {
2160 rt->mainThread.jitStackLimit = rt->mainThread.nativeStackLimit[kind];
2161 #ifdef JS_ARM_SIMULATOR
2162 rt->mainThread.jitStackLimit = jit::Simulator::StackLimit();
2163 #endif
2164 }
2165 }
2166 #endif
2167 }
2169 JS_PUBLIC_API(void)
2170 JS_SetNativeStackQuota(JSRuntime *rt, size_t systemCodeStackSize,
2171 size_t trustedScriptStackSize,
2172 size_t untrustedScriptStackSize)
2173 {
2174 JS_ASSERT_IF(trustedScriptStackSize,
2175 trustedScriptStackSize < systemCodeStackSize);
2176 if (!trustedScriptStackSize)
2177 trustedScriptStackSize = systemCodeStackSize;
2178 JS_ASSERT_IF(untrustedScriptStackSize,
2179 untrustedScriptStackSize < trustedScriptStackSize);
2180 if (!untrustedScriptStackSize)
2181 untrustedScriptStackSize = trustedScriptStackSize;
2182 SetNativeStackQuota(rt, StackForSystemCode, systemCodeStackSize);
2183 SetNativeStackQuota(rt, StackForTrustedScript, trustedScriptStackSize);
2184 SetNativeStackQuota(rt, StackForUntrustedScript, untrustedScriptStackSize);
2185 }
2187 /************************************************************************/
2189 JS_PUBLIC_API(int)
2190 JS_IdArrayLength(JSContext *cx, JSIdArray *ida)
2191 {
2192 return ida->length;
2193 }
2195 JS_PUBLIC_API(jsid)
2196 JS_IdArrayGet(JSContext *cx, JSIdArray *ida, int index)
2197 {
2198 JS_ASSERT(index >= 0 && index < ida->length);
2199 return ida->vector[index];
2200 }
2202 JS_PUBLIC_API(void)
2203 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
2204 {
2205 cx->runtime()->defaultFreeOp()->free_(ida);
2206 }
2208 JS_PUBLIC_API(bool)
2209 JS_ValueToId(JSContext *cx, HandleValue value, MutableHandleId idp)
2210 {
2211 AssertHeapIsIdle(cx);
2212 CHECK_REQUEST(cx);
2213 assertSameCompartment(cx, value);
2214 return ValueToId<CanGC>(cx, value, idp);
2215 }
2217 JS_PUBLIC_API(bool)
2218 JS_StringToId(JSContext *cx, HandleString string, MutableHandleId idp)
2219 {
2220 AssertHeapIsIdle(cx);
2221 CHECK_REQUEST(cx);
2222 assertSameCompartment(cx, string);
2223 RootedValue value(cx, StringValue(string));
2224 return ValueToId<CanGC>(cx, value, idp);
2225 }
2227 JS_PUBLIC_API(bool)
2228 JS_IdToValue(JSContext *cx, jsid id, MutableHandleValue vp)
2229 {
2230 AssertHeapIsIdle(cx);
2231 CHECK_REQUEST(cx);
2232 vp.set(IdToValue(id));
2233 assertSameCompartment(cx, vp);
2234 return true;
2235 }
2237 JS_PUBLIC_API(bool)
2238 JS_DefaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp)
2239 {
2240 AssertHeapIsIdle(cx);
2241 CHECK_REQUEST(cx);
2242 JS_ASSERT(obj != nullptr);
2243 JS_ASSERT(hint == JSTYPE_VOID || hint == JSTYPE_STRING || hint == JSTYPE_NUMBER);
2244 return JSObject::defaultValue(cx, obj, hint, vp);
2245 }
2247 JS_PUBLIC_API(bool)
2248 JS_PropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
2249 {
2250 return true;
2251 }
2253 JS_PUBLIC_API(bool)
2254 JS_StrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
2255 {
2256 return true;
2257 }
2259 JS_PUBLIC_API(bool)
2260 JS_DeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded)
2261 {
2262 *succeeded = true;
2263 return true;
2264 }
2266 JS_PUBLIC_API(bool)
2267 JS_EnumerateStub(JSContext *cx, HandleObject obj)
2268 {
2269 return true;
2270 }
2272 JS_PUBLIC_API(bool)
2273 JS_ResolveStub(JSContext *cx, HandleObject obj, HandleId id)
2274 {
2275 return true;
2276 }
2278 JS_PUBLIC_API(bool)
2279 JS_ConvertStub(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp)
2280 {
2281 JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION);
2282 JS_ASSERT(obj);
2283 return DefaultValue(cx, obj, type, vp);
2284 }
2286 JS_PUBLIC_API(JSObject *)
2287 JS_InitClass(JSContext *cx, HandleObject obj, HandleObject parent_proto,
2288 const JSClass *clasp, JSNative constructor, unsigned nargs,
2289 const JSPropertySpec *ps, const JSFunctionSpec *fs,
2290 const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs)
2291 {
2292 AssertHeapIsIdle(cx);
2293 CHECK_REQUEST(cx);
2294 assertSameCompartment(cx, obj, parent_proto);
2295 return js_InitClass(cx, obj, parent_proto, Valueify(clasp), constructor,
2296 nargs, ps, fs, static_ps, static_fs);
2297 }
2299 JS_PUBLIC_API(bool)
2300 JS_LinkConstructorAndPrototype(JSContext *cx, HandleObject ctor, HandleObject proto)
2301 {
2302 return LinkConstructorAndPrototype(cx, ctor, proto);
2303 }
2305 JS_PUBLIC_API(const JSClass *)
2306 JS_GetClass(JSObject *obj)
2307 {
2308 return obj->getJSClass();
2309 }
2311 JS_PUBLIC_API(bool)
2312 JS_InstanceOf(JSContext *cx, HandleObject obj, const JSClass *clasp, CallArgs *args)
2313 {
2314 AssertHeapIsIdle(cx);
2315 CHECK_REQUEST(cx);
2316 #ifdef DEBUG
2317 if (args) {
2318 assertSameCompartment(cx, obj);
2319 assertSameCompartment(cx, args->thisv(), args->calleev());
2320 }
2321 #endif
2322 if (!obj || obj->getJSClass() != clasp) {
2323 if (args)
2324 ReportIncompatibleMethod(cx, *args, Valueify(clasp));
2325 return false;
2326 }
2327 return true;
2328 }
2330 JS_PUBLIC_API(bool)
2331 JS_HasInstance(JSContext *cx, HandleObject obj, HandleValue value, bool *bp)
2332 {
2333 AssertHeapIsIdle(cx);
2334 assertSameCompartment(cx, obj, value);
2335 return HasInstance(cx, obj, value, bp);
2336 }
2338 JS_PUBLIC_API(void *)
2339 JS_GetPrivate(JSObject *obj)
2340 {
2341 /* This function can be called by a finalizer. */
2342 return obj->getPrivate();
2343 }
2345 JS_PUBLIC_API(void)
2346 JS_SetPrivate(JSObject *obj, void *data)
2347 {
2348 /* This function can be called by a finalizer. */
2349 obj->setPrivate(data);
2350 }
2352 JS_PUBLIC_API(void *)
2353 JS_GetInstancePrivate(JSContext *cx, HandleObject obj, const JSClass *clasp, CallArgs *args)
2354 {
2355 if (!JS_InstanceOf(cx, obj, clasp, args))
2356 return nullptr;
2357 return obj->getPrivate();
2358 }
2360 JS_PUBLIC_API(bool)
2361 JS_GetPrototype(JSContext *cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JSObject*> protop)
2362 {
2363 return JSObject::getProto(cx, obj, protop);
2364 }
2366 JS_PUBLIC_API(bool)
2367 JS_SetPrototype(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<JSObject*> proto)
2368 {
2369 AssertHeapIsIdle(cx);
2370 CHECK_REQUEST(cx);
2371 assertSameCompartment(cx, obj, proto);
2373 bool succeeded;
2374 if (!JSObject::setProto(cx, obj, proto, &succeeded))
2375 return false;
2377 if (!succeeded) {
2378 RootedValue val(cx, ObjectValue(*obj));
2379 js_ReportValueError(cx, JSMSG_SETPROTOTYPEOF_FAIL, JSDVG_IGNORE_STACK, val, js::NullPtr());
2380 return false;
2381 }
2383 return true;
2384 }
2386 JS_PUBLIC_API(JSObject *)
2387 JS_GetParent(JSObject *obj)
2388 {
2389 JS_ASSERT(!obj->is<ScopeObject>());
2390 return obj->getParent();
2391 }
2393 JS_PUBLIC_API(bool)
2394 JS_SetParent(JSContext *cx, HandleObject obj, HandleObject parent)
2395 {
2396 AssertHeapIsIdle(cx);
2397 CHECK_REQUEST(cx);
2398 JS_ASSERT(!obj->is<ScopeObject>());
2399 JS_ASSERT(parent || !obj->getParent());
2400 assertSameCompartment(cx, obj, parent);
2402 return JSObject::setParent(cx, obj, parent);
2403 }
2405 JS_PUBLIC_API(JSObject *)
2406 JS_GetConstructor(JSContext *cx, HandleObject proto)
2407 {
2408 AssertHeapIsIdle(cx);
2409 CHECK_REQUEST(cx);
2410 assertSameCompartment(cx, proto);
2412 RootedValue cval(cx);
2413 if (!JSObject::getProperty(cx, proto, proto, cx->names().constructor, &cval))
2414 return nullptr;
2415 if (!IsFunctionObject(cval)) {
2416 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
2417 proto->getClass()->name);
2418 return nullptr;
2419 }
2420 return &cval.toObject();
2421 }
2423 namespace {
2425 class AutoCompartmentRooter : private JS::CustomAutoRooter
2426 {
2427 public:
2428 explicit AutoCompartmentRooter(JSContext *cx, JSCompartment *comp
2429 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
2430 : CustomAutoRooter(cx), compartment(comp)
2431 {
2432 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
2433 }
2435 operator JSCompartment *() {
2436 return compartment;
2437 }
2439 JSCompartment *operator->() {
2440 return compartment;
2441 }
2443 protected:
2444 virtual void trace(JSTracer *trc)
2445 {
2446 compartment->mark();
2447 }
2449 private:
2450 JSCompartment *compartment;
2451 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
2452 };
2454 } /* anonymous namespace */
2456 bool
2457 JS::CompartmentOptions::cloneSingletons(JSContext *cx) const
2458 {
2459 return cloneSingletonsOverride_.get(cx->options().cloneSingletons());
2460 }
2462 JS::CompartmentOptions &
2463 JS::CompartmentOptions::setZone(ZoneSpecifier spec)
2464 {
2465 zone_.spec = spec;
2466 return *this;
2467 }
2469 JS::CompartmentOptions &
2470 JS::CompartmentOptions::setSameZoneAs(JSObject *obj)
2471 {
2472 zone_.pointer = static_cast<void *>(obj->zone());
2473 return *this;
2474 }
2476 JS::CompartmentOptions &
2477 JS::CompartmentOptionsRef(JSCompartment *compartment)
2478 {
2479 return compartment->options();
2480 }
2482 JS::CompartmentOptions &
2483 JS::CompartmentOptionsRef(JSObject *obj)
2484 {
2485 return obj->compartment()->options();
2486 }
2488 JS::CompartmentOptions &
2489 JS::CompartmentOptionsRef(JSContext *cx)
2490 {
2491 return cx->compartment()->options();
2492 }
2494 JS_PUBLIC_API(JSObject *)
2495 JS_NewGlobalObject(JSContext *cx, const JSClass *clasp, JSPrincipals *principals,
2496 JS::OnNewGlobalHookOption hookOption,
2497 const JS::CompartmentOptions &options /* = JS::CompartmentOptions() */)
2498 {
2499 AssertHeapIsIdle(cx);
2500 CHECK_REQUEST(cx);
2501 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
2502 JS_ASSERT(!cx->isExceptionPending());
2504 JSRuntime *rt = cx->runtime();
2506 Zone *zone;
2507 if (options.zoneSpecifier() == JS::SystemZone)
2508 zone = rt->systemZone;
2509 else if (options.zoneSpecifier() == JS::FreshZone)
2510 zone = nullptr;
2511 else
2512 zone = static_cast<Zone *>(options.zonePointer());
2514 AutoCompartmentRooter compartment(cx, NewCompartment(cx, zone, principals, options));
2515 if (!compartment)
2516 return nullptr;
2518 // Lazily create the system zone.
2519 if (!rt->systemZone && options.zoneSpecifier() == JS::SystemZone) {
2520 rt->systemZone = compartment->zone();
2521 rt->systemZone->isSystem = true;
2522 }
2524 Rooted<GlobalObject *> global(cx);
2525 {
2526 AutoCompartment ac(cx, compartment);
2527 global = GlobalObject::create(cx, Valueify(clasp));
2528 }
2530 if (!global)
2531 return nullptr;
2533 if (hookOption == JS::FireOnNewGlobalHook)
2534 JS_FireOnNewGlobalObject(cx, global);
2536 return global;
2537 }
2539 JS_PUBLIC_API(void)
2540 JS_GlobalObjectTraceHook(JSTracer *trc, JSObject *global)
2541 {
2542 JS_ASSERT(global->is<GlobalObject>());
2544 // Off thread parsing and compilation tasks create a dummy global which is then
2545 // merged back into the host compartment. Since it used to be a global, it will still
2546 // have this trace hook, but it does not have a meaning relative to its new compartment.
2547 // We can safely skip it.
2548 if (!global->isOwnGlobal())
2549 return;
2551 // Trace the compartment for any GC things that should only stick around if we know the
2552 // compartment is live.
2553 global->compartment()->trace(trc);
2555 JSTraceOp trace = global->compartment()->options().getTrace();
2556 if (trace)
2557 trace(trc, global);
2558 }
2560 JS_PUBLIC_API(void)
2561 JS_FireOnNewGlobalObject(JSContext *cx, JS::HandleObject global)
2562 {
2563 // This hook is infallible, because we don't really want arbitrary script
2564 // to be able to throw errors during delicate global creation routines.
2565 // This infallibility will eat OOM and slow script, but if that happens
2566 // we'll likely run up into them again soon in a fallible context.
2567 Rooted<js::GlobalObject*> globalObject(cx, &global->as<GlobalObject>());
2568 Debugger::onNewGlobalObject(cx, globalObject);
2569 }
2571 JS_PUBLIC_API(JSObject *)
2572 JS_NewObject(JSContext *cx, const JSClass *jsclasp, HandleObject proto, HandleObject parent)
2573 {
2574 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
2575 AssertHeapIsIdle(cx);
2576 CHECK_REQUEST(cx);
2577 assertSameCompartment(cx, proto, parent);
2579 const Class *clasp = Valueify(jsclasp);
2580 if (!clasp)
2581 clasp = &JSObject::class_; /* default class is Object */
2583 JS_ASSERT(clasp != &JSFunction::class_);
2584 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
2586 JSObject *obj = NewObjectWithClassProto(cx, clasp, proto, parent);
2587 JS_ASSERT_IF(obj, obj->getParent());
2588 return obj;
2589 }
2591 JS_PUBLIC_API(JSObject *)
2592 JS_NewObjectWithGivenProto(JSContext *cx, const JSClass *jsclasp, HandleObject proto, HandleObject parent)
2593 {
2594 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
2595 AssertHeapIsIdle(cx);
2596 CHECK_REQUEST(cx);
2597 assertSameCompartment(cx, proto, parent);
2599 const Class *clasp = Valueify(jsclasp);
2600 if (!clasp)
2601 clasp = &JSObject::class_; /* default class is Object */
2603 JS_ASSERT(clasp != &JSFunction::class_);
2604 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
2606 JSObject *obj = NewObjectWithGivenProto(cx, clasp, proto, parent);
2607 if (obj)
2608 MarkTypeObjectUnknownProperties(cx, obj->type());
2609 return obj;
2610 }
2612 JS_PUBLIC_API(JSObject *)
2613 JS_NewObjectForConstructor(JSContext *cx, const JSClass *clasp, const CallArgs& args)
2614 {
2615 AssertHeapIsIdle(cx);
2616 CHECK_REQUEST(cx);
2618 Value callee = args.calleev();
2619 assertSameCompartment(cx, callee);
2620 RootedObject obj(cx, &callee.toObject());
2621 return CreateThis(cx, Valueify(clasp), obj);
2622 }
2624 JS_PUBLIC_API(bool)
2625 JS_IsExtensible(JSContext *cx, HandleObject obj, bool *extensible)
2626 {
2627 return JSObject::isExtensible(cx, obj, extensible);
2628 }
2630 JS_PUBLIC_API(bool)
2631 JS_IsNative(JSObject *obj)
2632 {
2633 return obj->isNative();
2634 }
2636 JS_PUBLIC_API(JSRuntime *)
2637 JS_GetObjectRuntime(JSObject *obj)
2638 {
2639 return obj->compartment()->runtimeFromMainThread();
2640 }
2642 JS_PUBLIC_API(bool)
2643 JS_FreezeObject(JSContext *cx, HandleObject obj)
2644 {
2645 AssertHeapIsIdle(cx);
2646 CHECK_REQUEST(cx);
2647 assertSameCompartment(cx, obj);
2648 return JSObject::freeze(cx, obj);
2649 }
2651 JS_PUBLIC_API(bool)
2652 JS_DeepFreezeObject(JSContext *cx, HandleObject obj)
2653 {
2654 AssertHeapIsIdle(cx);
2655 CHECK_REQUEST(cx);
2656 assertSameCompartment(cx, obj);
2658 /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */
2659 bool extensible;
2660 if (!JSObject::isExtensible(cx, obj, &extensible))
2661 return false;
2662 if (!extensible)
2663 return true;
2665 if (!JSObject::freeze(cx, obj))
2666 return false;
2668 /* Walk slots in obj and if any value is a non-null object, seal it. */
2669 for (uint32_t i = 0, n = obj->slotSpan(); i < n; ++i) {
2670 const Value &v = obj->getSlot(i);
2671 if (v.isPrimitive())
2672 continue;
2673 RootedObject obj(cx, &v.toObject());
2674 if (!JS_DeepFreezeObject(cx, obj))
2675 return false;
2676 }
2678 return true;
2679 }
2681 static bool
2682 LookupPropertyById(JSContext *cx, HandleObject obj, HandleId id,
2683 MutableHandleObject objp, MutableHandleShape propp)
2684 {
2685 AssertHeapIsIdle(cx);
2686 CHECK_REQUEST(cx);
2687 assertSameCompartment(cx, obj, id);
2689 return JSObject::lookupGeneric(cx, obj, id, objp, propp);
2690 }
2692 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
2694 static bool
2695 LookupResult(JSContext *cx, HandleObject obj, HandleObject obj2, HandleId id,
2696 HandleShape shape, MutableHandleValue vp)
2697 {
2698 if (!shape) {
2699 /* XXX bad API: no way to tell "not defined" from "void value" */
2700 vp.setUndefined();
2701 return true;
2702 }
2704 if (!obj2->isNative()) {
2705 if (obj2->is<ProxyObject>()) {
2706 Rooted<PropertyDescriptor> desc(cx);
2707 if (!Proxy::getPropertyDescriptor(cx, obj2, id, &desc))
2708 return false;
2709 if (!desc.isShared()) {
2710 vp.set(desc.value());
2711 return true;
2712 }
2713 }
2714 } else if (IsImplicitDenseOrTypedArrayElement(shape)) {
2715 vp.set(obj2->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
2716 return true;
2717 } else {
2718 /* Peek at the native property's slot value, without doing a Get. */
2719 if (shape->hasSlot()) {
2720 vp.set(obj2->nativeGetSlot(shape->slot()));
2721 return true;
2722 }
2723 }
2725 /* XXX bad API: no way to return "defined but value unknown" */
2726 vp.setBoolean(true);
2727 return true;
2728 }
2730 JS_PUBLIC_API(bool)
2731 JS_LookupPropertyById(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
2732 {
2733 RootedObject obj2(cx);
2734 RootedShape prop(cx);
2736 return LookupPropertyById(cx, obj, id, &obj2, &prop) &&
2737 LookupResult(cx, obj, obj2, id, prop, vp);
2738 }
2740 JS_PUBLIC_API(bool)
2741 JS_LookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp)
2742 {
2743 CHECK_REQUEST(cx);
2744 RootedId id(cx);
2745 if (!IndexToId(cx, index, &id))
2746 return false;
2747 return JS_LookupPropertyById(cx, obj, id, vp);
2748 }
2750 JS_PUBLIC_API(bool)
2751 JS_LookupProperty(JSContext *cx, HandleObject objArg, const char *name, MutableHandleValue vp)
2752 {
2753 RootedObject obj(cx, objArg);
2754 JSAtom *atom = Atomize(cx, name, strlen(name));
2755 if (!atom)
2756 return false;
2758 RootedId id(cx, AtomToId(atom));
2759 return JS_LookupPropertyById(cx, obj, id, vp);
2760 }
2762 JS_PUBLIC_API(bool)
2763 JS_LookupUCProperty(JSContext *cx, HandleObject objArg, const jschar *name, size_t namelen,
2764 MutableHandleValue vp)
2765 {
2766 RootedObject obj(cx, objArg);
2767 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
2768 if (!atom)
2769 return false;
2771 RootedId id(cx, AtomToId(atom));
2772 return JS_LookupPropertyById(cx, obj, id, vp);
2773 }
2775 JS_PUBLIC_API(bool)
2776 JS_HasPropertyById(JSContext *cx, HandleObject obj, HandleId id, bool *foundp)
2777 {
2778 RootedObject obj2(cx);
2779 RootedShape prop(cx);
2780 bool ok = LookupPropertyById(cx, obj, id, &obj2, &prop);
2781 *foundp = (prop != nullptr);
2782 return ok;
2783 }
2785 JS_PUBLIC_API(bool)
2786 JS_HasElement(JSContext *cx, HandleObject obj, uint32_t index, bool *foundp)
2787 {
2788 AssertHeapIsIdle(cx);
2789 CHECK_REQUEST(cx);
2790 RootedId id(cx);
2791 if (!IndexToId(cx, index, &id))
2792 return false;
2793 return JS_HasPropertyById(cx, obj, id, foundp);
2794 }
2796 JS_PUBLIC_API(bool)
2797 JS_HasProperty(JSContext *cx, HandleObject obj, const char *name, bool *foundp)
2798 {
2799 JSAtom *atom = Atomize(cx, name, strlen(name));
2800 if (!atom)
2801 return false;
2802 RootedId id(cx, AtomToId(atom));
2803 return JS_HasPropertyById(cx, obj, id, foundp);
2804 }
2806 JS_PUBLIC_API(bool)
2807 JS_HasUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, bool *foundp)
2808 {
2809 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
2810 if (!atom)
2811 return false;
2812 RootedId id(cx, AtomToId(atom));
2813 return JS_HasPropertyById(cx, obj, id, foundp);
2814 }
2816 JS_PUBLIC_API(bool)
2817 JS_AlreadyHasOwnPropertyById(JSContext *cx, HandleObject obj, HandleId id, bool *foundp)
2818 {
2819 AssertHeapIsIdle(cx);
2820 CHECK_REQUEST(cx);
2821 assertSameCompartment(cx, obj, id);
2823 if (!obj->isNative()) {
2824 RootedObject obj2(cx);
2825 RootedShape prop(cx);
2827 if (!LookupPropertyById(cx, obj, id, &obj2, &prop))
2828 return false;
2829 *foundp = (obj == obj2);
2830 return true;
2831 }
2833 // Check for an existing native property on the objct. Be careful not to
2834 // call any lookup or resolve hooks.
2836 if (JSID_IS_INT(id)) {
2837 uint32_t index = JSID_TO_INT(id);
2839 if (obj->containsDenseElement(index)) {
2840 *foundp = true;
2841 return true;
2842 }
2844 if (obj->is<TypedArrayObject>() && index < obj->as<TypedArrayObject>().length()) {
2845 *foundp = true;
2846 return true;
2847 }
2848 }
2850 *foundp = obj->nativeContains(cx, id);
2851 return true;
2852 }
2854 JS_PUBLIC_API(bool)
2855 JS_AlreadyHasOwnElement(JSContext *cx, HandleObject obj, uint32_t index, bool *foundp)
2856 {
2857 AssertHeapIsIdle(cx);
2858 CHECK_REQUEST(cx);
2859 RootedId id(cx);
2860 if (!IndexToId(cx, index, &id))
2861 return false;
2862 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
2863 }
2865 JS_PUBLIC_API(bool)
2866 JS_AlreadyHasOwnProperty(JSContext *cx, HandleObject obj, const char *name, bool *foundp)
2867 {
2868 JSAtom *atom = Atomize(cx, name, strlen(name));
2869 if (!atom)
2870 return false;
2871 RootedId id(cx, AtomToId(atom));
2872 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
2873 }
2875 JS_PUBLIC_API(bool)
2876 JS_AlreadyHasOwnUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
2877 bool *foundp)
2878 {
2879 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
2880 if (!atom)
2881 return false;
2882 RootedId id(cx, AtomToId(atom));
2883 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
2884 }
2886 /* Wrapper functions to create wrappers with no corresponding JSJitInfo from API
2887 * function arguments.
2888 */
2889 static JSPropertyOpWrapper
2890 GetterWrapper(JSPropertyOp getter)
2891 {
2892 JSPropertyOpWrapper ret;
2893 ret.op = getter;
2894 ret.info = nullptr;
2895 return ret;
2896 }
2898 static JSStrictPropertyOpWrapper
2899 SetterWrapper(JSStrictPropertyOp setter)
2900 {
2901 JSStrictPropertyOpWrapper ret;
2902 ret.op = setter;
2903 ret.info = nullptr;
2904 return ret;
2905 }
2907 static bool
2908 DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
2909 const JSPropertyOpWrapper &get, const JSStrictPropertyOpWrapper &set,
2910 unsigned attrs, unsigned flags)
2911 {
2912 PropertyOp getter = get.op;
2913 StrictPropertyOp setter = set.op;
2914 /*
2915 * JSPROP_READONLY has no meaning when accessors are involved. Ideally we'd
2916 * throw if this happens, but we've accepted it for long enough that it's
2917 * not worth trying to make callers change their ways. Just flip it off on
2918 * its way through the API layer so that we can enforce this internally.
2919 */
2920 if (attrs & (JSPROP_GETTER | JSPROP_SETTER))
2921 attrs &= ~JSPROP_READONLY;
2923 /*
2924 * When we use DefineProperty, we need full scriptable Function objects rather
2925 * than JSNatives. However, we might be pulling this property descriptor off
2926 * of something with JSNative property descriptors. If we are, wrap them in
2927 * JS Function objects.
2928 */
2929 if (attrs & JSPROP_NATIVE_ACCESSORS) {
2930 JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
2931 JSFunction::Flags zeroFlags = JSAPIToJSFunctionFlags(0);
2932 // We can't just use JS_NewFunctionById here because it
2933 // assumes a string id.
2934 RootedAtom atom(cx, JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : nullptr);
2935 attrs &= ~JSPROP_NATIVE_ACCESSORS;
2936 if (getter) {
2937 RootedObject global(cx, (JSObject*) &obj->global());
2938 JSFunction *getobj = NewFunction(cx, NullPtr(), (Native) getter, 0,
2939 zeroFlags, global, atom);
2940 if (!getobj)
2941 return false;
2943 if (get.info)
2944 getobj->setJitInfo(get.info);
2946 getter = JS_DATA_TO_FUNC_PTR(PropertyOp, getobj);
2947 attrs |= JSPROP_GETTER;
2948 }
2949 if (setter) {
2950 // Root just the getter, since the setter is not yet a JSObject.
2951 AutoRooterGetterSetter getRoot(cx, JSPROP_GETTER, &getter, nullptr);
2952 RootedObject global(cx, (JSObject*) &obj->global());
2953 JSFunction *setobj = NewFunction(cx, NullPtr(), (Native) setter, 1,
2954 zeroFlags, global, atom);
2955 if (!setobj)
2956 return false;
2958 if (set.info)
2959 setobj->setJitInfo(set.info);
2961 setter = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setobj);
2962 attrs |= JSPROP_SETTER;
2963 }
2964 }
2967 AssertHeapIsIdle(cx);
2968 CHECK_REQUEST(cx);
2969 assertSameCompartment(cx, obj, id, value,
2970 (attrs & JSPROP_GETTER)
2971 ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
2972 : nullptr,
2973 (attrs & JSPROP_SETTER)
2974 ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
2975 : nullptr);
2977 return JSObject::defineGeneric(cx, obj, id, value, getter, setter, attrs);
2978 }
2980 JS_PUBLIC_API(bool)
2981 JS_DefinePropertyById(JSContext *cx, JSObject *objArg, jsid idArg, jsval valueArg,
2982 JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
2983 {
2984 RootedObject obj(cx, objArg);
2985 RootedId id(cx, idArg);
2986 RootedValue value(cx, valueArg);
2987 return DefinePropertyById(cx, obj, id, value, GetterWrapper(getter), SetterWrapper(setter),
2988 attrs, 0);
2989 }
2991 JS_PUBLIC_API(bool)
2992 JS_DefineElement(JSContext *cx, JSObject *objArg, uint32_t index, jsval valueArg,
2993 JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
2994 {
2995 RootedObject obj(cx, objArg);
2996 RootedValue value(cx, valueArg);
2997 AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
2998 AssertHeapIsIdle(cx);
2999 CHECK_REQUEST(cx);
3000 RootedId id(cx);
3001 if (!IndexToId(cx, index, &id))
3002 return false;
3003 return DefinePropertyById(cx, obj, id, value, GetterWrapper(getter), SetterWrapper(setter),
3004 attrs, 0);
3005 }
3007 static bool
3008 DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue value,
3009 const JSPropertyOpWrapper &getter, const JSStrictPropertyOpWrapper &setter,
3010 unsigned attrs, unsigned flags)
3011 {
3012 AutoRooterGetterSetter gsRoot(cx, attrs, const_cast<JSPropertyOp *>(&getter.op),
3013 const_cast<JSStrictPropertyOp *>(&setter.op));
3015 RootedId id(cx);
3016 if (attrs & JSPROP_INDEX) {
3017 id.set(INT_TO_JSID(intptr_t(name)));
3018 attrs &= ~JSPROP_INDEX;
3019 } else {
3020 JSAtom *atom = Atomize(cx, name, strlen(name));
3021 if (!atom)
3022 return false;
3023 id = AtomToId(atom);
3024 }
3026 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags);
3027 }
3030 static bool
3031 DefineSelfHostedProperty(JSContext *cx,
3032 HandleObject obj,
3033 const char *name,
3034 const char *getterName,
3035 const char *setterName,
3036 unsigned attrs,
3037 unsigned flags)
3038 {
3039 RootedAtom nameAtom(cx, Atomize(cx, name, strlen(name)));
3040 if (!nameAtom)
3041 return false;
3043 RootedAtom getterNameAtom(cx, Atomize(cx, getterName, strlen(getterName)));
3044 if (!getterNameAtom)
3045 return false;
3047 RootedValue getterValue(cx);
3048 if (!cx->global()->getSelfHostedFunction(cx, getterNameAtom, nameAtom,
3049 0, &getterValue))
3050 {
3051 return false;
3052 }
3053 JS_ASSERT(getterValue.isObject() && getterValue.toObject().is<JSFunction>());
3054 RootedFunction getterFunc(cx, &getterValue.toObject().as<JSFunction>());
3055 JSPropertyOp getterOp = JS_DATA_TO_FUNC_PTR(PropertyOp, getterFunc.get());
3057 RootedFunction setterFunc(cx);
3058 if (setterName) {
3059 RootedAtom setterNameAtom(cx, Atomize(cx, setterName, strlen(setterName)));
3060 if (!setterNameAtom)
3061 return false;
3063 RootedValue setterValue(cx);
3064 if (!cx->global()->getSelfHostedFunction(cx, setterNameAtom, nameAtom,
3065 0, &setterValue))
3066 {
3067 return false;
3068 }
3069 JS_ASSERT(setterValue.isObject() && setterValue.toObject().is<JSFunction>());
3070 setterFunc = &getterValue.toObject().as<JSFunction>();
3071 }
3072 JSStrictPropertyOp setterOp = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setterFunc.get());
3074 return DefineProperty(cx, obj, name, JS::UndefinedHandleValue,
3075 GetterWrapper(getterOp), SetterWrapper(setterOp),
3076 attrs, flags);
3077 }
3079 JS_PUBLIC_API(bool)
3080 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue value,
3081 unsigned attrs,
3082 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
3083 {
3084 return DefineProperty(cx, obj, name, value, GetterWrapper(getter), SetterWrapper(setter),
3085 attrs, 0);
3086 }
3088 JS_PUBLIC_API(bool)
3089 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleObject valueArg,
3090 unsigned attrs,
3091 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
3092 {
3093 RootedValue value(cx, ObjectValue(*valueArg));
3094 return DefineProperty(cx, obj, name, value, GetterWrapper(getter), SetterWrapper(setter),
3095 attrs, 0);
3096 }
3098 JS_PUBLIC_API(bool)
3099 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleString valueArg,
3100 unsigned attrs,
3101 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
3102 {
3103 RootedValue value(cx, StringValue(valueArg));
3104 return DefineProperty(cx, obj, name, value, GetterWrapper(getter), SetterWrapper(setter),
3105 attrs, 0);
3106 }
3108 JS_PUBLIC_API(bool)
3109 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, int32_t valueArg,
3110 unsigned attrs,
3111 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
3112 {
3113 Value value = Int32Value(valueArg);
3114 return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value),
3115 GetterWrapper(getter), SetterWrapper(setter), attrs, 0);
3116 }
3118 JS_PUBLIC_API(bool)
3119 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, uint32_t valueArg,
3120 unsigned attrs,
3121 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
3122 {
3123 Value value = UINT_TO_JSVAL(valueArg);
3124 return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value),
3125 GetterWrapper(getter), SetterWrapper(setter), attrs, 0);
3126 }
3128 JS_PUBLIC_API(bool)
3129 JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, double valueArg,
3130 unsigned attrs,
3131 PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
3132 {
3133 Value value = NumberValue(valueArg);
3134 return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value),
3135 GetterWrapper(getter), SetterWrapper(setter), attrs, 0);
3136 }
3138 static bool
3139 DefineUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
3140 const Value &value_, PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
3141 unsigned flags)
3142 {
3143 RootedValue value(cx, value_);
3144 AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
3145 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
3146 if (!atom)
3147 return false;
3148 RootedId id(cx, AtomToId(atom));
3149 return DefinePropertyById(cx, obj, id, value, GetterWrapper(getter), SetterWrapper(setter),
3150 attrs, flags);
3151 }
3153 JS_PUBLIC_API(bool)
3154 JS_DefineUCProperty(JSContext *cx, JSObject *objArg, const jschar *name, size_t namelen,
3155 jsval valueArg, JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
3156 {
3157 RootedObject obj(cx, objArg);
3158 RootedValue value(cx, valueArg);
3159 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0);
3160 }
3162 JS_PUBLIC_API(bool)
3163 JS_DefineOwnProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue descriptor, bool *bp)
3164 {
3165 AssertHeapIsIdle(cx);
3166 CHECK_REQUEST(cx);
3167 assertSameCompartment(cx, obj, id, descriptor);
3169 return DefineOwnProperty(cx, obj, id, descriptor, bp);
3170 }
3172 JS_PUBLIC_API(JSObject *)
3173 JS_DefineObject(JSContext *cx, JSObject *objArg, const char *name, const JSClass *jsclasp,
3174 JSObject *protoArg, unsigned attrs)
3175 {
3176 RootedObject obj(cx, objArg);
3177 RootedObject proto(cx, protoArg);
3178 AssertHeapIsIdle(cx);
3179 CHECK_REQUEST(cx);
3180 assertSameCompartment(cx, obj, proto);
3182 const Class *clasp = Valueify(jsclasp);
3183 if (!clasp)
3184 clasp = &JSObject::class_; /* default class is Object */
3186 RootedObject nobj(cx, NewObjectWithClassProto(cx, clasp, proto, obj));
3187 if (!nobj)
3188 return nullptr;
3190 RootedValue nobjValue(cx, ObjectValue(*nobj));
3191 if (!DefineProperty(cx, obj, name, nobjValue, GetterWrapper(nullptr), SetterWrapper(nullptr),
3192 attrs, 0)) {
3193 return nullptr;
3194 }
3196 return nobj;
3197 }
3199 JS_PUBLIC_API(bool)
3200 JS_DefineConstDoubles(JSContext *cx, HandleObject obj, const JSConstDoubleSpec *cds)
3201 {
3202 bool ok;
3203 unsigned attrs;
3205 AssertHeapIsIdle(cx);
3206 CHECK_REQUEST(cx);
3207 JSPropertyOpWrapper noget = GetterWrapper(nullptr);
3208 JSStrictPropertyOpWrapper noset = SetterWrapper(nullptr);
3209 for (ok = true; cds->name; cds++) {
3210 RootedValue value(cx, DoubleValue(cds->dval));
3211 attrs = cds->flags;
3212 if (!attrs)
3213 attrs = JSPROP_READONLY | JSPROP_PERMANENT;
3214 ok = DefineProperty(cx, obj, cds->name, value, noget, noset, attrs, 0);
3215 if (!ok)
3216 break;
3217 }
3218 return ok;
3219 }
3221 JS_PUBLIC_API(bool)
3222 JS_DefineProperties(JSContext *cx, HandleObject obj, const JSPropertySpec *ps)
3223 {
3224 bool ok;
3225 for (ok = true; ps->name; ps++) {
3226 if (ps->flags & JSPROP_NATIVE_ACCESSORS) {
3227 // If you declare native accessors, then you should have a native
3228 // getter.
3229 JS_ASSERT(ps->getter.propertyOp.op);
3230 // If you do not have a self-hosted getter, you should not have a
3231 // self-hosted setter. This is the closest approximation to that
3232 // assertion we can have with our setup.
3233 JS_ASSERT_IF(ps->setter.propertyOp.info, ps->setter.propertyOp.op);
3235 ok = DefineProperty(cx, obj, ps->name, JS::UndefinedHandleValue,
3236 ps->getter.propertyOp, ps->setter.propertyOp, ps->flags, 0);
3237 } else {
3238 // If you have self-hosted getter/setter, you can't have a
3239 // native one.
3240 JS_ASSERT(!ps->getter.propertyOp.op && !ps->setter.propertyOp.op);
3241 JS_ASSERT(ps->flags & JSPROP_GETTER);
3242 /*
3243 * During creation of the self-hosting global, we ignore all
3244 * self-hosted properties, as that means we're currently setting up
3245 * the global object that the self-hosted code is then compiled
3246 * in. That means that Self-hosted properties can't be used in the
3247 * self-hosting global itself, right now.
3248 */
3249 if (cx->runtime()->isSelfHostingGlobal(cx->global()))
3250 continue;
3252 ok = DefineSelfHostedProperty(cx, obj, ps->name,
3253 ps->getter.selfHosted.funname,
3254 ps->setter.selfHosted.funname,
3255 ps->flags, 0);
3256 }
3257 if (!ok)
3258 break;
3259 }
3260 return ok;
3261 }
3263 static bool
3264 GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id,
3265 MutableHandle<PropertyDescriptor> desc)
3266 {
3267 RootedObject obj2(cx);
3268 RootedShape shape(cx);
3270 if (!LookupPropertyById(cx, obj, id, &obj2, &shape))
3271 return false;
3273 desc.clear();
3274 if (!shape)
3275 return true;
3277 desc.object().set(obj2);
3278 if (obj2->isNative()) {
3279 if (IsImplicitDenseOrTypedArrayElement(shape)) {
3280 desc.setEnumerable();
3281 desc.value().set(obj2->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
3282 } else {
3283 desc.setAttributes(shape->attributes());
3284 desc.setGetter(shape->getter());
3285 desc.setSetter(shape->setter());
3286 JS_ASSERT(desc.value().isUndefined());
3287 if (shape->hasSlot())
3288 desc.value().set(obj2->nativeGetSlot(shape->slot()));
3289 }
3290 } else {
3291 if (obj2->is<ProxyObject>())
3292 return Proxy::getPropertyDescriptor(cx, obj2, id, desc);
3293 if (!JSObject::getGenericAttributes(cx, obj2, id, &desc.attributesRef()))
3294 return false;
3295 JS_ASSERT(desc.getter() == nullptr);
3296 JS_ASSERT(desc.setter() == nullptr);
3297 JS_ASSERT(desc.value().isUndefined());
3298 }
3299 return true;
3300 }
3302 JS_PUBLIC_API(bool)
3303 JS_GetOwnPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id,
3304 MutableHandle<JSPropertyDescriptor> desc)
3305 {
3306 AssertHeapIsIdle(cx);
3307 CHECK_REQUEST(cx);
3309 return GetOwnPropertyDescriptor(cx, obj, id, desc);
3310 }
3312 JS_PUBLIC_API(bool)
3313 JS_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, const char *name,
3314 MutableHandle<JSPropertyDescriptor> desc)
3315 {
3316 JSAtom *atom = Atomize(cx, name, strlen(name));
3317 if (!atom)
3318 return false;
3319 RootedId id(cx, AtomToId(atom));
3320 return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc);
3321 }
3323 JS_PUBLIC_API(bool)
3324 JS_GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id,
3325 MutableHandle<JSPropertyDescriptor> desc)
3326 {
3327 return GetPropertyDescriptorById(cx, obj, id, desc);
3328 }
3330 JS_PUBLIC_API(bool)
3331 JS_GetPropertyDescriptor(JSContext *cx, HandleObject obj, const char *name,
3332 MutableHandle<JSPropertyDescriptor> desc)
3333 {
3334 JSAtom *atom = Atomize(cx, name, strlen(name));
3335 if (!atom)
3336 return false;
3337 RootedId id(cx, AtomToId(atom));
3338 return atom && JS_GetPropertyDescriptorById(cx, obj, id, desc);
3339 }
3341 JS_PUBLIC_API(bool)
3342 JS_GetPropertyById(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
3343 {
3344 return JS_ForwardGetPropertyTo(cx, obj, id, obj, vp);
3345 }
3347 JS_PUBLIC_API(bool)
3348 JS_ForwardGetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject onBehalfOf,
3349 JS::MutableHandleValue vp)
3350 {
3351 AssertHeapIsIdle(cx);
3352 CHECK_REQUEST(cx);
3353 assertSameCompartment(cx, obj, id);
3354 assertSameCompartment(cx, onBehalfOf);
3356 return JSObject::getGeneric(cx, obj, onBehalfOf, id, vp);
3357 }
3359 JS_PUBLIC_API(bool)
3360 JS_GetElement(JSContext *cx, HandleObject objArg, uint32_t index, MutableHandleValue vp)
3361 {
3362 return JS_ForwardGetElementTo(cx, objArg, index, objArg, vp);
3363 }
3365 JS_PUBLIC_API(bool)
3366 JS_ForwardGetElementTo(JSContext *cx, HandleObject obj, uint32_t index, HandleObject onBehalfOf,
3367 MutableHandleValue vp)
3368 {
3369 AssertHeapIsIdle(cx);
3370 CHECK_REQUEST(cx);
3371 assertSameCompartment(cx, obj);
3373 return JSObject::getElement(cx, obj, onBehalfOf, index, vp);
3374 }
3376 JS_PUBLIC_API(bool)
3377 JS_GetProperty(JSContext *cx, HandleObject obj, const char *name, MutableHandleValue vp)
3378 {
3379 JSAtom *atom = Atomize(cx, name, strlen(name));
3380 if (!atom)
3381 return false;
3382 RootedId id(cx, AtomToId(atom));
3383 return JS_GetPropertyById(cx, obj, id, vp);
3384 }
3386 JS_PUBLIC_API(bool)
3387 JS_GetUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
3388 MutableHandleValue vp)
3389 {
3390 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
3391 if (!atom)
3392 return false;
3393 RootedId id(cx, AtomToId(atom));
3394 return JS_GetPropertyById(cx, obj, id, vp);
3395 }
3397 JS_PUBLIC_API(bool)
3398 JS_SetPropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue v)
3399 {
3400 RootedValue value(cx, v);
3401 AssertHeapIsIdle(cx);
3402 CHECK_REQUEST(cx);
3403 assertSameCompartment(cx, obj, id);
3405 return JSObject::setGeneric(cx, obj, obj, id, &value, false);
3406 }
3408 static bool
3409 SetElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp)
3410 {
3411 AssertHeapIsIdle(cx);
3412 CHECK_REQUEST(cx);
3413 assertSameCompartment(cx, obj, vp);
3415 return JSObject::setElement(cx, obj, obj, index, vp, false);
3416 }
3418 JS_PUBLIC_API(bool)
3419 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v)
3420 {
3421 RootedValue value(cx, v);
3422 return SetElement(cx, obj, index, &value);
3423 }
3425 JS_PUBLIC_API(bool)
3426 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleObject v)
3427 {
3428 RootedValue value(cx, ObjectOrNullValue(v));
3429 return SetElement(cx, obj, index, &value);
3430 }
3432 JS_PUBLIC_API(bool)
3433 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, HandleString v)
3434 {
3435 RootedValue value(cx, StringValue(v));
3436 return SetElement(cx, obj, index, &value);
3437 }
3439 JS_PUBLIC_API(bool)
3440 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, int32_t v)
3441 {
3442 RootedValue value(cx, NumberValue(v));
3443 return SetElement(cx, obj, index, &value);
3444 }
3446 JS_PUBLIC_API(bool)
3447 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, uint32_t v)
3448 {
3449 RootedValue value(cx, NumberValue(v));
3450 return SetElement(cx, obj, index, &value);
3451 }
3453 JS_PUBLIC_API(bool)
3454 JS_SetElement(JSContext *cx, HandleObject obj, uint32_t index, double v)
3455 {
3456 RootedValue value(cx, NumberValue(v));
3457 return SetElement(cx, obj, index, &value);
3458 }
3460 JS_PUBLIC_API(bool)
3461 JS_SetProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue v)
3462 {
3463 JSAtom *atom = Atomize(cx, name, strlen(name));
3464 if (!atom)
3465 return false;
3466 RootedId id(cx, AtomToId(atom));
3467 return JS_SetPropertyById(cx, obj, id, v);
3468 }
3470 JS_PUBLIC_API(bool)
3471 JS_SetUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
3472 HandleValue v)
3473 {
3474 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
3475 if (!atom)
3476 return false;
3477 RootedId id(cx, AtomToId(atom));
3478 return JS_SetPropertyById(cx, obj, id, v);
3479 }
3481 JS_PUBLIC_API(bool)
3482 JS_DeletePropertyById2(JSContext *cx, HandleObject obj, HandleId id, bool *result)
3483 {
3484 AssertHeapIsIdle(cx);
3485 CHECK_REQUEST(cx);
3486 assertSameCompartment(cx, obj, id);
3488 return JSObject::deleteByValue(cx, obj, IdToValue(id), result);
3489 }
3491 JS_PUBLIC_API(bool)
3492 JS_DeleteElement2(JSContext *cx, HandleObject obj, uint32_t index, bool *result)
3493 {
3494 AssertHeapIsIdle(cx);
3495 CHECK_REQUEST(cx);
3496 assertSameCompartment(cx, obj);
3498 return JSObject::deleteElement(cx, obj, index, result);
3499 }
3501 JS_PUBLIC_API(bool)
3502 JS_DeleteProperty2(JSContext *cx, HandleObject obj, const char *name, bool *result)
3503 {
3504 CHECK_REQUEST(cx);
3505 assertSameCompartment(cx, obj);
3507 JSAtom *atom = Atomize(cx, name, strlen(name));
3508 if (!atom)
3509 return false;
3510 return JSObject::deleteByValue(cx, obj, StringValue(atom), result);
3511 }
3513 JS_PUBLIC_API(bool)
3514 JS_DeleteUCProperty2(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
3515 bool *result)
3516 {
3517 CHECK_REQUEST(cx);
3518 assertSameCompartment(cx, obj);
3520 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
3521 if (!atom)
3522 return false;
3523 return JSObject::deleteByValue(cx, obj, StringValue(atom), result);
3524 }
3526 JS_PUBLIC_API(bool)
3527 JS_DeletePropertyById(JSContext *cx, HandleObject obj, HandleId id)
3528 {
3529 bool junk;
3530 return JS_DeletePropertyById2(cx, obj, id, &junk);
3531 }
3533 JS_PUBLIC_API(bool)
3534 JS_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index)
3535 {
3536 bool junk;
3537 return JS_DeleteElement2(cx, obj, index, &junk);
3538 }
3540 JS_PUBLIC_API(bool)
3541 JS_DeleteProperty(JSContext *cx, HandleObject obj, const char *name)
3542 {
3543 bool junk;
3544 return JS_DeleteProperty2(cx, obj, name, &junk);
3545 }
3547 static Shape *
3548 LastConfigurableShape(JSObject *obj)
3549 {
3550 for (Shape::Range<NoGC> r(obj->lastProperty()); !r.empty(); r.popFront()) {
3551 Shape *shape = &r.front();
3552 if (shape->configurable())
3553 return shape;
3554 }
3555 return nullptr;
3556 }
3558 JS_PUBLIC_API(void)
3559 JS_ClearNonGlobalObject(JSContext *cx, HandleObject obj)
3560 {
3561 AssertHeapIsIdle(cx);
3562 CHECK_REQUEST(cx);
3563 assertSameCompartment(cx, obj);
3565 JS_ASSERT(!obj->is<GlobalObject>());
3567 if (!obj->isNative())
3568 return;
3570 /* Remove all configurable properties from obj. */
3571 RootedShape shape(cx);
3572 while ((shape = LastConfigurableShape(obj))) {
3573 if (!obj->removeProperty(cx, shape->propid()))
3574 return;
3575 }
3577 /* Set all remaining writable plain data properties to undefined. */
3578 for (Shape::Range<NoGC> r(obj->lastProperty()); !r.empty(); r.popFront()) {
3579 Shape *shape = &r.front();
3580 if (shape->isDataDescriptor() &&
3581 shape->writable() &&
3582 shape->hasDefaultSetter() &&
3583 shape->hasSlot())
3584 {
3585 obj->nativeSetSlot(shape->slot(), UndefinedValue());
3586 }
3587 }
3588 }
3590 JS_PUBLIC_API(void)
3591 JS_SetAllNonReservedSlotsToUndefined(JSContext *cx, JSObject *objArg)
3592 {
3593 RootedObject obj(cx, objArg);
3594 AssertHeapIsIdle(cx);
3595 CHECK_REQUEST(cx);
3596 assertSameCompartment(cx, obj);
3598 if (!obj->isNative())
3599 return;
3601 const Class *clasp = obj->getClass();
3602 unsigned numReserved = JSCLASS_RESERVED_SLOTS(clasp);
3603 unsigned numSlots = obj->slotSpan();
3604 for (unsigned i = numReserved; i < numSlots; i++)
3605 obj->setSlot(i, UndefinedValue());
3606 }
3608 JS_PUBLIC_API(JSIdArray *)
3609 JS_Enumerate(JSContext *cx, HandleObject obj)
3610 {
3611 AssertHeapIsIdle(cx);
3612 CHECK_REQUEST(cx);
3613 assertSameCompartment(cx, obj);
3615 AutoIdVector props(cx);
3616 JSIdArray *ida;
3617 if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida))
3618 return nullptr;
3619 return ida;
3620 }
3622 /*
3623 * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
3624 * prop_iterator_class somehow...
3625 * + preserve the obj->enumerate API while optimizing the native object case
3626 * + native case here uses a JSShape *, but that iterates in reverse!
3627 * + so we make non-native match, by reverse-iterating after JS_Enumerating
3628 */
3629 static const uint32_t JSSLOT_ITER_INDEX = 0;
3631 static void
3632 prop_iter_finalize(FreeOp *fop, JSObject *obj)
3633 {
3634 void *pdata = obj->getPrivate();
3635 if (!pdata)
3636 return;
3638 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) {
3639 /* Non-native case: destroy the ida enumerated when obj was created. */
3640 JSIdArray *ida = (JSIdArray *) pdata;
3641 fop->free_(ida);
3642 }
3643 }
3645 static void
3646 prop_iter_trace(JSTracer *trc, JSObject *obj)
3647 {
3648 void *pdata = obj->getPrivate();
3649 if (!pdata)
3650 return;
3652 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
3653 /*
3654 * Native case: just mark the next property to visit. We don't need a
3655 * barrier here because the pointer is updated via setPrivate, which
3656 * always takes a barrier.
3657 */
3658 Shape *tmp = static_cast<Shape *>(pdata);
3659 MarkShapeUnbarriered(trc, &tmp, "prop iter shape");
3660 obj->setPrivateUnbarriered(tmp);
3661 } else {
3662 /* Non-native case: mark each id in the JSIdArray private. */
3663 JSIdArray *ida = (JSIdArray *) pdata;
3664 MarkIdRange(trc, ida->length, ida->vector, "prop iter");
3665 }
3666 }
3668 static const Class prop_iter_class = {
3669 "PropertyIterator",
3670 JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(1),
3671 JS_PropertyStub, /* addProperty */
3672 JS_DeletePropertyStub, /* delProperty */
3673 JS_PropertyStub, /* getProperty */
3674 JS_StrictPropertyStub, /* setProperty */
3675 JS_EnumerateStub,
3676 JS_ResolveStub,
3677 JS_ConvertStub,
3678 prop_iter_finalize,
3679 nullptr, /* call */
3680 nullptr, /* hasInstance */
3681 nullptr, /* construct */
3682 prop_iter_trace
3683 };
3685 JS_PUBLIC_API(JSObject *)
3686 JS_NewPropertyIterator(JSContext *cx, HandleObject obj)
3687 {
3688 AssertHeapIsIdle(cx);
3689 CHECK_REQUEST(cx);
3690 assertSameCompartment(cx, obj);
3692 RootedObject iterobj(cx, NewObjectWithClassProto(cx, &prop_iter_class, nullptr, obj));
3693 if (!iterobj)
3694 return nullptr;
3696 int index;
3697 if (obj->isNative()) {
3698 /* Native case: start with the last property in obj. */
3699 iterobj->setPrivateGCThing(obj->lastProperty());
3700 index = -1;
3701 } else {
3702 /* Non-native case: enumerate a JSIdArray and keep it via private. */
3703 JSIdArray *ida = JS_Enumerate(cx, obj);
3704 if (!ida)
3705 return nullptr;
3706 iterobj->setPrivate((void *)ida);
3707 index = ida->length;
3708 }
3710 /* iterobj cannot escape to other threads here. */
3711 iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(index));
3712 return iterobj;
3713 }
3715 JS_PUBLIC_API(bool)
3716 JS_NextProperty(JSContext *cx, HandleObject iterobj, jsid *idp)
3717 {
3718 AssertHeapIsIdle(cx);
3719 CHECK_REQUEST(cx);
3720 assertSameCompartment(cx, iterobj);
3721 int32_t i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
3722 if (i < 0) {
3723 /* Native case: private data is a property tree node pointer. */
3724 JS_ASSERT(iterobj->getParent()->isNative());
3725 Shape *shape = static_cast<Shape *>(iterobj->getPrivate());
3727 while (shape->previous() && !shape->enumerable())
3728 shape = shape->previous();
3730 if (!shape->previous()) {
3731 JS_ASSERT(shape->isEmptyShape());
3732 *idp = JSID_VOID;
3733 } else {
3734 iterobj->setPrivateGCThing(const_cast<Shape *>(shape->previous().get()));
3735 *idp = shape->propid();
3736 }
3737 } else {
3738 /* Non-native case: use the ida enumerated when iterobj was created. */
3739 JSIdArray *ida = (JSIdArray *) iterobj->getPrivate();
3740 JS_ASSERT(i <= ida->length);
3741 STATIC_ASSUME(i <= ida->length);
3742 if (i == 0) {
3743 *idp = JSID_VOID;
3744 } else {
3745 *idp = ida->vector[--i];
3746 iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i));
3747 }
3748 }
3749 return true;
3750 }
3752 JS_PUBLIC_API(jsval)
3753 JS_GetReservedSlot(JSObject *obj, uint32_t index)
3754 {
3755 return obj->getReservedSlot(index);
3756 }
3758 JS_PUBLIC_API(void)
3759 JS_SetReservedSlot(JSObject *obj, uint32_t index, Value value)
3760 {
3761 obj->setReservedSlot(index, value);
3762 }
3764 JS_PUBLIC_API(JSObject *)
3765 JS_NewArrayObject(JSContext *cx, const JS::HandleValueArray& contents)
3766 {
3767 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
3768 AssertHeapIsIdle(cx);
3769 CHECK_REQUEST(cx);
3771 assertSameCompartment(cx, contents);
3772 return NewDenseCopiedArray(cx, contents.length(), contents.begin());
3773 }
3775 JS_PUBLIC_API(JSObject *)
3776 JS_NewArrayObject(JSContext *cx, size_t length)
3777 {
3778 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
3779 AssertHeapIsIdle(cx);
3780 CHECK_REQUEST(cx);
3782 return NewDenseAllocatedArray(cx, length);
3783 }
3785 JS_PUBLIC_API(bool)
3786 JS_IsArrayObject(JSContext *cx, JS::HandleObject obj)
3787 {
3788 assertSameCompartment(cx, obj);
3789 return ObjectClassIs(obj, ESClass_Array, cx);
3790 }
3792 JS_PUBLIC_API(bool)
3793 JS_IsArrayObject(JSContext *cx, JS::HandleValue value)
3794 {
3795 if (!value.isObject())
3796 return false;
3797 RootedObject obj(cx, &value.toObject());
3798 return JS_IsArrayObject(cx, obj);
3799 }
3801 JS_PUBLIC_API(bool)
3802 JS_GetArrayLength(JSContext *cx, HandleObject obj, uint32_t *lengthp)
3803 {
3804 AssertHeapIsIdle(cx);
3805 CHECK_REQUEST(cx);
3806 assertSameCompartment(cx, obj);
3807 return GetLengthProperty(cx, obj, lengthp);
3808 }
3810 JS_PUBLIC_API(bool)
3811 JS_SetArrayLength(JSContext *cx, HandleObject obj, uint32_t length)
3812 {
3813 AssertHeapIsIdle(cx);
3814 CHECK_REQUEST(cx);
3815 assertSameCompartment(cx, obj);
3816 return SetLengthProperty(cx, obj, length);
3817 }
3819 JS_PUBLIC_API(void)
3820 JS_HoldPrincipals(JSPrincipals *principals)
3821 {
3822 ++principals->refcount;
3823 }
3825 JS_PUBLIC_API(void)
3826 JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals)
3827 {
3828 int rc = --principals->refcount;
3829 if (rc == 0)
3830 rt->destroyPrincipals(principals);
3831 }
3833 JS_PUBLIC_API(void)
3834 JS_SetSecurityCallbacks(JSRuntime *rt, const JSSecurityCallbacks *scb)
3835 {
3836 JS_ASSERT(scb != &NullSecurityCallbacks);
3837 rt->securityCallbacks = scb ? scb : &NullSecurityCallbacks;
3838 }
3840 JS_PUBLIC_API(const JSSecurityCallbacks *)
3841 JS_GetSecurityCallbacks(JSRuntime *rt)
3842 {
3843 return (rt->securityCallbacks != &NullSecurityCallbacks) ? rt->securityCallbacks : nullptr;
3844 }
3846 JS_PUBLIC_API(void)
3847 JS_SetTrustedPrincipals(JSRuntime *rt, const JSPrincipals *prin)
3848 {
3849 rt->setTrustedPrincipals(prin);
3850 }
3852 extern JS_PUBLIC_API(void)
3853 JS_InitDestroyPrincipalsCallback(JSRuntime *rt, JSDestroyPrincipalsOp destroyPrincipals)
3854 {
3855 JS_ASSERT(destroyPrincipals);
3856 JS_ASSERT(!rt->destroyPrincipals);
3857 rt->destroyPrincipals = destroyPrincipals;
3858 }
3860 JS_PUBLIC_API(JSFunction *)
3861 JS_NewFunction(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
3862 HandleObject parent, const char *name)
3863 {
3864 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
3866 AssertHeapIsIdle(cx);
3867 CHECK_REQUEST(cx);
3868 assertSameCompartment(cx, parent);
3870 RootedAtom atom(cx);
3871 if (name) {
3872 atom = Atomize(cx, name, strlen(name));
3873 if (!atom)
3874 return nullptr;
3875 }
3877 JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags);
3878 return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, atom);
3879 }
3881 JS_PUBLIC_API(JSFunction *)
3882 JS_NewFunctionById(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
3883 HandleObject parent, HandleId id)
3884 {
3885 JS_ASSERT(JSID_IS_STRING(id));
3886 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
3887 JS_ASSERT(native);
3888 AssertHeapIsIdle(cx);
3889 CHECK_REQUEST(cx);
3890 assertSameCompartment(cx, parent);
3892 RootedAtom name(cx, JSID_TO_ATOM(id));
3893 JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags);
3894 return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, name);
3895 }
3897 JS_PUBLIC_API(JSFunction *)
3898 JS::GetSelfHostedFunction(JSContext *cx, const char *selfHostedName, HandleId id, unsigned nargs)
3899 {
3900 JS_ASSERT(JSID_IS_STRING(id));
3901 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
3902 AssertHeapIsIdle(cx);
3903 CHECK_REQUEST(cx);
3905 RootedAtom name(cx, JSID_TO_ATOM(id));
3906 RootedAtom shName(cx, Atomize(cx, selfHostedName, strlen(selfHostedName)));
3907 if (!shName)
3908 return nullptr;
3909 RootedValue funVal(cx);
3910 if (!cx->global()->getSelfHostedFunction(cx, shName, name, nargs, &funVal))
3911 return nullptr;
3912 return &funVal.toObject().as<JSFunction>();
3913 }
3915 JS_PUBLIC_API(JSObject *)
3916 JS_CloneFunctionObject(JSContext *cx, HandleObject funobj, HandleObject parentArg)
3917 {
3918 RootedObject parent(cx, parentArg);
3920 AssertHeapIsIdle(cx);
3921 CHECK_REQUEST(cx);
3922 assertSameCompartment(cx, parent);
3923 // Note that funobj can be in a different compartment.
3925 if (!parent)
3926 parent = cx->global();
3928 if (!funobj->is<JSFunction>()) {
3929 AutoCompartment ac(cx, funobj);
3930 RootedValue v(cx, ObjectValue(*funobj));
3931 ReportIsNotFunction(cx, v);
3932 return nullptr;
3933 }
3935 RootedFunction fun(cx, &funobj->as<JSFunction>());
3936 if (fun->isInterpretedLazy()) {
3937 AutoCompartment ac(cx, funobj);
3938 if (!fun->getOrCreateScript(cx))
3939 return nullptr;
3940 }
3941 /*
3942 * If a function was compiled to be lexically nested inside some other
3943 * script, we cannot clone it without breaking the compiler's assumptions.
3944 */
3945 if (fun->isInterpreted() && (fun->nonLazyScript()->enclosingStaticScope() ||
3946 (fun->nonLazyScript()->compileAndGo() && !parent->is<GlobalObject>())))
3947 {
3948 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
3949 return nullptr;
3950 }
3952 if (fun->isBoundFunction()) {
3953 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT);
3954 return nullptr;
3955 }
3957 if (fun->isNative() && IsAsmJSModuleNative(fun->native())) {
3958 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT);
3959 return nullptr;
3960 }
3962 return CloneFunctionObject(cx, fun, parent, fun->getAllocKind());
3963 }
3965 JS_PUBLIC_API(JSObject *)
3966 JS_GetFunctionObject(JSFunction *fun)
3967 {
3968 return fun;
3969 }
3971 JS_PUBLIC_API(JSString *)
3972 JS_GetFunctionId(JSFunction *fun)
3973 {
3974 return fun->atom();
3975 }
3977 JS_PUBLIC_API(JSString *)
3978 JS_GetFunctionDisplayId(JSFunction *fun)
3979 {
3980 return fun->displayAtom();
3981 }
3983 JS_PUBLIC_API(uint16_t)
3984 JS_GetFunctionArity(JSFunction *fun)
3985 {
3986 return fun->nargs();
3987 }
3989 JS_PUBLIC_API(bool)
3990 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
3991 {
3992 return obj->is<JSFunction>();
3993 }
3995 JS_PUBLIC_API(bool)
3996 JS_ObjectIsCallable(JSContext *cx, JSObject *obj)
3997 {
3998 return obj->isCallable();
3999 }
4001 JS_PUBLIC_API(bool)
4002 JS_IsNativeFunction(JSObject *funobj, JSNative call)
4003 {
4004 if (!funobj->is<JSFunction>())
4005 return false;
4006 JSFunction *fun = &funobj->as<JSFunction>();
4007 return fun->isNative() && fun->native() == call;
4008 }
4010 extern JS_PUBLIC_API(bool)
4011 JS_IsConstructor(JSFunction *fun)
4012 {
4013 return fun->isNativeConstructor() || fun->isInterpretedConstructor();
4014 }
4016 JS_PUBLIC_API(JSObject*)
4017 JS_BindCallable(JSContext *cx, HandleObject target, HandleObject newThis)
4018 {
4019 RootedValue thisArg(cx, ObjectValue(*newThis));
4020 return js_fun_bind(cx, target, thisArg, nullptr, 0);
4021 }
4023 static bool
4024 js_generic_native_method_dispatcher(JSContext *cx, unsigned argc, Value *vp)
4025 {
4026 CallArgs args = CallArgsFromVp(argc, vp);
4028 const JSFunctionSpec *fs = (JSFunctionSpec *)
4029 args.callee().as<JSFunction>().getExtendedSlot(0).toPrivate();
4030 JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
4032 if (argc < 1) {
4033 js_ReportMissingArg(cx, args.calleev(), 0);
4034 return false;
4035 }
4037 /*
4038 * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
4039 * which is almost always the class constructor object, e.g. Array. Then
4040 * call the corresponding prototype native method with our first argument
4041 * passed as |this|.
4042 */
4043 memmove(vp + 1, vp + 2, argc * sizeof(jsval));
4045 /* Clear the last parameter in case too few arguments were passed. */
4046 vp[2 + --argc].setUndefined();
4048 return fs->call.op(cx, argc, vp);
4049 }
4051 JS_PUBLIC_API(bool)
4052 JS_DefineFunctions(JSContext *cx, HandleObject obj, const JSFunctionSpec *fs)
4053 {
4054 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4055 AssertHeapIsIdle(cx);
4056 CHECK_REQUEST(cx);
4057 assertSameCompartment(cx, obj);
4059 RootedObject ctor(cx);
4061 for (; fs->name; fs++) {
4062 RootedAtom atom(cx);
4063 // If the name starts with "@@", it must be a well-known symbol.
4064 if (fs->name[0] != '@' || fs->name[1] != '@')
4065 atom = Atomize(cx, fs->name, strlen(fs->name));
4066 else if (strcmp(fs->name, "@@iterator") == 0)
4067 // FIXME: This atom should be a symbol: bug 918828.
4068 atom = cx->names().std_iterator;
4069 else
4070 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_SYMBOL, fs->name);
4071 if (!atom)
4072 return false;
4074 Rooted<jsid> id(cx, AtomToId(atom));
4076 /*
4077 * Define a generic arity N+1 static method for the arity N prototype
4078 * method if flags contains JSFUN_GENERIC_NATIVE.
4079 */
4080 unsigned flags = fs->flags;
4081 if (flags & JSFUN_GENERIC_NATIVE) {
4082 if (!ctor) {
4083 ctor = JS_GetConstructor(cx, obj);
4084 if (!ctor)
4085 return false;
4086 }
4088 flags &= ~JSFUN_GENERIC_NATIVE;
4089 JSFunction *fun = DefineFunction(cx, ctor, id,
4090 js_generic_native_method_dispatcher,
4091 fs->nargs + 1, flags,
4092 JSFunction::ExtendedFinalizeKind);
4093 if (!fun)
4094 return false;
4096 /*
4097 * As jsapi.h notes, fs must point to storage that lives as long
4098 * as fun->object lives.
4099 */
4100 fun->setExtendedSlot(0, PrivateValue(const_cast<JSFunctionSpec*>(fs)));
4101 }
4103 /*
4104 * Delay cloning self-hosted functions until they are called. This is
4105 * achieved by passing DefineFunction a nullptr JSNative which
4106 * produces an interpreted JSFunction where !hasScript. Interpreted
4107 * call paths then call InitializeLazyFunctionScript if !hasScript.
4108 */
4109 if (fs->selfHostedName) {
4110 JS_ASSERT(!fs->call.op);
4111 JS_ASSERT(!fs->call.info);
4112 /*
4113 * During creation of the self-hosting global, we ignore all
4114 * self-hosted functions, as that means we're currently setting up
4115 * the global object that the self-hosted code is then compiled
4116 * in. Self-hosted functions can access each other via their names,
4117 * but not via the builtin classes they get installed into.
4118 */
4119 if (cx->runtime()->isSelfHostingGlobal(cx->global()))
4120 continue;
4122 RootedAtom shName(cx, Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName)));
4123 if (!shName)
4124 return false;
4125 RootedValue funVal(cx);
4126 if (!cx->global()->getSelfHostedFunction(cx, shName, atom, fs->nargs, &funVal))
4127 return false;
4128 if (!JSObject::defineGeneric(cx, obj, id, funVal, nullptr, nullptr, flags))
4129 return false;
4130 } else {
4131 JSFunction *fun = DefineFunction(cx, obj, id, fs->call.op, fs->nargs, flags);
4132 if (!fun)
4133 return false;
4134 if (fs->call.info)
4135 fun->setJitInfo(fs->call.info);
4136 }
4137 }
4138 return true;
4139 }
4141 JS_PUBLIC_API(JSFunction *)
4142 JS_DefineFunction(JSContext *cx, HandleObject obj, const char *name, JSNative call,
4143 unsigned nargs, unsigned attrs)
4144 {
4145 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4146 AssertHeapIsIdle(cx);
4147 CHECK_REQUEST(cx);
4148 assertSameCompartment(cx, obj);
4149 JSAtom *atom = Atomize(cx, name, strlen(name));
4150 if (!atom)
4151 return nullptr;
4152 Rooted<jsid> id(cx, AtomToId(atom));
4153 return DefineFunction(cx, obj, id, call, nargs, attrs);
4154 }
4156 JS_PUBLIC_API(JSFunction *)
4157 JS_DefineUCFunction(JSContext *cx, HandleObject obj,
4158 const jschar *name, size_t namelen, JSNative call,
4159 unsigned nargs, unsigned attrs)
4160 {
4161 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4162 AssertHeapIsIdle(cx);
4163 CHECK_REQUEST(cx);
4164 assertSameCompartment(cx, obj);
4165 JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
4166 if (!atom)
4167 return nullptr;
4168 Rooted<jsid> id(cx, AtomToId(atom));
4169 return DefineFunction(cx, obj, id, call, nargs, attrs);
4170 }
4172 extern JS_PUBLIC_API(JSFunction *)
4173 JS_DefineFunctionById(JSContext *cx, HandleObject obj, HandleId id, JSNative call,
4174 unsigned nargs, unsigned attrs)
4175 {
4176 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4177 AssertHeapIsIdle(cx);
4178 CHECK_REQUEST(cx);
4179 assertSameCompartment(cx, obj);
4180 return DefineFunction(cx, obj, id, call, nargs, attrs);
4181 }
4183 struct AutoLastFrameCheck
4184 {
4185 AutoLastFrameCheck(JSContext *cx
4186 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
4187 : cx(cx)
4188 {
4189 JS_ASSERT(cx);
4190 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
4191 }
4193 ~AutoLastFrameCheck() {
4194 if (cx->isExceptionPending() &&
4195 !JS_IsRunning(cx) &&
4196 !cx->options().dontReportUncaught()) {
4197 js_ReportUncaughtException(cx);
4198 }
4199 }
4201 private:
4202 JSContext *cx;
4203 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
4204 };
4206 /* Use the fastest available getc. */
4207 #if defined(HAVE_GETC_UNLOCKED)
4208 # define fast_getc getc_unlocked
4209 #elif defined(HAVE__GETC_NOLOCK)
4210 # define fast_getc _getc_nolock
4211 #else
4212 # define fast_getc getc
4213 #endif
4215 typedef js::Vector<char, 8, TempAllocPolicy> FileContents;
4217 static bool
4218 ReadCompleteFile(JSContext *cx, FILE *fp, FileContents &buffer)
4219 {
4220 /* Get the complete length of the file, if possible. */
4221 struct stat st;
4222 int ok = fstat(fileno(fp), &st);
4223 if (ok != 0)
4224 return false;
4225 if (st.st_size > 0) {
4226 if (!buffer.reserve(st.st_size))
4227 return false;
4228 }
4230 // Read in the whole file. Note that we can't assume the data's length
4231 // is actually st.st_size, because 1) some files lie about their size
4232 // (/dev/zero and /dev/random), and 2) reading files in text mode on
4233 // Windows collapses "\r\n" pairs to single \n characters.
4234 for (;;) {
4235 int c = fast_getc(fp);
4236 if (c == EOF)
4237 break;
4238 if (!buffer.append(c))
4239 return false;
4240 }
4242 return true;
4243 }
4245 namespace {
4247 class AutoFile
4248 {
4249 FILE *fp_;
4250 public:
4251 AutoFile()
4252 : fp_(nullptr)
4253 {}
4254 ~AutoFile()
4255 {
4256 if (fp_ && fp_ != stdin)
4257 fclose(fp_);
4258 }
4259 FILE *fp() const { return fp_; }
4260 bool open(JSContext *cx, const char *filename);
4261 bool readAll(JSContext *cx, FileContents &buffer)
4262 {
4263 JS_ASSERT(fp_);
4264 return ReadCompleteFile(cx, fp_, buffer);
4265 }
4266 };
4268 } /* anonymous namespace */
4270 /*
4271 * Open a source file for reading. Supports "-" and nullptr to mean stdin. The
4272 * return value must be fclosed unless it is stdin.
4273 */
4274 bool
4275 AutoFile::open(JSContext *cx, const char *filename)
4276 {
4277 if (!filename || strcmp(filename, "-") == 0) {
4278 fp_ = stdin;
4279 } else {
4280 fp_ = fopen(filename, "r");
4281 if (!fp_) {
4282 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_OPEN,
4283 filename, "No such file or directory");
4284 return false;
4285 }
4286 }
4287 return true;
4288 }
4290 JSObject * const JS::ReadOnlyCompileOptions::nullObjectPtr = nullptr;
4292 void
4293 JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions &rhs)
4294 {
4295 version = rhs.version;
4296 versionSet = rhs.versionSet;
4297 utf8 = rhs.utf8;
4298 lineno = rhs.lineno;
4299 column = rhs.column;
4300 compileAndGo = rhs.compileAndGo;
4301 forEval = rhs.forEval;
4302 noScriptRval = rhs.noScriptRval;
4303 selfHostingMode = rhs.selfHostingMode;
4304 canLazilyParse = rhs.canLazilyParse;
4305 strictOption = rhs.strictOption;
4306 extraWarningsOption = rhs.extraWarningsOption;
4307 werrorOption = rhs.werrorOption;
4308 asmJSOption = rhs.asmJSOption;
4309 forceAsync = rhs.forceAsync;
4310 installedFile = rhs.installedFile;
4311 sourceIsLazy = rhs.sourceIsLazy;
4312 introductionType = rhs.introductionType;
4313 introductionLineno = rhs.introductionLineno;
4314 introductionOffset = rhs.introductionOffset;
4315 hasIntroductionInfo = rhs.hasIntroductionInfo;
4316 }
4318 JSPrincipals *
4319 JS::ReadOnlyCompileOptions::originPrincipals(ExclusiveContext *cx) const
4320 {
4321 return NormalizeOriginPrincipals(cx->compartment()->principals, originPrincipals_);
4322 }
4324 JS::OwningCompileOptions::OwningCompileOptions(JSContext *cx)
4325 : ReadOnlyCompileOptions(),
4326 runtime(GetRuntime(cx)),
4327 elementRoot(cx),
4328 elementAttributeNameRoot(cx),
4329 introductionScriptRoot(cx)
4330 {
4331 }
4333 JS::OwningCompileOptions::~OwningCompileOptions()
4334 {
4335 if (originPrincipals_)
4336 JS_DropPrincipals(runtime, originPrincipals_);
4338 // OwningCompileOptions always owns these, so these casts are okay.
4339 js_free(const_cast<char *>(filename_));
4340 js_free(const_cast<jschar *>(sourceMapURL_));
4341 js_free(const_cast<char *>(introducerFilename_));
4342 }
4344 bool
4345 JS::OwningCompileOptions::copy(JSContext *cx, const ReadOnlyCompileOptions &rhs)
4346 {
4347 copyPODOptions(rhs);
4349 setOriginPrincipals(rhs.originPrincipals(cx));
4350 setElement(rhs.element());
4351 setElementAttributeName(rhs.elementAttributeName());
4352 setIntroductionScript(rhs.introductionScript());
4354 return (setFileAndLine(cx, rhs.filename(), rhs.lineno) &&
4355 setSourceMapURL(cx, rhs.sourceMapURL()) &&
4356 setIntroducerFilename(cx, rhs.introducerFilename()));
4357 }
4359 bool
4360 JS::OwningCompileOptions::setFile(JSContext *cx, const char *f)
4361 {
4362 char *copy = nullptr;
4363 if (f) {
4364 copy = JS_strdup(cx, f);
4365 if (!copy)
4366 return false;
4367 }
4369 // OwningCompileOptions always owns filename_, so this cast is okay.
4370 js_free(const_cast<char *>(filename_));
4372 filename_ = copy;
4373 return true;
4374 }
4376 bool
4377 JS::OwningCompileOptions::setFileAndLine(JSContext *cx, const char *f, unsigned l)
4378 {
4379 if (!setFile(cx, f))
4380 return false;
4382 lineno = l;
4383 return true;
4384 }
4386 bool
4387 JS::OwningCompileOptions::setSourceMapURL(JSContext *cx, const jschar *s)
4388 {
4389 jschar *copy = nullptr;
4390 if (s) {
4391 copy = js_strdup(cx, s);
4392 if (!copy)
4393 return false;
4394 }
4396 // OwningCompileOptions always owns sourceMapURL_, so this cast is okay.
4397 js_free(const_cast<jschar *>(sourceMapURL_));
4399 sourceMapURL_ = copy;
4400 return true;
4401 }
4403 bool
4404 JS::OwningCompileOptions::setIntroducerFilename(JSContext *cx, const char *s)
4405 {
4406 char *copy = nullptr;
4407 if (s) {
4408 copy = JS_strdup(cx, s);
4409 if (!copy)
4410 return false;
4411 }
4413 // OwningCompileOptions always owns introducerFilename_, so this cast is okay.
4414 js_free(const_cast<char *>(introducerFilename_));
4416 introducerFilename_ = copy;
4417 return true;
4418 }
4420 bool
4421 JS::OwningCompileOptions::wrap(JSContext *cx, JSCompartment *compartment)
4422 {
4423 if (!compartment->wrap(cx, &elementRoot))
4424 return false;
4425 if (elementAttributeNameRoot) {
4426 if (!compartment->wrap(cx, elementAttributeNameRoot.address()))
4427 return false;
4428 }
4430 // There is no equivalent of cross-compartment wrappers for scripts. If
4431 // the introduction script would be in a different compartment from the
4432 // compiled code, we would be creating a cross-compartment script
4433 // reference, which would be bogus. In that case, just don't bother to
4434 // retain the introduction script.
4435 if (introductionScriptRoot) {
4436 if (introductionScriptRoot->compartment() != compartment)
4437 introductionScriptRoot = nullptr;
4438 }
4440 return true;
4441 }
4443 JS::CompileOptions::CompileOptions(JSContext *cx, JSVersion version)
4444 : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx),
4445 introductionScriptRoot(cx)
4446 {
4447 this->version = (version != JSVERSION_UNKNOWN) ? version : cx->findVersion();
4449 compileAndGo = false;
4450 noScriptRval = cx->options().noScriptRval();
4451 strictOption = cx->options().strictMode();
4452 extraWarningsOption = cx->options().extraWarnings();
4453 werrorOption = cx->options().werror();
4454 asmJSOption = cx->runtime()->options().asmJS();
4455 }
4457 bool
4458 JS::CompileOptions::wrap(JSContext *cx, JSCompartment *compartment)
4459 {
4460 if (!compartment->wrap(cx, &elementRoot))
4461 return false;
4462 if (elementAttributeNameRoot) {
4463 if (!compartment->wrap(cx, elementAttributeNameRoot.address()))
4464 return false;
4465 }
4467 // There is no equivalent of cross-compartment wrappers for scripts. If
4468 // the introduction script would be in a different compartment from the
4469 // compiled code, we would be creating a cross-compartment script
4470 // reference, which would be bogus. In that case, just don't bother to
4471 // retain the introduction script.
4472 if (introductionScriptRoot) {
4473 if (introductionScriptRoot->compartment() != compartment)
4474 introductionScriptRoot = nullptr;
4475 }
4477 return true;
4478 }
4480 bool
4481 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
4482 SourceBufferHolder &srcBuf, MutableHandleScript script)
4483 {
4484 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4485 AssertHeapIsIdle(cx);
4486 CHECK_REQUEST(cx);
4487 assertSameCompartment(cx, obj);
4488 AutoLastFrameCheck lfc(cx);
4490 script.set(frontend::CompileScript(cx, &cx->tempLifoAlloc(), obj, NullPtr(), options, srcBuf));
4491 return !!script;
4492 }
4494 JSScript *
4495 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
4496 const jschar *chars, size_t length)
4497 {
4498 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
4499 RootedScript script(cx);
4500 if (!Compile(cx, obj, options, srcBuf, &script))
4501 return nullptr;
4502 return script;
4503 }
4505 JSScript *
4506 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
4507 const char *bytes, size_t length)
4508 {
4509 jschar *chars;
4510 if (options.utf8)
4511 chars = UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get();
4512 else
4513 chars = InflateString(cx, bytes, &length);
4514 if (!chars)
4515 return nullptr;
4517 JSScript *script = Compile(cx, obj, options, chars, length);
4518 js_free(chars);
4519 return script;
4520 }
4522 JSScript *
4523 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options, FILE *fp)
4524 {
4525 FileContents buffer(cx);
4526 if (!ReadCompleteFile(cx, fp, buffer))
4527 return nullptr;
4529 JSScript *script = Compile(cx, obj, options, buffer.begin(), buffer.length());
4530 return script;
4531 }
4533 JSScript *
4534 JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg, const char *filename)
4535 {
4536 AutoFile file;
4537 if (!file.open(cx, filename))
4538 return nullptr;
4539 CompileOptions options(cx, optionsArg);
4540 options.setFileAndLine(filename, 1);
4541 return Compile(cx, obj, options, file.fp());
4542 }
4544 JS_PUBLIC_API(bool)
4545 JS::CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options, size_t length)
4546 {
4547 static const size_t TINY_LENGTH = 1000;
4548 static const size_t HUGE_LENGTH = 100 * 1000;
4550 // These are heuristics which the caller may choose to ignore (e.g., for
4551 // testing purposes).
4552 if (!options.forceAsync) {
4553 // Compiling off the main thread inolves creating a new Zone and other
4554 // significant overheads. Don't bother if the script is tiny.
4555 if (length < TINY_LENGTH)
4556 return false;
4558 #ifdef JS_THREADSAFE
4559 // If the parsing task would have to wait for GC to complete, it'll probably
4560 // be faster to just start it synchronously on the main thread unless the
4561 // script is huge.
4562 if (OffThreadParsingMustWaitForGC(cx->runtime()) && length < HUGE_LENGTH)
4563 return false;
4564 #endif // JS_THREADSAFE
4565 }
4567 return cx->runtime()->canUseParallelParsing();
4568 }
4570 JS_PUBLIC_API(bool)
4571 JS::CompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options,
4572 const jschar *chars, size_t length,
4573 OffThreadCompileCallback callback, void *callbackData)
4574 {
4575 JS_ASSERT(CanCompileOffThread(cx, options, length));
4576 return StartOffThreadParseScript(cx, options, chars, length, callback, callbackData);
4577 }
4579 JS_PUBLIC_API(JSScript *)
4580 JS::FinishOffThreadScript(JSContext *maybecx, JSRuntime *rt, void *token)
4581 {
4582 #ifdef JS_THREADSAFE
4583 JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
4585 if (maybecx) {
4586 RootedScript script(maybecx);
4587 {
4588 AutoLastFrameCheck lfc(maybecx);
4589 script = WorkerThreadState().finishParseTask(maybecx, rt, token);
4590 }
4591 return script;
4592 } else {
4593 return WorkerThreadState().finishParseTask(maybecx, rt, token);
4594 }
4595 #else
4596 MOZ_ASSUME_UNREACHABLE("Off thread compilation is not available.");
4597 #endif
4598 }
4600 JS_PUBLIC_API(JSScript *)
4601 JS_CompileScript(JSContext *cx, JS::HandleObject obj, const char *ascii,
4602 size_t length, const JS::CompileOptions &options)
4603 {
4604 return Compile(cx, obj, options, ascii, length);
4605 }
4607 JS_PUBLIC_API(JSScript *)
4608 JS_CompileUCScript(JSContext *cx, JS::HandleObject obj, const jschar *chars,
4609 size_t length, const JS::CompileOptions &options)
4610 {
4611 return Compile(cx, obj, options, chars, length);
4612 }
4614 JS_PUBLIC_API(bool)
4615 JS_BufferIsCompilableUnit(JSContext *cx, HandleObject obj, const char *utf8, size_t length)
4616 {
4617 AssertHeapIsIdle(cx);
4618 CHECK_REQUEST(cx);
4619 assertSameCompartment(cx, obj);
4621 cx->clearPendingException();
4623 jschar *chars = JS::UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(utf8, length), &length).get();
4624 if (!chars)
4625 return true;
4627 // Return true on any out-of-memory error or non-EOF-related syntax error, so our
4628 // caller doesn't try to collect more buffered source.
4629 bool result = true;
4631 CompileOptions options(cx);
4632 options.setCompileAndGo(false);
4633 Parser<frontend::FullParseHandler> parser(cx, &cx->tempLifoAlloc(),
4634 options, chars, length,
4635 /* foldConstants = */ true, nullptr, nullptr);
4636 JSErrorReporter older = JS_SetErrorReporter(cx, nullptr);
4637 if (!parser.parse(obj)) {
4638 // We ran into an error. If it was because we ran out of source, we
4639 // return false so our caller knows to try to collect more buffered
4640 // source.
4641 if (parser.isUnexpectedEOF())
4642 result = false;
4644 cx->clearPendingException();
4645 }
4646 JS_SetErrorReporter(cx, older);
4648 js_free(chars);
4649 return result;
4650 }
4652 JS_PUBLIC_API(JSObject *)
4653 JS_GetGlobalFromScript(JSScript *script)
4654 {
4655 JS_ASSERT(!script->isCachedEval());
4656 return &script->global();
4657 }
4659 JS_PUBLIC_API(bool)
4660 JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
4661 const char *name, unsigned nargs, const char *const *argnames,
4662 SourceBufferHolder &srcBuf, MutableHandleFunction fun)
4663 {
4664 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4665 AssertHeapIsIdle(cx);
4666 CHECK_REQUEST(cx);
4667 assertSameCompartment(cx, obj);
4668 RootedAtom funAtom(cx);
4669 AutoLastFrameCheck lfc(cx);
4671 if (name) {
4672 funAtom = Atomize(cx, name, strlen(name));
4673 if (!funAtom)
4674 return false;
4675 }
4677 AutoNameVector formals(cx);
4678 for (unsigned i = 0; i < nargs; i++) {
4679 RootedAtom argAtom(cx, Atomize(cx, argnames[i], strlen(argnames[i])));
4680 if (!argAtom || !formals.append(argAtom->asPropertyName()))
4681 return false;
4682 }
4684 fun.set(NewFunction(cx, NullPtr(), nullptr, 0, JSFunction::INTERPRETED, obj,
4685 funAtom, JSFunction::FinalizeKind, TenuredObject));
4686 if (!fun)
4687 return false;
4689 if (!frontend::CompileFunctionBody(cx, fun, options, formals, srcBuf))
4690 return false;
4692 if (obj && funAtom && options.defineOnScope) {
4693 Rooted<jsid> id(cx, AtomToId(funAtom));
4694 RootedValue value(cx, ObjectValue(*fun));
4695 if (!JSObject::defineGeneric(cx, obj, id, value, nullptr, nullptr, JSPROP_ENUMERATE))
4696 return false;
4697 }
4699 return true;
4700 }
4702 JS_PUBLIC_API(JSFunction *)
4703 JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
4704 const char *name, unsigned nargs, const char *const *argnames,
4705 const jschar *chars, size_t length)
4706 {
4707 RootedFunction fun(cx);
4708 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
4709 if (!JS::CompileFunction(cx, obj, options, name, nargs, argnames, srcBuf, &fun))
4710 return nullptr;
4711 return fun;
4712 }
4714 JS_PUBLIC_API(JSFunction *)
4715 JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
4716 const char *name, unsigned nargs, const char *const *argnames,
4717 const char *bytes, size_t length)
4718 {
4719 jschar *chars;
4720 if (options.utf8)
4721 chars = UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(bytes, length), &length).get();
4722 else
4723 chars = InflateString(cx, bytes, &length);
4724 if (!chars)
4725 return nullptr;
4727 JSFunction *fun = CompileFunction(cx, obj, options, name, nargs, argnames, chars, length);
4728 js_free(chars);
4729 return fun;
4730 }
4732 JS_PUBLIC_API(JSFunction *)
4733 JS_CompileUCFunction(JSContext *cx, JS::HandleObject obj, const char *name,
4734 unsigned nargs, const char *const *argnames,
4735 const jschar *chars, size_t length,
4736 const CompileOptions &options)
4737 {
4738 return CompileFunction(cx, obj, options, name, nargs, argnames, chars, length);
4739 }
4741 JS_PUBLIC_API(JSFunction *)
4742 JS_CompileFunction(JSContext *cx, JS::HandleObject obj, const char *name,
4743 unsigned nargs, const char *const *argnames,
4744 const char *ascii, size_t length,
4745 const JS::CompileOptions &options)
4746 {
4747 return CompileFunction(cx, obj, options, name, nargs, argnames, ascii, length);
4748 }
4750 JS_PUBLIC_API(JSString *)
4751 JS_DecompileScript(JSContext *cx, HandleScript script, const char *name, unsigned indent)
4752 {
4753 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4755 AssertHeapIsIdle(cx);
4756 CHECK_REQUEST(cx);
4757 script->ensureNonLazyCanonicalFunction(cx);
4758 RootedFunction fun(cx, script->functionNonDelazifying());
4759 if (fun)
4760 return JS_DecompileFunction(cx, fun, indent);
4761 bool haveSource = script->scriptSource()->hasSourceData();
4762 if (!haveSource && !JSScript::loadSource(cx, script->scriptSource(), &haveSource))
4763 return nullptr;
4764 return haveSource ? script->sourceData(cx) : js_NewStringCopyZ<CanGC>(cx, "[no source]");
4765 }
4767 JS_PUBLIC_API(JSString *)
4768 JS_DecompileFunction(JSContext *cx, HandleFunction fun, unsigned indent)
4769 {
4770 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4771 AssertHeapIsIdle(cx);
4772 CHECK_REQUEST(cx);
4773 assertSameCompartment(cx, fun);
4774 return FunctionToString(cx, fun, false, !(indent & JS_DONT_PRETTY_PRINT));
4775 }
4777 JS_PUBLIC_API(JSString *)
4778 JS_DecompileFunctionBody(JSContext *cx, HandleFunction fun, unsigned indent)
4779 {
4780 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4781 AssertHeapIsIdle(cx);
4782 CHECK_REQUEST(cx);
4783 assertSameCompartment(cx, fun);
4784 return FunctionToString(cx, fun, true, !(indent & JS_DONT_PRETTY_PRINT));
4785 }
4787 MOZ_NEVER_INLINE static bool
4788 ExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg, jsval *rval)
4789 {
4790 RootedScript script(cx, scriptArg);
4792 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4793 AssertHeapIsIdle(cx);
4794 CHECK_REQUEST(cx);
4795 assertSameCompartment(cx, obj, scriptArg);
4796 AutoLastFrameCheck lfc(cx);
4797 return Execute(cx, script, *obj, rval);
4798 }
4800 MOZ_NEVER_INLINE JS_PUBLIC_API(bool)
4801 JS_ExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg, MutableHandleValue rval)
4802 {
4803 return ExecuteScript(cx, obj, scriptArg, rval.address());
4804 }
4806 MOZ_NEVER_INLINE JS_PUBLIC_API(bool)
4807 JS_ExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg)
4808 {
4809 return ExecuteScript(cx, obj, scriptArg, nullptr);
4810 }
4812 JS_PUBLIC_API(bool)
4813 JS::CloneAndExecuteScript(JSContext *cx, HandleObject obj, HandleScript scriptArg)
4814 {
4815 CHECK_REQUEST(cx);
4816 assertSameCompartment(cx, obj);
4817 RootedScript script(cx, scriptArg);
4818 if (script->compartment() != cx->compartment()) {
4819 script = CloneScript(cx, NullPtr(), NullPtr(), script);
4820 if (!script)
4821 return false;
4822 }
4823 return ExecuteScript(cx, obj, script, nullptr);
4824 }
4826 JS_PUBLIC_API(bool)
4827 JS_ExecuteScriptVersion(JSContext *cx, HandleObject obj, HandleScript script,
4828 MutableHandleValue rval, JSVersion version)
4829 {
4830 return ExecuteScript(cx, obj, script, rval.address());
4831 }
4833 JS_PUBLIC_API(bool)
4834 JS_ExecuteScriptVersion(JSContext *cx, HandleObject obj, HandleScript script, JSVersion version)
4835 {
4836 return ExecuteScript(cx, obj, script, nullptr);
4837 }
4839 static const unsigned LARGE_SCRIPT_LENGTH = 500*1024;
4841 static bool
4842 Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
4843 SourceBufferHolder &srcBuf, JS::Value *rval)
4844 {
4845 CompileOptions options(cx, optionsArg);
4846 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
4847 AssertHeapIsIdle(cx);
4848 CHECK_REQUEST(cx);
4849 assertSameCompartment(cx, obj);
4851 AutoLastFrameCheck lfc(cx);
4853 options.setCompileAndGo(obj->is<GlobalObject>());
4854 options.setNoScriptRval(!rval);
4855 SourceCompressionTask sct(cx);
4856 RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(),
4857 obj, NullPtr(), options,
4858 srcBuf, nullptr, 0, &sct));
4859 if (!script)
4860 return false;
4862 JS_ASSERT(script->getVersion() == options.version);
4864 bool result = Execute(cx, script, *obj, rval);
4865 if (!sct.complete())
4866 result = false;
4868 // After evaluation, the compiled script will not be run again.
4869 // script->ensureRanAnalysis allocated 1 analyze::Bytecode for every opcode
4870 // which for large scripts means significant memory. Perform a GC eagerly
4871 // to clear out this analysis data before anything happens to inhibit the
4872 // flushing of this memory (such as setting requestAnimationFrame).
4873 if (script->length() > LARGE_SCRIPT_LENGTH) {
4874 script = nullptr;
4875 PrepareZoneForGC(cx->zone());
4876 GC(cx->runtime(), GC_NORMAL, JS::gcreason::FINISH_LARGE_EVALUTE);
4877 }
4879 return result;
4880 }
4882 static bool
4883 Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
4884 const jschar *chars, size_t length, JS::Value *rval)
4885 {
4886 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
4887 return ::Evaluate(cx, obj, optionsArg, srcBuf, rval);
4888 }
4890 static bool
4891 Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
4892 const char *bytes, size_t length, JS::Value *rval)
4893 {
4894 jschar *chars;
4895 if (options.utf8)
4896 chars = UTF8CharsToNewTwoByteCharsZ(cx, JS::UTF8Chars(bytes, length), &length).get();
4897 else
4898 chars = InflateString(cx, bytes, &length);
4899 if (!chars)
4900 return false;
4902 SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::GiveOwnership);
4903 bool ok = ::Evaluate(cx, obj, options, srcBuf, rval);
4904 return ok;
4905 }
4907 static bool
4908 Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
4909 const char *filename, JS::Value *rval)
4910 {
4911 FileContents buffer(cx);
4912 {
4913 AutoFile file;
4914 if (!file.open(cx, filename) || !file.readAll(cx, buffer))
4915 return false;
4916 }
4918 CompileOptions options(cx, optionsArg);
4919 options.setFileAndLine(filename, 1);
4920 return Evaluate(cx, obj, options, buffer.begin(), buffer.length(), rval);
4921 }
4923 extern JS_PUBLIC_API(bool)
4924 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
4925 SourceBufferHolder &srcBuf, MutableHandleValue rval)
4926 {
4927 return ::Evaluate(cx, obj, optionsArg, srcBuf, rval.address());
4928 }
4930 extern JS_PUBLIC_API(bool)
4931 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
4932 const jschar *chars, size_t length, MutableHandleValue rval)
4933 {
4934 return ::Evaluate(cx, obj, optionsArg, chars, length, rval.address());
4935 }
4937 extern JS_PUBLIC_API(bool)
4938 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
4939 const char *bytes, size_t length, MutableHandleValue rval)
4940 {
4941 return ::Evaluate(cx, obj, options, bytes, length, rval.address());
4942 }
4944 extern JS_PUBLIC_API(bool)
4945 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
4946 const char *filename, MutableHandleValue rval)
4947 {
4948 return ::Evaluate(cx, obj, optionsArg, filename, rval.address());
4949 }
4951 extern JS_PUBLIC_API(bool)
4952 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
4953 SourceBufferHolder &srcBuf)
4954 {
4955 return ::Evaluate(cx, obj, optionsArg, srcBuf, nullptr);
4956 }
4958 extern JS_PUBLIC_API(bool)
4959 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
4960 const jschar *chars, size_t length)
4961 {
4962 return ::Evaluate(cx, obj, optionsArg, chars, length, nullptr);
4963 }
4965 extern JS_PUBLIC_API(bool)
4966 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
4967 const char *bytes, size_t length)
4968 {
4969 return ::Evaluate(cx, obj, options, bytes, length, nullptr);
4970 }
4972 extern JS_PUBLIC_API(bool)
4973 JS::Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
4974 const char *filename)
4975 {
4976 return ::Evaluate(cx, obj, optionsArg, filename, nullptr);
4977 }
4979 JS_PUBLIC_API(bool)
4980 JS_EvaluateUCScript(JSContext *cx, HandleObject obj, const jschar *chars, unsigned length,
4981 const char *filename, unsigned lineno, MutableHandleValue rval)
4982 {
4983 CompileOptions options(cx);
4984 options.setFileAndLine(filename, lineno);
4986 return ::Evaluate(cx, obj, options, chars, length, rval.address());
4987 }
4989 JS_PUBLIC_API(bool)
4990 JS_EvaluateUCScript(JSContext *cx, HandleObject obj, SourceBufferHolder &srcBuf,
4991 const char *filename, unsigned lineno, MutableHandleValue rval)
4992 {
4993 CompileOptions options(cx);
4994 options.setFileAndLine(filename, lineno);
4996 return ::Evaluate(cx, obj, options, srcBuf, rval.address());
4997 }
4999 JS_PUBLIC_API(bool)
5000 JS_EvaluateScript(JSContext *cx, HandleObject obj, const char *bytes, unsigned nbytes,
5001 const char *filename, unsigned lineno, MutableHandleValue rval)
5002 {
5003 CompileOptions options(cx);
5004 options.setFileAndLine(filename, lineno);
5006 return ::Evaluate(cx, obj, options, bytes, nbytes, rval.address());
5007 }
5009 JS_PUBLIC_API(bool)
5010 JS_EvaluateScript(JSContext *cx, HandleObject obj, const char *bytes, unsigned nbytes,
5011 const char *filename, unsigned lineno)
5012 {
5013 CompileOptions options(cx);
5014 options.setFileAndLine(filename, lineno);
5016 return ::Evaluate(cx, obj, options, bytes, nbytes, nullptr);
5017 }
5019 JS_PUBLIC_API(bool)
5020 JS_CallFunction(JSContext *cx, HandleObject obj, HandleFunction fun, const HandleValueArray& args,
5021 MutableHandleValue rval)
5022 {
5023 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
5024 AssertHeapIsIdle(cx);
5025 CHECK_REQUEST(cx);
5026 assertSameCompartment(cx, obj, fun, args);
5027 AutoLastFrameCheck lfc(cx);
5029 return Invoke(cx, ObjectOrNullValue(obj), ObjectValue(*fun), args.length(), args.begin(), rval);
5030 }
5032 JS_PUBLIC_API(bool)
5033 JS_CallFunctionName(JSContext *cx, HandleObject obj, const char *name, const HandleValueArray& args,
5034 MutableHandleValue rval)
5035 {
5036 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
5037 AssertHeapIsIdle(cx);
5038 CHECK_REQUEST(cx);
5039 assertSameCompartment(cx, obj, args);
5040 AutoLastFrameCheck lfc(cx);
5042 JSAtom *atom = Atomize(cx, name, strlen(name));
5043 if (!atom)
5044 return false;
5046 RootedValue v(cx);
5047 RootedId id(cx, AtomToId(atom));
5048 if (!JSObject::getGeneric(cx, obj, obj, id, &v))
5049 return false;
5051 return Invoke(cx, ObjectOrNullValue(obj), v, args.length(), args.begin(), rval);
5052 }
5054 JS_PUBLIC_API(bool)
5055 JS_CallFunctionValue(JSContext *cx, HandleObject obj, HandleValue fval, const HandleValueArray& args,
5056 MutableHandleValue rval)
5057 {
5058 JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
5059 AssertHeapIsIdle(cx);
5060 CHECK_REQUEST(cx);
5061 assertSameCompartment(cx, obj, fval, args);
5062 AutoLastFrameCheck lfc(cx);
5064 return Invoke(cx, ObjectOrNullValue(obj), fval, args.length(), args.begin(), rval);
5065 }
5067 JS_PUBLIC_API(bool)
5068 JS::Call(JSContext *cx, HandleValue thisv, HandleValue fval, const JS::HandleValueArray& args,
5069 MutableHandleValue rval)
5070 {
5071 AssertHeapIsIdle(cx);
5072 CHECK_REQUEST(cx);
5073 assertSameCompartment(cx, thisv, fval, args);
5074 AutoLastFrameCheck lfc(cx);
5076 return Invoke(cx, thisv, fval, args.length(), args.begin(), rval);
5077 }
5079 static JSObject *
5080 JS_NewHelper(JSContext *cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
5081 {
5082 AssertHeapIsIdle(cx);
5083 CHECK_REQUEST(cx);
5084 assertSameCompartment(cx, ctor, inputArgs);
5086 // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
5087 // is not a simple variation of JSOP_CALL. We have to determine what class
5088 // of object to create, create it, and clamp the return value to an object,
5089 // among other details. InvokeConstructor does the hard work.
5090 InvokeArgs args(cx);
5091 if (!args.init(inputArgs.length()))
5092 return nullptr;
5094 args.setCallee(ObjectValue(*ctor));
5095 args.setThis(NullValue());
5096 PodCopy(args.array(), inputArgs.begin(), inputArgs.length());
5098 if (!InvokeConstructor(cx, args))
5099 return nullptr;
5101 if (!args.rval().isObject()) {
5102 /*
5103 * Although constructors may return primitives (via proxies), this
5104 * API is asking for an object, so we report an error.
5105 */
5106 JSAutoByteString bytes;
5107 if (js_ValueToPrintable(cx, args.rval(), &bytes)) {
5108 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_NEW_RESULT,
5109 bytes.ptr());
5110 }
5111 return nullptr;
5112 }
5114 return &args.rval().toObject();
5115 }
5117 JS_PUBLIC_API(JSObject *)
5118 JS_New(JSContext *cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
5119 {
5120 RootedObject obj(cx);
5121 {
5122 AutoLastFrameCheck lfc(cx);
5123 obj = JS_NewHelper(cx, ctor, inputArgs);
5124 }
5125 return obj;
5126 }
5128 JS_PUBLIC_API(JSInterruptCallback)
5129 JS_SetInterruptCallback(JSRuntime *rt, JSInterruptCallback callback)
5130 {
5131 JSInterruptCallback old = rt->interruptCallback;
5132 rt->interruptCallback = callback;
5133 return old;
5134 }
5136 JS_PUBLIC_API(JSInterruptCallback)
5137 JS_GetInterruptCallback(JSRuntime *rt)
5138 {
5139 return rt->interruptCallback;
5140 }
5142 JS_PUBLIC_API(void)
5143 JS_RequestInterruptCallback(JSRuntime *rt)
5144 {
5145 rt->requestInterrupt(JSRuntime::RequestInterruptAnyThread);
5146 }
5148 JS_PUBLIC_API(bool)
5149 JS_IsRunning(JSContext *cx)
5150 {
5151 return cx->currentlyRunning();
5152 }
5154 JS_PUBLIC_API(bool)
5155 JS_SaveFrameChain(JSContext *cx)
5156 {
5157 AssertHeapIsIdleOrIterating(cx);
5158 CHECK_REQUEST(cx);
5159 return cx->saveFrameChain();
5160 }
5162 JS_PUBLIC_API(void)
5163 JS_RestoreFrameChain(JSContext *cx)
5164 {
5165 AssertHeapIsIdleOrIterating(cx);
5166 CHECK_REQUEST(cx);
5167 cx->restoreFrameChain();
5168 }
5170 #ifdef MOZ_TRACE_JSCALLS
5171 JS_PUBLIC_API(void)
5172 JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb)
5173 {
5174 cx->functionCallback = fcb;
5175 }
5177 JS_PUBLIC_API(JSFunctionCallback)
5178 JS_GetFunctionCallback(JSContext *cx)
5179 {
5180 return cx->functionCallback;
5181 }
5182 #endif
5184 /************************************************************************/
5185 JS_PUBLIC_API(JSString *)
5186 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
5187 {
5188 AssertHeapIsIdle(cx);
5189 CHECK_REQUEST(cx);
5190 if (!n)
5191 return cx->names().empty;
5192 return js_NewStringCopyN<CanGC>(cx, s, n);
5193 }
5195 JS_PUBLIC_API(JSString *)
5196 JS_NewStringCopyZ(JSContext *cx, const char *s)
5197 {
5198 size_t n;
5199 jschar *js;
5200 JSString *str;
5202 AssertHeapIsIdle(cx);
5203 CHECK_REQUEST(cx);
5204 if (!s || !*s)
5205 return cx->runtime()->emptyString;
5206 n = strlen(s);
5207 js = InflateString(cx, s, &n);
5208 if (!js)
5209 return nullptr;
5210 str = js_NewString<CanGC>(cx, js, n);
5211 if (!str)
5212 js_free(js);
5213 return str;
5214 }
5216 JS_PUBLIC_API(bool)
5217 JS_StringHasBeenInterned(JSContext *cx, JSString *str)
5218 {
5219 AssertHeapIsIdle(cx);
5220 CHECK_REQUEST(cx);
5222 if (!str->isAtom())
5223 return false;
5225 return AtomIsInterned(cx, &str->asAtom());
5226 }
5228 JS_PUBLIC_API(jsid)
5229 INTERNED_STRING_TO_JSID(JSContext *cx, JSString *str)
5230 {
5231 JS_ASSERT(str);
5232 JS_ASSERT(((size_t)str & JSID_TYPE_MASK) == 0);
5233 JS_ASSERT_IF(cx, JS_StringHasBeenInterned(cx, str));
5234 return AtomToId(&str->asAtom());
5235 }
5237 JS_PUBLIC_API(JSString *)
5238 JS_InternJSString(JSContext *cx, HandleString str)
5239 {
5240 AssertHeapIsIdle(cx);
5241 CHECK_REQUEST(cx);
5242 JSAtom *atom = AtomizeString(cx, str, InternAtom);
5243 JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
5244 return atom;
5245 }
5247 JS_PUBLIC_API(JSString *)
5248 JS_InternString(JSContext *cx, const char *s)
5249 {
5250 return JS_InternStringN(cx, s, strlen(s));
5251 }
5253 JS_PUBLIC_API(JSString *)
5254 JS_InternStringN(JSContext *cx, const char *s, size_t length)
5255 {
5256 AssertHeapIsIdle(cx);
5257 CHECK_REQUEST(cx);
5258 JSAtom *atom = Atomize(cx, s, length, InternAtom);
5259 JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
5260 return atom;
5261 }
5263 JS_PUBLIC_API(JSString *)
5264 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
5265 {
5266 AssertHeapIsIdle(cx);
5267 CHECK_REQUEST(cx);
5268 return js_NewString<CanGC>(cx, chars, length);
5269 }
5271 JS_PUBLIC_API(JSString *)
5272 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
5273 {
5274 AssertHeapIsIdle(cx);
5275 CHECK_REQUEST(cx);
5276 if (!n)
5277 return cx->names().empty;
5278 return js_NewStringCopyN<CanGC>(cx, s, n);
5279 }
5281 JS_PUBLIC_API(JSString *)
5282 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
5283 {
5284 AssertHeapIsIdle(cx);
5285 CHECK_REQUEST(cx);
5286 if (!s)
5287 return cx->runtime()->emptyString;
5288 return js_NewStringCopyZ<CanGC>(cx, s);
5289 }
5291 JS_PUBLIC_API(JSString *)
5292 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
5293 {
5294 AssertHeapIsIdle(cx);
5295 CHECK_REQUEST(cx);
5296 JSAtom *atom = AtomizeChars(cx, s, length, InternAtom);
5297 JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
5298 return atom;
5299 }
5301 JS_PUBLIC_API(JSString *)
5302 JS_InternUCString(JSContext *cx, const jschar *s)
5303 {
5304 return JS_InternUCStringN(cx, s, js_strlen(s));
5305 }
5307 JS_PUBLIC_API(size_t)
5308 JS_GetStringLength(JSString *str)
5309 {
5310 return str->length();
5311 }
5313 JS_PUBLIC_API(const jschar *)
5314 JS_GetStringCharsZ(JSContext *cx, JSString *str)
5315 {
5316 size_t dummy;
5317 return JS_GetStringCharsZAndLength(cx, str, &dummy);
5318 }
5320 JS_PUBLIC_API(const jschar *)
5321 JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength)
5322 {
5323 /*
5324 * Don't require |cx->compartment()| to be |str|'s compartment. We don't need
5325 * it, and it's annoying for callers.
5326 */
5327 JS_ASSERT(plength);
5328 AssertHeapIsIdleOrStringIsFlat(cx, str);
5329 CHECK_REQUEST(cx);
5330 JSFlatString *flat = str->ensureFlat(cx);
5331 if (!flat)
5332 return nullptr;
5333 *plength = flat->length();
5334 return flat->chars();
5335 }
5337 JS_PUBLIC_API(const jschar *)
5338 JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
5339 {
5340 JS_ASSERT(plength);
5341 AssertHeapIsIdleOrStringIsFlat(cx, str);
5342 CHECK_REQUEST(cx);
5343 assertSameCompartment(cx, str);
5344 JSLinearString *linear = str->ensureLinear(cx);
5345 if (!linear)
5346 return nullptr;
5347 *plength = linear->length();
5348 return linear->chars();
5349 }
5351 JS_PUBLIC_API(const jschar *)
5352 JS_GetInternedStringChars(JSString *str)
5353 {
5354 JS_ASSERT(str->isAtom());
5355 JSFlatString *flat = str->ensureFlat(nullptr);
5356 if (!flat)
5357 return nullptr;
5358 return flat->chars();
5359 }
5361 JS_PUBLIC_API(const jschar *)
5362 JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength)
5363 {
5364 JS_ASSERT(str->isAtom());
5365 JS_ASSERT(plength);
5366 JSFlatString *flat = str->ensureFlat(nullptr);
5367 if (!flat)
5368 return nullptr;
5369 *plength = flat->length();
5370 return flat->chars();
5371 }
5373 extern JS_PUBLIC_API(JSFlatString *)
5374 JS_FlattenString(JSContext *cx, JSString *str)
5375 {
5376 AssertHeapIsIdle(cx);
5377 CHECK_REQUEST(cx);
5378 assertSameCompartment(cx, str);
5379 JSFlatString *flat = str->ensureFlat(cx);
5380 if (!flat)
5381 return nullptr;
5382 return flat;
5383 }
5385 extern JS_PUBLIC_API(const jschar *)
5386 JS_GetFlatStringChars(JSFlatString *str)
5387 {
5388 return str->chars();
5389 }
5391 JS_PUBLIC_API(bool)
5392 JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result)
5393 {
5394 AssertHeapIsIdle(cx);
5395 CHECK_REQUEST(cx);
5397 return CompareStrings(cx, str1, str2, result);
5398 }
5400 JS_PUBLIC_API(bool)
5401 JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, bool *match)
5402 {
5403 AssertHeapIsIdle(cx);
5404 CHECK_REQUEST(cx);
5406 JSLinearString *linearStr = str->ensureLinear(cx);
5407 if (!linearStr)
5408 return false;
5409 *match = StringEqualsAscii(linearStr, asciiBytes);
5410 return true;
5411 }
5413 JS_PUBLIC_API(bool)
5414 JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes)
5415 {
5416 return StringEqualsAscii(str, asciiBytes);
5417 }
5419 JS_PUBLIC_API(size_t)
5420 JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote)
5421 {
5422 return PutEscapedString(buffer, size, str, quote);
5423 }
5425 JS_PUBLIC_API(size_t)
5426 JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote)
5427 {
5428 AssertHeapIsIdle(cx);
5429 JSLinearString *linearStr = str->ensureLinear(cx);
5430 if (!linearStr)
5431 return size_t(-1);
5432 return PutEscapedString(buffer, size, linearStr, quote);
5433 }
5435 JS_PUBLIC_API(bool)
5436 JS_FileEscapedString(FILE *fp, JSString *str, char quote)
5437 {
5438 JSLinearString *linearStr = str->ensureLinear(nullptr);
5439 return linearStr && FileEscapedString(fp, linearStr, quote);
5440 }
5442 JS_PUBLIC_API(JSString *)
5443 JS_NewDependentString(JSContext *cx, HandleString str, size_t start, size_t length)
5444 {
5445 AssertHeapIsIdle(cx);
5446 CHECK_REQUEST(cx);
5447 return js_NewDependentString(cx, str, start, length);
5448 }
5450 JS_PUBLIC_API(JSString *)
5451 JS_ConcatStrings(JSContext *cx, HandleString left, HandleString right)
5452 {
5453 AssertHeapIsIdle(cx);
5454 CHECK_REQUEST(cx);
5455 return ConcatStrings<CanGC>(cx, left, right);
5456 }
5458 JS_PUBLIC_API(bool)
5459 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp)
5460 {
5461 AssertHeapIsIdle(cx);
5462 CHECK_REQUEST(cx);
5464 if (!dst) {
5465 *dstlenp = srclen;
5466 return true;
5467 }
5469 size_t dstlen = *dstlenp;
5471 if (srclen > dstlen) {
5472 InflateStringToBuffer(src, dstlen, dst);
5474 AutoSuppressGC suppress(cx);
5475 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BUFFER_TOO_SMALL);
5476 return false;
5477 }
5479 InflateStringToBuffer(src, srclen, dst);
5480 *dstlenp = srclen;
5481 return true;
5482 }
5484 JS_PUBLIC_API(char *)
5485 JS_EncodeString(JSContext *cx, JSString *str)
5486 {
5487 AssertHeapIsIdle(cx);
5488 CHECK_REQUEST(cx);
5490 JSLinearString *linear = str->ensureLinear(cx);
5491 if (!linear)
5492 return nullptr;
5494 return LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->range()).c_str();
5495 }
5497 JS_PUBLIC_API(char *)
5498 JS_EncodeStringToUTF8(JSContext *cx, HandleString str)
5499 {
5500 AssertHeapIsIdle(cx);
5501 CHECK_REQUEST(cx);
5503 JSLinearString *linear = str->ensureLinear(cx);
5504 if (!linear)
5505 return nullptr;
5507 return TwoByteCharsToNewUTF8CharsZ(cx, linear->range()).c_str();
5508 }
5510 JS_PUBLIC_API(size_t)
5511 JS_GetStringEncodingLength(JSContext *cx, JSString *str)
5512 {
5513 AssertHeapIsIdle(cx);
5514 CHECK_REQUEST(cx);
5516 const jschar *chars = str->getChars(cx);
5517 if (!chars)
5518 return size_t(-1);
5519 return str->length();
5520 }
5522 JS_PUBLIC_API(size_t)
5523 JS_EncodeStringToBuffer(JSContext *cx, JSString *str, char *buffer, size_t length)
5524 {
5525 AssertHeapIsIdle(cx);
5526 CHECK_REQUEST(cx);
5528 /*
5529 * FIXME bug 612141 - fix DeflateStringToBuffer interface so the result
5530 * would allow to distinguish between insufficient buffer and encoding
5531 * error.
5532 */
5533 size_t writtenLength = length;
5534 const jschar *chars = str->getChars(nullptr);
5535 if (!chars)
5536 return size_t(-1);
5537 if (DeflateStringToBuffer(nullptr, chars, str->length(), buffer, &writtenLength)) {
5538 JS_ASSERT(writtenLength <= length);
5539 return writtenLength;
5540 }
5541 JS_ASSERT(writtenLength <= length);
5542 size_t necessaryLength = str->length();
5543 if (necessaryLength == size_t(-1))
5544 return size_t(-1);
5545 JS_ASSERT(writtenLength == length); // C strings are NOT encoded.
5546 return necessaryLength;
5547 }
5549 JS_PUBLIC_API(bool)
5550 JS_Stringify(JSContext *cx, MutableHandleValue vp, HandleObject replacer,
5551 HandleValue space, JSONWriteCallback callback, void *data)
5552 {
5553 AssertHeapIsIdle(cx);
5554 CHECK_REQUEST(cx);
5555 assertSameCompartment(cx, replacer, space);
5556 StringBuffer sb(cx);
5557 if (!js_Stringify(cx, vp, replacer, space, sb))
5558 return false;
5559 if (sb.empty()) {
5560 HandlePropertyName null = cx->names().null;
5561 return callback(null->chars(), null->length(), data);
5562 }
5563 return callback(sb.begin(), sb.length(), data);
5564 }
5566 JS_PUBLIC_API(bool)
5567 JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, JS::MutableHandleValue vp)
5568 {
5569 AssertHeapIsIdle(cx);
5570 CHECK_REQUEST(cx);
5572 RootedValue reviver(cx, NullValue());
5573 return ParseJSONWithReviver(cx, ConstTwoByteChars(chars, len), len, reviver, vp);
5574 }
5576 JS_PUBLIC_API(bool)
5577 JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, HandleValue reviver, MutableHandleValue vp)
5578 {
5579 AssertHeapIsIdle(cx);
5580 CHECK_REQUEST(cx);
5581 return ParseJSONWithReviver(cx, ConstTwoByteChars(chars, len), len, reviver, vp);
5582 }
5584 /************************************************************************/
5586 JS_PUBLIC_API(void)
5587 JS_ReportError(JSContext *cx, const char *format, ...)
5588 {
5589 va_list ap;
5591 AssertHeapIsIdle(cx);
5592 va_start(ap, format);
5593 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
5594 va_end(ap);
5595 }
5597 JS_PUBLIC_API(void)
5598 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
5599 void *userRef, const unsigned errorNumber, ...)
5600 {
5601 va_list ap;
5602 va_start(ap, errorNumber);
5603 JS_ReportErrorNumberVA(cx, errorCallback, userRef, errorNumber, ap);
5604 va_end(ap);
5605 }
5607 JS_PUBLIC_API(void)
5608 JS_ReportErrorNumberVA(JSContext *cx, JSErrorCallback errorCallback,
5609 void *userRef, const unsigned errorNumber,
5610 va_list ap)
5611 {
5612 AssertHeapIsIdle(cx);
5613 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5614 errorNumber, ArgumentsAreASCII, ap);
5615 }
5617 JS_PUBLIC_API(void)
5618 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
5619 void *userRef, const unsigned errorNumber, ...)
5620 {
5621 va_list ap;
5623 AssertHeapIsIdle(cx);
5624 va_start(ap, errorNumber);
5625 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5626 errorNumber, ArgumentsAreUnicode, ap);
5627 va_end(ap);
5628 }
5630 JS_PUBLIC_API(void)
5631 JS_ReportErrorNumberUCArray(JSContext *cx, JSErrorCallback errorCallback,
5632 void *userRef, const unsigned errorNumber,
5633 const jschar **args)
5634 {
5635 AssertHeapIsIdle(cx);
5636 js_ReportErrorNumberUCArray(cx, JSREPORT_ERROR, errorCallback, userRef,
5637 errorNumber, args);
5638 }
5640 JS_PUBLIC_API(bool)
5641 JS_ReportWarning(JSContext *cx, const char *format, ...)
5642 {
5643 va_list ap;
5644 bool ok;
5646 AssertHeapIsIdle(cx);
5647 va_start(ap, format);
5648 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
5649 va_end(ap);
5650 return ok;
5651 }
5653 JS_PUBLIC_API(bool)
5654 JS_ReportErrorFlagsAndNumber(JSContext *cx, unsigned flags,
5655 JSErrorCallback errorCallback, void *userRef,
5656 const unsigned errorNumber, ...)
5657 {
5658 va_list ap;
5659 bool ok;
5661 AssertHeapIsIdle(cx);
5662 va_start(ap, errorNumber);
5663 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5664 errorNumber, ArgumentsAreASCII, ap);
5665 va_end(ap);
5666 return ok;
5667 }
5669 JS_PUBLIC_API(bool)
5670 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, unsigned flags,
5671 JSErrorCallback errorCallback, void *userRef,
5672 const unsigned errorNumber, ...)
5673 {
5674 va_list ap;
5675 bool ok;
5677 AssertHeapIsIdle(cx);
5678 va_start(ap, errorNumber);
5679 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5680 errorNumber, ArgumentsAreUnicode, ap);
5681 va_end(ap);
5682 return ok;
5683 }
5685 JS_PUBLIC_API(void)
5686 JS_ReportOutOfMemory(JSContext *cx)
5687 {
5688 js_ReportOutOfMemory(cx);
5689 }
5691 JS_PUBLIC_API(void)
5692 JS_ReportAllocationOverflow(JSContext *cx)
5693 {
5694 js_ReportAllocationOverflow(cx);
5695 }
5697 JS_PUBLIC_API(JSErrorReporter)
5698 JS_GetErrorReporter(JSContext *cx)
5699 {
5700 return cx->errorReporter;
5701 }
5703 JS_PUBLIC_API(JSErrorReporter)
5704 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
5705 {
5706 JSErrorReporter older;
5708 older = cx->errorReporter;
5709 cx->errorReporter = er;
5710 return older;
5711 }
5713 /************************************************************************/
5715 /*
5716 * Dates.
5717 */
5718 JS_PUBLIC_API(JSObject *)
5719 JS_NewDateObject(JSContext *cx, int year, int mon, int mday, int hour, int min, int sec)
5720 {
5721 AssertHeapIsIdle(cx);
5722 CHECK_REQUEST(cx);
5723 return js_NewDateObject(cx, year, mon, mday, hour, min, sec);
5724 }
5726 JS_PUBLIC_API(JSObject *)
5727 JS_NewDateObjectMsec(JSContext *cx, double msec)
5728 {
5729 AssertHeapIsIdle(cx);
5730 CHECK_REQUEST(cx);
5731 return js_NewDateObjectMsec(cx, msec);
5732 }
5734 JS_PUBLIC_API(bool)
5735 JS_ObjectIsDate(JSContext *cx, HandleObject obj)
5736 {
5737 assertSameCompartment(cx, obj);
5738 return ObjectClassIs(obj, ESClass_Date, cx);
5739 }
5741 JS_PUBLIC_API(void)
5742 JS_ClearDateCaches(JSContext *cx)
5743 {
5744 AssertHeapIsIdle(cx);
5745 CHECK_REQUEST(cx);
5746 cx->runtime()->dateTimeInfo.updateTimeZoneAdjustment();
5747 }
5749 /************************************************************************/
5751 /*
5752 * Regular Expressions.
5753 */
5754 JS_PUBLIC_API(JSObject *)
5755 JS_NewRegExpObject(JSContext *cx, HandleObject obj, char *bytes, size_t length, unsigned flags)
5756 {
5757 AssertHeapIsIdle(cx);
5758 CHECK_REQUEST(cx);
5759 jschar *chars = InflateString(cx, bytes, &length);
5760 if (!chars)
5761 return nullptr;
5763 RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics();
5764 RegExpObject *reobj = RegExpObject::create(cx, res, chars, length,
5765 RegExpFlag(flags), nullptr);
5766 js_free(chars);
5767 return reobj;
5768 }
5770 JS_PUBLIC_API(JSObject *)
5771 JS_NewUCRegExpObject(JSContext *cx, HandleObject obj, jschar *chars, size_t length,
5772 unsigned flags)
5773 {
5774 AssertHeapIsIdle(cx);
5775 CHECK_REQUEST(cx);
5776 RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics();
5777 return RegExpObject::create(cx, res, chars, length,
5778 RegExpFlag(flags), nullptr);
5779 }
5781 JS_PUBLIC_API(void)
5782 JS_SetRegExpInput(JSContext *cx, HandleObject obj, HandleString input, bool multiline)
5783 {
5784 AssertHeapIsIdle(cx);
5785 CHECK_REQUEST(cx);
5786 assertSameCompartment(cx, input);
5788 obj->as<GlobalObject>().getRegExpStatics()->reset(cx, input, !!multiline);
5789 }
5791 JS_PUBLIC_API(void)
5792 JS_ClearRegExpStatics(JSContext *cx, HandleObject obj)
5793 {
5794 AssertHeapIsIdle(cx);
5795 CHECK_REQUEST(cx);
5796 JS_ASSERT(obj);
5798 obj->as<GlobalObject>().getRegExpStatics()->clear();
5799 }
5801 JS_PUBLIC_API(bool)
5802 JS_ExecuteRegExp(JSContext *cx, HandleObject obj, HandleObject reobj, jschar *chars,
5803 size_t length, size_t *indexp, bool test, MutableHandleValue rval)
5804 {
5805 AssertHeapIsIdle(cx);
5806 CHECK_REQUEST(cx);
5808 RegExpStatics *res = obj->as<GlobalObject>().getRegExpStatics();
5810 return ExecuteRegExpLegacy(cx, res, reobj->as<RegExpObject>(), NullPtr(), chars, length, indexp,
5811 test, rval);
5812 }
5814 JS_PUBLIC_API(JSObject *)
5815 JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, unsigned flags)
5816 {
5817 AssertHeapIsIdle(cx);
5818 CHECK_REQUEST(cx);
5819 jschar *chars = InflateString(cx, bytes, &length);
5820 if (!chars)
5821 return nullptr;
5822 RegExpObject *reobj = RegExpObject::createNoStatics(cx, chars, length,
5823 RegExpFlag(flags), nullptr);
5824 js_free(chars);
5825 return reobj;
5826 }
5828 JS_PUBLIC_API(JSObject *)
5829 JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, unsigned flags)
5830 {
5831 AssertHeapIsIdle(cx);
5832 CHECK_REQUEST(cx);
5833 return RegExpObject::createNoStatics(cx, chars, length,
5834 RegExpFlag(flags), nullptr);
5835 }
5837 JS_PUBLIC_API(bool)
5838 JS_ExecuteRegExpNoStatics(JSContext *cx, HandleObject obj, jschar *chars, size_t length,
5839 size_t *indexp, bool test, MutableHandleValue rval)
5840 {
5841 AssertHeapIsIdle(cx);
5842 CHECK_REQUEST(cx);
5844 return ExecuteRegExpLegacy(cx, nullptr, obj->as<RegExpObject>(), NullPtr(), chars, length,
5845 indexp, test, rval);
5846 }
5848 JS_PUBLIC_API(bool)
5849 JS_ObjectIsRegExp(JSContext *cx, HandleObject obj)
5850 {
5851 assertSameCompartment(cx, obj);
5852 return ObjectClassIs(obj, ESClass_RegExp, cx);
5853 }
5855 JS_PUBLIC_API(unsigned)
5856 JS_GetRegExpFlags(JSContext *cx, HandleObject obj)
5857 {
5858 AssertHeapIsIdle(cx);
5859 CHECK_REQUEST(cx);
5861 return obj->as<RegExpObject>().getFlags();
5862 }
5864 JS_PUBLIC_API(JSString *)
5865 JS_GetRegExpSource(JSContext *cx, HandleObject obj)
5866 {
5867 AssertHeapIsIdle(cx);
5868 CHECK_REQUEST(cx);
5870 return obj->as<RegExpObject>().getSource();
5871 }
5873 /************************************************************************/
5875 JS_PUBLIC_API(bool)
5876 JS_SetDefaultLocale(JSRuntime *rt, const char *locale)
5877 {
5878 AssertHeapIsIdle(rt);
5879 return rt->setDefaultLocale(locale);
5880 }
5882 JS_PUBLIC_API(const char*)
5883 JS_GetDefaultLocale(JSRuntime *rt)
5884 {
5885 AssertHeapIsIdle(rt);
5886 return rt->getDefaultLocale();
5887 }
5889 JS_PUBLIC_API(void)
5890 JS_ResetDefaultLocale(JSRuntime *rt)
5891 {
5892 AssertHeapIsIdle(rt);
5893 rt->resetDefaultLocale();
5894 }
5896 JS_PUBLIC_API(void)
5897 JS_SetLocaleCallbacks(JSRuntime *rt, JSLocaleCallbacks *callbacks)
5898 {
5899 AssertHeapIsIdle(rt);
5900 rt->localeCallbacks = callbacks;
5901 }
5903 JS_PUBLIC_API(JSLocaleCallbacks *)
5904 JS_GetLocaleCallbacks(JSRuntime *rt)
5905 {
5906 /* This function can be called by a finalizer. */
5907 return rt->localeCallbacks;
5908 }
5910 /************************************************************************/
5912 JS_PUBLIC_API(bool)
5913 JS_IsExceptionPending(JSContext *cx)
5914 {
5915 /* This function can be called by a finalizer. */
5916 return (bool) cx->isExceptionPending();
5917 }
5919 JS_PUBLIC_API(bool)
5920 JS_GetPendingException(JSContext *cx, MutableHandleValue vp)
5921 {
5922 AssertHeapIsIdle(cx);
5923 CHECK_REQUEST(cx);
5924 if (!cx->isExceptionPending())
5925 return false;
5926 return cx->getPendingException(vp);
5927 }
5929 JS_PUBLIC_API(void)
5930 JS_SetPendingException(JSContext *cx, HandleValue value)
5931 {
5932 AssertHeapIsIdle(cx);
5933 CHECK_REQUEST(cx);
5934 assertSameCompartment(cx, value);
5935 cx->setPendingException(value);
5936 }
5938 JS_PUBLIC_API(void)
5939 JS_ClearPendingException(JSContext *cx)
5940 {
5941 AssertHeapIsIdle(cx);
5942 cx->clearPendingException();
5943 }
5945 JS_PUBLIC_API(bool)
5946 JS_ReportPendingException(JSContext *cx)
5947 {
5948 AssertHeapIsIdle(cx);
5949 CHECK_REQUEST(cx);
5951 // This can only fail due to oom.
5952 bool ok = js_ReportUncaughtException(cx);
5953 JS_ASSERT(!cx->isExceptionPending());
5954 return ok;
5955 }
5957 JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext *cx)
5958 : context(cx), wasThrowing(cx->throwing), exceptionValue(cx)
5959 {
5960 AssertHeapIsIdle(cx);
5961 CHECK_REQUEST(cx);
5962 if (wasThrowing) {
5963 exceptionValue = cx->unwrappedException_;
5964 cx->clearPendingException();
5965 }
5966 }
5968 void
5969 JS::AutoSaveExceptionState::restore()
5970 {
5971 context->throwing = wasThrowing;
5972 context->unwrappedException_ = exceptionValue;
5973 drop();
5974 }
5976 JS::AutoSaveExceptionState::~AutoSaveExceptionState()
5977 {
5978 if (wasThrowing && !context->isExceptionPending()) {
5979 context->throwing = true;
5980 context->unwrappedException_ = exceptionValue;
5981 }
5982 }
5984 struct JSExceptionState {
5985 bool throwing;
5986 jsval exception;
5987 };
5989 JS_PUBLIC_API(JSExceptionState *)
5990 JS_SaveExceptionState(JSContext *cx)
5991 {
5992 JSExceptionState *state;
5994 AssertHeapIsIdle(cx);
5995 CHECK_REQUEST(cx);
5996 state = cx->pod_malloc<JSExceptionState>();
5997 if (state) {
5998 state->throwing =
5999 JS_GetPendingException(cx, MutableHandleValue::fromMarkedLocation(&state->exception));
6000 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
6001 AddValueRoot(cx, &state->exception, "JSExceptionState.exception");
6002 }
6003 return state;
6004 }
6006 JS_PUBLIC_API(void)
6007 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
6008 {
6009 AssertHeapIsIdle(cx);
6010 CHECK_REQUEST(cx);
6011 if (state) {
6012 if (state->throwing)
6013 JS_SetPendingException(cx, HandleValue::fromMarkedLocation(&state->exception));
6014 else
6015 JS_ClearPendingException(cx);
6016 JS_DropExceptionState(cx, state);
6017 }
6018 }
6020 JS_PUBLIC_API(void)
6021 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
6022 {
6023 AssertHeapIsIdle(cx);
6024 CHECK_REQUEST(cx);
6025 if (state) {
6026 if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
6027 assertSameCompartment(cx, state->exception);
6028 RemoveRoot(cx->runtime(), &state->exception);
6029 }
6030 js_free(state);
6031 }
6032 }
6034 JS_PUBLIC_API(JSErrorReport *)
6035 JS_ErrorFromException(JSContext *cx, HandleObject obj)
6036 {
6037 AssertHeapIsIdle(cx);
6038 CHECK_REQUEST(cx);
6039 assertSameCompartment(cx, obj);
6040 return js_ErrorFromException(cx, obj);
6041 }
6043 JS_PUBLIC_API(bool)
6044 JS_ThrowStopIteration(JSContext *cx)
6045 {
6046 AssertHeapIsIdle(cx);
6047 return js_ThrowStopIteration(cx);
6048 }
6050 JS_PUBLIC_API(bool)
6051 JS_IsStopIteration(jsval v)
6052 {
6053 return v.isObject() && v.toObject().is<StopIterationObject>();
6054 }
6056 JS_PUBLIC_API(intptr_t)
6057 JS_GetCurrentThread()
6058 {
6059 #ifdef JS_THREADSAFE
6060 return reinterpret_cast<intptr_t>(PR_GetCurrentThread());
6061 #else
6062 return 0;
6063 #endif
6064 }
6066 extern MOZ_NEVER_INLINE JS_PUBLIC_API(void)
6067 JS_AbortIfWrongThread(JSRuntime *rt)
6068 {
6069 if (!CurrentThreadCanAccessRuntime(rt))
6070 MOZ_CRASH();
6071 if (!js::TlsPerThreadData.get()->associatedWith(rt))
6072 MOZ_CRASH();
6073 }
6075 #ifdef JS_GC_ZEAL
6076 JS_PUBLIC_API(void)
6077 JS_SetGCZeal(JSContext *cx, uint8_t zeal, uint32_t frequency)
6078 {
6079 SetGCZeal(cx->runtime(), zeal, frequency);
6080 }
6082 JS_PUBLIC_API(void)
6083 JS_ScheduleGC(JSContext *cx, uint32_t count)
6084 {
6085 cx->runtime()->gcNextScheduled = count;
6086 }
6087 #endif
6089 JS_PUBLIC_API(void)
6090 JS_SetParallelParsingEnabled(JSRuntime *rt, bool enabled)
6091 {
6092 #ifdef JS_ION
6093 rt->setParallelParsingEnabled(enabled);
6094 #endif
6095 }
6097 JS_PUBLIC_API(void)
6098 JS_SetParallelIonCompilationEnabled(JSRuntime *rt, bool enabled)
6099 {
6100 #ifdef JS_ION
6101 rt->setParallelIonCompilationEnabled(enabled);
6102 #endif
6103 }
6105 JS_PUBLIC_API(void)
6106 JS_SetGlobalJitCompilerOption(JSRuntime *rt, JSJitCompilerOption opt, uint32_t value)
6107 {
6108 #ifdef JS_ION
6110 switch (opt) {
6111 case JSJITCOMPILER_BASELINE_USECOUNT_TRIGGER:
6112 if (value == uint32_t(-1)) {
6113 jit::JitOptions defaultValues;
6114 value = defaultValues.baselineUsesBeforeCompile;
6115 }
6116 jit::js_JitOptions.baselineUsesBeforeCompile = value;
6117 break;
6118 case JSJITCOMPILER_ION_USECOUNT_TRIGGER:
6119 if (value == uint32_t(-1)) {
6120 jit::js_JitOptions.resetUsesBeforeCompile();
6121 break;
6122 }
6123 jit::js_JitOptions.setUsesBeforeCompile(value);
6124 if (value == 0)
6125 jit::js_JitOptions.setEagerCompilation();
6126 break;
6127 case JSJITCOMPILER_ION_ENABLE:
6128 if (value == 1) {
6129 JS::RuntimeOptionsRef(rt).setIon(true);
6130 IonSpew(js::jit::IonSpew_Scripts, "Enable ion");
6131 } else if (value == 0) {
6132 JS::RuntimeOptionsRef(rt).setIon(false);
6133 IonSpew(js::jit::IonSpew_Scripts, "Disable ion");
6134 }
6135 break;
6136 case JSJITCOMPILER_BASELINE_ENABLE:
6137 if (value == 1) {
6138 JS::RuntimeOptionsRef(rt).setBaseline(true);
6139 IonSpew(js::jit::IonSpew_BaselineScripts, "Enable baseline");
6140 } else if (value == 0) {
6141 JS::RuntimeOptionsRef(rt).setBaseline(false);
6142 IonSpew(js::jit::IonSpew_BaselineScripts, "Disable baseline");
6143 }
6144 break;
6145 case JSJITCOMPILER_PARALLEL_COMPILATION_ENABLE:
6146 if (value == 1) {
6147 rt->setParallelIonCompilationEnabled(true);
6148 IonSpew(js::jit::IonSpew_Scripts, "Enable parallel compilation");
6149 } else if (value == 0) {
6150 rt->setParallelIonCompilationEnabled(false);
6151 IonSpew(js::jit::IonSpew_Scripts, "Disable parallel compilation");
6152 }
6153 break;
6154 default:
6155 break;
6156 }
6157 #endif
6158 }
6160 JS_PUBLIC_API(int)
6161 JS_GetGlobalJitCompilerOption(JSRuntime *rt, JSJitCompilerOption opt)
6162 {
6163 #ifdef JS_ION
6164 switch (opt) {
6165 case JSJITCOMPILER_BASELINE_USECOUNT_TRIGGER:
6166 return jit::js_JitOptions.baselineUsesBeforeCompile;
6167 case JSJITCOMPILER_ION_USECOUNT_TRIGGER:
6168 return jit::js_JitOptions.forcedDefaultIonUsesBeforeCompile;
6169 case JSJITCOMPILER_ION_ENABLE:
6170 return JS::RuntimeOptionsRef(rt).ion();
6171 case JSJITCOMPILER_BASELINE_ENABLE:
6172 return JS::RuntimeOptionsRef(rt).baseline();
6173 case JSJITCOMPILER_PARALLEL_COMPILATION_ENABLE:
6174 return rt->canUseParallelIonCompilation();
6175 default:
6176 break;
6177 }
6178 #endif
6179 return 0;
6180 }
6182 /************************************************************************/
6184 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN)
6186 #include "jswin.h"
6188 /*
6189 * Initialization routine for the JS DLL.
6190 */
6191 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
6192 {
6193 return TRUE;
6194 }
6196 #endif
6198 JS_PUBLIC_API(bool)
6199 JS_IndexToId(JSContext *cx, uint32_t index, MutableHandleId id)
6200 {
6201 return IndexToId(cx, index, id);
6202 }
6204 JS_PUBLIC_API(bool)
6205 JS_CharsToId(JSContext* cx, JS::TwoByteChars chars, MutableHandleId idp)
6206 {
6207 RootedAtom atom(cx, AtomizeChars(cx, chars.start().get(), chars.length()));
6208 if (!atom)
6209 return false;
6210 #ifdef DEBUG
6211 uint32_t dummy;
6212 MOZ_ASSERT(!atom->isIndex(&dummy), "API misuse: |chars| must not encode an index");
6213 #endif
6214 idp.set(AtomToId(atom));
6215 return true;
6216 }
6218 JS_PUBLIC_API(bool)
6219 JS_IsIdentifier(JSContext *cx, HandleString str, bool *isIdentifier)
6220 {
6221 assertSameCompartment(cx, str);
6223 JSLinearString* linearStr = str->ensureLinear(cx);
6224 if (!linearStr)
6225 return false;
6227 *isIdentifier = js::frontend::IsIdentifier(linearStr);
6228 return true;
6229 }
6231 namespace JS {
6233 void
6234 AutoFilename::reset(void *newScriptSource)
6235 {
6236 if (newScriptSource)
6237 reinterpret_cast<ScriptSource*>(newScriptSource)->incref();
6238 if (scriptSource_)
6239 reinterpret_cast<ScriptSource*>(scriptSource_)->decref();
6240 scriptSource_ = newScriptSource;
6241 }
6243 const char *
6244 AutoFilename::get() const
6245 {
6246 JS_ASSERT(scriptSource_);
6247 return reinterpret_cast<ScriptSource*>(scriptSource_)->filename();
6248 }
6250 JS_PUBLIC_API(bool)
6251 DescribeScriptedCaller(JSContext *cx, AutoFilename *filename, unsigned *lineno)
6252 {
6253 if (lineno)
6254 *lineno = 0;
6256 NonBuiltinFrameIter i(cx);
6257 if (i.done())
6258 return false;
6260 // If the caller is hidden, the embedding wants us to return false here so
6261 // that it can check its own stack (see HideScriptedCaller).
6262 if (i.activation()->scriptedCallerIsHidden())
6263 return false;
6265 if (filename)
6266 filename->reset(i.scriptSource());
6267 if (lineno)
6268 *lineno = i.computeLine();
6269 return true;
6270 }
6272 JS_PUBLIC_API(JSObject *)
6273 GetScriptedCallerGlobal(JSContext *cx)
6274 {
6275 NonBuiltinFrameIter i(cx);
6276 if (i.done())
6277 return nullptr;
6279 // If the caller is hidden, the embedding wants us to return null here so
6280 // that it can check its own stack (see HideScriptedCaller).
6281 if (i.activation()->scriptedCallerIsHidden())
6282 return nullptr;
6284 GlobalObject *global = i.activation()->compartment()->maybeGlobal();
6286 // Noone should be running code in the atoms compartment or running code in
6287 // a compartment without any live objects, so there should definitely be a
6288 // live global.
6289 JS_ASSERT(global);
6291 return global;
6292 }
6294 JS_PUBLIC_API(void)
6295 HideScriptedCaller(JSContext *cx)
6296 {
6297 MOZ_ASSERT(cx);
6299 // If there's no accessible activation on the stack, we'll return null from
6300 // DescribeScriptedCaller anyway, so there's no need to annotate anything.
6301 Activation *act = cx->runtime()->mainThread.activation();
6302 if (!act)
6303 return;
6304 act->hideScriptedCaller();
6305 }
6307 JS_PUBLIC_API(void)
6308 UnhideScriptedCaller(JSContext *cx)
6309 {
6310 Activation *act = cx->runtime()->mainThread.activation();
6311 if (!act)
6312 return;
6313 act->unhideScriptedCaller();
6314 }
6316 } /* namespace JS */
6318 #ifdef JS_THREADSAFE
6319 static PRStatus
6320 CallOnce(void *func)
6321 {
6322 JSInitCallback init = JS_DATA_TO_FUNC_PTR(JSInitCallback, func);
6323 return init() ? PR_SUCCESS : PR_FAILURE;
6324 }
6325 #endif
6327 JS_PUBLIC_API(bool)
6328 JS_CallOnce(JSCallOnceType *once, JSInitCallback func)
6329 {
6330 #ifdef JS_THREADSAFE
6331 return PR_CallOnceWithArg(once, CallOnce, JS_FUNC_TO_DATA_PTR(void *, func)) == PR_SUCCESS;
6332 #else
6333 if (!*once) {
6334 *once = true;
6335 return func();
6336 } else {
6337 return true;
6338 }
6339 #endif
6340 }
6342 AutoGCRooter::AutoGCRooter(JSContext *cx, ptrdiff_t tag)
6343 : down(ContextFriendFields::get(cx)->autoGCRooters),
6344 tag_(tag),
6345 stackTop(&ContextFriendFields::get(cx)->autoGCRooters)
6346 {
6347 JS_ASSERT(this != *stackTop);
6348 *stackTop = this;
6349 }
6351 AutoGCRooter::AutoGCRooter(ContextFriendFields *cx, ptrdiff_t tag)
6352 : down(cx->autoGCRooters),
6353 tag_(tag),
6354 stackTop(&cx->autoGCRooters)
6355 {
6356 JS_ASSERT(this != *stackTop);
6357 *stackTop = this;
6358 }
6360 #ifdef DEBUG
6361 JS_PUBLIC_API(void)
6362 JS::AssertArgumentsAreSane(JSContext *cx, HandleValue value)
6363 {
6364 AssertHeapIsIdle(cx);
6365 CHECK_REQUEST(cx);
6366 assertSameCompartment(cx, value);
6367 }
6368 #endif /* DEBUG */
6370 JS_PUBLIC_API(void *)
6371 JS_EncodeScript(JSContext *cx, HandleScript scriptArg, uint32_t *lengthp)
6372 {
6373 XDREncoder encoder(cx);
6374 RootedScript script(cx, scriptArg);
6375 if (!encoder.codeScript(&script))
6376 return nullptr;
6377 return encoder.forgetData(lengthp);
6378 }
6380 JS_PUBLIC_API(void *)
6381 JS_EncodeInterpretedFunction(JSContext *cx, HandleObject funobjArg, uint32_t *lengthp)
6382 {
6383 XDREncoder encoder(cx);
6384 RootedObject funobj(cx, funobjArg);
6385 if (!encoder.codeFunction(&funobj))
6386 return nullptr;
6387 return encoder.forgetData(lengthp);
6388 }
6390 JS_PUBLIC_API(JSScript *)
6391 JS_DecodeScript(JSContext *cx, const void *data, uint32_t length,
6392 JSPrincipals *originPrincipals)
6393 {
6394 XDRDecoder decoder(cx, data, length, originPrincipals);
6395 RootedScript script(cx);
6396 if (!decoder.codeScript(&script))
6397 return nullptr;
6398 return script;
6399 }
6401 JS_PUBLIC_API(JSObject *)
6402 JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length,
6403 JSPrincipals *originPrincipals)
6404 {
6405 XDRDecoder decoder(cx, data, length, originPrincipals);
6406 RootedObject funobj(cx);
6407 if (!decoder.codeFunction(&funobj))
6408 return nullptr;
6409 return funobj;
6410 }
6412 JS_PUBLIC_API(bool)
6413 JS_PreventExtensions(JSContext *cx, JS::HandleObject obj)
6414 {
6415 bool extensible;
6416 if (!JSObject::isExtensible(cx, obj, &extensible))
6417 return false;
6418 if (!extensible)
6419 return true;
6420 return JSObject::preventExtensions(cx, obj);
6421 }
6423 JS_PUBLIC_API(void)
6424 JS::SetAsmJSCacheOps(JSRuntime *rt, const JS::AsmJSCacheOps *ops)
6425 {
6426 rt->asmJSCacheOps = *ops;
6427 }
6429 char *
6430 JSAutoByteString::encodeLatin1(ExclusiveContext *cx, JSString *str)
6431 {
6432 JSLinearString *linear = str->ensureLinear(cx);
6433 if (!linear)
6434 return nullptr;
6436 mBytes = LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->range()).c_str();
6437 return mBytes;
6438 }
6440 JS_PUBLIC_API(void)
6441 JS::SetLargeAllocationFailureCallback(JSRuntime *rt, JS::LargeAllocationFailureCallback lafc)
6442 {
6443 rt->largeAllocationFailureCallback = lafc;
6444 }
6446 JS_PUBLIC_API(void)
6447 JS::SetOutOfMemoryCallback(JSRuntime *rt, OutOfMemoryCallback cb)
6448 {
6449 rt->oomCallback = cb;
6450 }