Bug 752461 - Hide click-to-play overlays when choosing "never activate plugins.....
[gecko.git] / js / src / jsapi.cpp
blobb58bc49e5a08d497b60d5f544253c493956c2890
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=78:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
25 * Contributor(s):
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 * JavaScript API.
45 #include "mozilla/FloatingPoint.h"
47 #include <ctype.h>
48 #include <stdarg.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <sys/stat.h>
52 #include "jstypes.h"
53 #include "jsutil.h"
54 #include "jsclist.h"
55 #include "jsprf.h"
56 #include "jsapi.h"
57 #include "jsarray.h"
58 #include "jsatom.h"
59 #include "jsbool.h"
60 #include "jsclone.h"
61 #include "jscntxt.h"
62 #include "jsversion.h"
63 #include "jsdate.h"
64 #include "jsdtoa.h"
65 #include "jsexn.h"
66 #include "jsfun.h"
67 #include "jsgc.h"
68 #include "jsinterp.h"
69 #include "jsiter.h"
70 #include "jslock.h"
71 #include "jsmath.h"
72 #include "jsnativestack.h"
73 #include "jsnum.h"
74 #include "json.h"
75 #include "jsobj.h"
76 #include "jsopcode.h"
77 #include "jsprobes.h"
78 #include "jsproxy.h"
79 #include "jsscope.h"
80 #include "jsscript.h"
81 #include "jsstr.h"
82 #include "prmjtime.h"
83 #include "jsweakmap.h"
84 #include "jswrapper.h"
85 #include "jstypedarray.h"
86 #include "jsxml.h"
88 #include "ds/LifoAlloc.h"
89 #include "builtin/MapObject.h"
90 #include "builtin/RegExp.h"
91 #include "frontend/BytecodeCompiler.h"
92 #include "frontend/BytecodeEmitter.h"
93 #include "gc/Marking.h"
94 #include "gc/Memory.h"
95 #include "js/MemoryMetrics.h"
96 #include "yarr/BumpPointerAllocator.h"
97 #include "vm/MethodGuard.h"
98 #include "vm/NumericConversions.h"
99 #include "vm/StringBuffer.h"
100 #include "vm/Xdr.h"
102 #include "jsatominlines.h"
103 #include "jsinferinlines.h"
104 #include "jsobjinlines.h"
105 #include "jsscopeinlines.h"
106 #include "jsscriptinlines.h"
108 #include "vm/ObjectImpl-inl.h"
109 #include "vm/RegExpObject-inl.h"
110 #include "vm/RegExpStatics-inl.h"
111 #include "vm/Stack-inl.h"
112 #include "vm/String-inl.h"
114 #if ENABLE_YARR_JIT
115 #include "assembler/jit/ExecutableAllocator.h"
116 #include "methodjit/Logging.h"
117 #endif
119 using namespace js;
120 using namespace js::gc;
121 using namespace js::types;
124 * This class is a version-establising barrier at the head of a VM entry or
125 * re-entry. It ensures that:
127 * - |newVersion| is the starting (default) version used for the context.
128 * - The starting version state is not an override.
129 * - Overrides in the VM session are not propagated to the caller.
131 class AutoVersionAPI
133 JSContext * const cx;
134 JSVersion oldDefaultVersion;
135 bool oldHasVersionOverride;
136 JSVersion oldVersionOverride;
137 #ifdef DEBUG
138 unsigned oldCompileOptions;
139 #endif
140 JSVersion newVersion;
142 public:
143 explicit AutoVersionAPI(JSContext *cx, JSVersion newVersion)
144 : cx(cx),
145 oldDefaultVersion(cx->getDefaultVersion()),
146 oldHasVersionOverride(cx->isVersionOverridden()),
147 oldVersionOverride(oldHasVersionOverride ? cx->findVersion() : JSVERSION_UNKNOWN)
148 #ifdef DEBUG
149 , oldCompileOptions(cx->getCompileOptions())
150 #endif
152 this->newVersion = newVersion;
153 cx->clearVersionOverride();
154 cx->setDefaultVersion(newVersion);
157 ~AutoVersionAPI() {
158 cx->setDefaultVersion(oldDefaultVersion);
159 if (oldHasVersionOverride)
160 cx->overrideVersion(oldVersionOverride);
161 else
162 cx->clearVersionOverride();
163 JS_ASSERT(oldCompileOptions == cx->getCompileOptions());
166 /* The version that this scoped-entity establishes. */
167 JSVersion version() const { return newVersion; }
170 #ifdef HAVE_VA_LIST_AS_ARRAY
171 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
172 #else
173 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
174 #endif
176 #ifdef JS_USE_JSID_STRUCT_TYPES
177 jsid JS_DEFAULT_XML_NAMESPACE_ID = { size_t(JSID_TYPE_DEFAULT_XML_NAMESPACE) };
178 jsid JSID_VOID = { size_t(JSID_TYPE_VOID) };
179 jsid JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) };
180 #endif
182 const jsval JSVAL_NULL = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL, 0));
183 const jsval JSVAL_ZERO = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_INT32, 0));
184 const jsval JSVAL_ONE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_INT32, 1));
185 const jsval JSVAL_FALSE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_FALSE));
186 const jsval JSVAL_TRUE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_TRUE));
187 const jsval JSVAL_VOID = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0));
189 /* Make sure that jschar is two bytes unsigned integer */
190 JS_STATIC_ASSERT((jschar)-1 > 0);
191 JS_STATIC_ASSERT(sizeof(jschar) == 2);
193 JS_PUBLIC_API(int64_t)
194 JS_Now()
196 return PRMJ_Now();
199 JS_PUBLIC_API(jsval)
200 JS_GetNaNValue(JSContext *cx)
202 return cx->runtime->NaNValue;
205 JS_PUBLIC_API(jsval)
206 JS_GetNegativeInfinityValue(JSContext *cx)
208 return cx->runtime->negativeInfinityValue;
211 JS_PUBLIC_API(jsval)
212 JS_GetPositiveInfinityValue(JSContext *cx)
214 return cx->runtime->positiveInfinityValue;
217 JS_PUBLIC_API(jsval)
218 JS_GetEmptyStringValue(JSContext *cx)
220 return STRING_TO_JSVAL(cx->runtime->emptyString);
223 JS_PUBLIC_API(JSString *)
224 JS_GetEmptyString(JSRuntime *rt)
226 JS_ASSERT(rt->hasContexts());
227 return rt->emptyString;
230 static JSBool
231 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, jsval **vpp, va_list *app)
233 const char *format;
234 JSArgumentFormatMap *map;
236 format = *formatp;
237 for (map = cx->argumentFormatMap; map; map = map->next) {
238 if (!strncmp(format, map->format, map->length)) {
239 *formatp = format + map->length;
240 return map->formatter(cx, format, fromJS, vpp, app);
243 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
244 return JS_FALSE;
247 static void
248 AssertNoGC(JSRuntime *rt)
250 JS_ASSERT(!rt->gcRunning);
253 static void
254 AssertNoGC(JSContext *cx)
256 AssertNoGC(cx->runtime);
259 static void
260 AssertNoGCOrFlatString(JSContext *cx, JSString *str)
263 * We allow some functions to be called during a GC as long as the argument
264 * is a flat string, since that will not cause allocation.
266 JS_ASSERT_IF(cx->runtime->gcRunning, str->isFlat());
269 JS_PUBLIC_API(JSBool)
270 JS_ConvertArguments(JSContext *cx, unsigned argc, jsval *argv, const char *format, ...)
272 va_list ap;
273 JSBool ok;
275 AssertNoGC(cx);
277 va_start(ap, format);
278 ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
279 va_end(ap);
280 return ok;
283 JS_PUBLIC_API(JSBool)
284 JS_ConvertArgumentsVA(JSContext *cx, unsigned argc, jsval *argv, const char *format, va_list ap)
286 jsval *sp;
287 JSBool required;
288 char c;
289 JSFunction *fun;
290 double d;
291 JSString *str;
292 JSObject *obj;
294 AssertNoGC(cx);
295 CHECK_REQUEST(cx);
296 assertSameCompartment(cx, JSValueArray(argv - 2, argc + 2));
297 sp = argv;
298 required = JS_TRUE;
299 while ((c = *format++) != '\0') {
300 if (isspace(c))
301 continue;
302 if (c == '/') {
303 required = JS_FALSE;
304 continue;
306 if (sp == argv + argc) {
307 if (required) {
308 fun = js_ValueToFunction(cx, &argv[-2], 0);
309 if (fun) {
310 char numBuf[12];
311 JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
312 JSAutoByteString funNameBytes;
313 if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
314 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
315 name, numBuf, (argc == 1) ? "" : "s");
318 return JS_FALSE;
320 break;
322 switch (c) {
323 case 'b':
324 *va_arg(ap, JSBool *) = js_ValueToBoolean(*sp);
325 break;
326 case 'c':
327 if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16_t *)))
328 return JS_FALSE;
329 break;
330 case 'i':
331 if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32_t *)))
332 return JS_FALSE;
333 break;
334 case 'u':
335 if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32_t *)))
336 return JS_FALSE;
337 break;
338 case 'j':
339 if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32_t *)))
340 return JS_FALSE;
341 break;
342 case 'd':
343 if (!JS_ValueToNumber(cx, *sp, va_arg(ap, double *)))
344 return JS_FALSE;
345 break;
346 case 'I':
347 if (!JS_ValueToNumber(cx, *sp, &d))
348 return JS_FALSE;
349 *va_arg(ap, double *) = ToInteger(d);
350 break;
351 case 'S':
352 case 'W':
353 str = ToString(cx, *sp);
354 if (!str)
355 return JS_FALSE;
356 *sp = STRING_TO_JSVAL(str);
357 if (c == 'W') {
358 JSFixedString *fixed = str->ensureFixed(cx);
359 if (!fixed)
360 return JS_FALSE;
361 *va_arg(ap, const jschar **) = fixed->chars();
362 } else {
363 *va_arg(ap, JSString **) = str;
365 break;
366 case 'o':
367 if (!js_ValueToObjectOrNull(cx, *sp, &obj))
368 return JS_FALSE;
369 *sp = OBJECT_TO_JSVAL(obj);
370 *va_arg(ap, JSObject **) = obj;
371 break;
372 case 'f':
373 obj = js_ValueToFunction(cx, sp, 0);
374 if (!obj)
375 return JS_FALSE;
376 *sp = OBJECT_TO_JSVAL(obj);
377 *va_arg(ap, JSFunction **) = obj->toFunction();
378 break;
379 case 'v':
380 *va_arg(ap, jsval *) = *sp;
381 break;
382 case '*':
383 break;
384 default:
385 format--;
386 if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
387 JS_ADDRESSOF_VA_LIST(ap))) {
388 return JS_FALSE;
390 /* NB: the formatter already updated sp, so we continue here. */
391 continue;
393 sp++;
395 return JS_TRUE;
398 JS_PUBLIC_API(JSBool)
399 JS_AddArgumentFormatter(JSContext *cx, const char *format, JSArgumentFormatter formatter)
401 size_t length;
402 JSArgumentFormatMap **mpp, *map;
404 length = strlen(format);
405 mpp = &cx->argumentFormatMap;
406 while ((map = *mpp) != NULL) {
407 /* Insert before any shorter string to match before prefixes. */
408 if (map->length < length)
409 break;
410 if (map->length == length && !strcmp(map->format, format))
411 goto out;
412 mpp = &map->next;
414 map = (JSArgumentFormatMap *) cx->malloc_(sizeof *map);
415 if (!map)
416 return JS_FALSE;
417 map->format = format;
418 map->length = length;
419 map->next = *mpp;
420 *mpp = map;
421 out:
422 map->formatter = formatter;
423 return JS_TRUE;
426 JS_PUBLIC_API(void)
427 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
429 size_t length;
430 JSArgumentFormatMap **mpp, *map;
432 length = strlen(format);
433 mpp = &cx->argumentFormatMap;
434 while ((map = *mpp) != NULL) {
435 if (map->length == length && !strcmp(map->format, format)) {
436 *mpp = map->next;
437 cx->free_(map);
438 return;
440 mpp = &map->next;
444 JS_PUBLIC_API(JSBool)
445 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
447 JSBool ok;
448 JSObject *obj;
449 JSString *str;
450 double d;
452 AssertNoGC(cx);
453 CHECK_REQUEST(cx);
454 assertSameCompartment(cx, v);
455 switch (type) {
456 case JSTYPE_VOID:
457 *vp = JSVAL_VOID;
458 ok = JS_TRUE;
459 break;
460 case JSTYPE_OBJECT:
461 ok = js_ValueToObjectOrNull(cx, v, &obj);
462 if (ok)
463 *vp = OBJECT_TO_JSVAL(obj);
464 break;
465 case JSTYPE_FUNCTION:
466 *vp = v;
467 obj = js_ValueToFunction(cx, vp, JSV2F_SEARCH_STACK);
468 ok = (obj != NULL);
469 break;
470 case JSTYPE_STRING:
471 str = ToString(cx, v);
472 ok = (str != NULL);
473 if (ok)
474 *vp = STRING_TO_JSVAL(str);
475 break;
476 case JSTYPE_NUMBER:
477 ok = JS_ValueToNumber(cx, v, &d);
478 if (ok)
479 *vp = DOUBLE_TO_JSVAL(d);
480 break;
481 case JSTYPE_BOOLEAN:
482 *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(v));
483 return JS_TRUE;
484 default: {
485 char numBuf[12];
486 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
487 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE, numBuf);
488 ok = JS_FALSE;
489 break;
492 return ok;
495 JS_PUBLIC_API(JSBool)
496 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
498 AssertNoGC(cx);
499 CHECK_REQUEST(cx);
500 assertSameCompartment(cx, v);
501 return js_ValueToObjectOrNull(cx, v, objp);
504 JS_PUBLIC_API(JSFunction *)
505 JS_ValueToFunction(JSContext *cx, jsval v)
507 AssertNoGC(cx);
508 CHECK_REQUEST(cx);
509 assertSameCompartment(cx, v);
510 return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
513 JS_PUBLIC_API(JSFunction *)
514 JS_ValueToConstructor(JSContext *cx, jsval v)
516 AssertNoGC(cx);
517 CHECK_REQUEST(cx);
518 assertSameCompartment(cx, v);
519 return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
522 JS_PUBLIC_API(JSString *)
523 JS_ValueToString(JSContext *cx, jsval v)
525 AssertNoGC(cx);
526 CHECK_REQUEST(cx);
527 assertSameCompartment(cx, v);
528 return ToString(cx, v);
531 JS_PUBLIC_API(JSString *)
532 JS_ValueToSource(JSContext *cx, jsval v)
534 AssertNoGC(cx);
535 CHECK_REQUEST(cx);
536 assertSameCompartment(cx, v);
537 return js_ValueToSource(cx, v);
540 JS_PUBLIC_API(JSBool)
541 JS_ValueToNumber(JSContext *cx, jsval v, double *dp)
543 AssertNoGC(cx);
544 CHECK_REQUEST(cx);
545 assertSameCompartment(cx, v);
547 return ToNumber(cx, v, dp);
550 JS_PUBLIC_API(JSBool)
551 JS_DoubleIsInt32(double d, int32_t *ip)
553 return MOZ_DOUBLE_IS_INT32(d, ip);
556 JS_PUBLIC_API(int32_t)
557 JS_DoubleToInt32(double d)
559 return ToInt32(d);
562 JS_PUBLIC_API(uint32_t)
563 JS_DoubleToUint32(double d)
565 return ToUint32(d);
568 JS_PUBLIC_API(JSBool)
569 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32_t *ip)
571 AssertNoGC(cx);
572 CHECK_REQUEST(cx);
573 assertSameCompartment(cx, v);
575 RootedVarValue value(cx, v);
576 return ToInt32(cx, value, ip);
579 JS_PUBLIC_API(JSBool)
580 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32_t *ip)
582 AssertNoGC(cx);
583 CHECK_REQUEST(cx);
584 assertSameCompartment(cx, v);
586 return ToUint32(cx, v, (uint32_t *)ip);
589 JS_PUBLIC_API(JSBool)
590 JS_ValueToInt32(JSContext *cx, jsval v, int32_t *ip)
592 AssertNoGC(cx);
593 CHECK_REQUEST(cx);
594 assertSameCompartment(cx, v);
596 return NonstandardToInt32(cx, v, (int32_t *)ip);
599 JS_PUBLIC_API(JSBool)
600 JS_ValueToUint16(JSContext *cx, jsval v, uint16_t *ip)
602 AssertNoGC(cx);
603 CHECK_REQUEST(cx);
604 assertSameCompartment(cx, v);
606 return ValueToUint16(cx, v, (uint16_t *)ip);
609 JS_PUBLIC_API(JSBool)
610 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
612 AssertNoGC(cx);
613 CHECK_REQUEST(cx);
614 assertSameCompartment(cx, v);
615 *bp = js_ValueToBoolean(v);
616 return JS_TRUE;
619 JS_PUBLIC_API(JSType)
620 JS_TypeOfValue(JSContext *cx, jsval v)
622 AssertNoGC(cx);
623 CHECK_REQUEST(cx);
624 assertSameCompartment(cx, v);
625 return TypeOfValue(cx, v);
628 JS_PUBLIC_API(const char *)
629 JS_GetTypeName(JSContext *cx, JSType type)
631 if ((unsigned)type >= (unsigned)JSTYPE_LIMIT)
632 return NULL;
633 return JS_TYPE_STR(type);
636 JS_PUBLIC_API(JSBool)
637 JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
639 AssertNoGC(cx);
640 CHECK_REQUEST(cx);
641 assertSameCompartment(cx, v1, v2);
642 bool eq;
643 if (!StrictlyEqual(cx, v1, v2, &eq))
644 return false;
645 *equal = eq;
646 return true;
649 JS_PUBLIC_API(JSBool)
650 JS_LooselyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
652 AssertNoGC(cx);
653 CHECK_REQUEST(cx);
654 assertSameCompartment(cx, v1, v2);
655 bool eq;
656 if (!LooselyEqual(cx, v1, v2, &eq))
657 return false;
658 *equal = eq;
659 return true;
662 JS_PUBLIC_API(JSBool)
663 JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same)
665 AssertNoGC(cx);
666 CHECK_REQUEST(cx);
667 assertSameCompartment(cx, v1, v2);
668 bool s;
669 if (!SameValue(cx, v1, v2, &s))
670 return false;
671 *same = s;
672 return true;
675 JS_PUBLIC_API(JSBool)
676 JS_IsBuiltinEvalFunction(JSFunction *fun)
678 return IsAnyBuiltinEval(fun);
681 JS_PUBLIC_API(JSBool)
682 JS_IsBuiltinFunctionConstructor(JSFunction *fun)
684 return IsBuiltinFunctionConstructor(fun);
687 /************************************************************************/
690 * Has a new runtime ever been created? This flag is used to detect unsafe
691 * changes to js_CStringsAreUTF8 after a runtime has been created, and to
692 * control things that should happen only once across all runtimes.
694 static JSBool js_NewRuntimeWasCalled = JS_FALSE;
696 static const JSSecurityCallbacks NullSecurityCallbacks = { };
698 JSRuntime::JSRuntime()
699 : atomsCompartment(NULL),
700 #ifdef JS_THREADSAFE
701 ownerThread_(NULL),
702 #endif
703 tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
704 execAlloc_(NULL),
705 bumpAlloc_(NULL),
706 #ifdef JS_METHODJIT
707 jaegerRuntime_(NULL),
708 #endif
709 nativeStackBase(0),
710 nativeStackQuota(0),
711 interpreterFrames(NULL),
712 cxCallback(NULL),
713 destroyCompartmentCallback(NULL),
714 activityCallback(NULL),
715 activityCallbackArg(NULL),
716 #ifdef JS_THREADSAFE
717 suspendCount(0),
718 requestDepth(0),
719 # ifdef DEBUG
720 checkRequestDepth(0),
721 # endif
722 #endif
723 gcSystemAvailableChunkListHead(NULL),
724 gcUserAvailableChunkListHead(NULL),
725 gcKeepAtoms(0),
726 gcBytes(0),
727 gcMaxBytes(0),
728 gcMaxMallocBytes(0),
729 gcNumArenasFreeCommitted(0),
730 gcVerifyData(NULL),
731 gcChunkAllocationSinceLastGC(false),
732 gcNextFullGCTime(0),
733 gcJitReleaseTime(0),
734 gcMode(JSGC_MODE_GLOBAL),
735 gcIsNeeded(0),
736 gcWeakMapList(NULL),
737 gcStats(thisFromCtor()),
738 gcNumber(0),
739 gcStartNumber(0),
740 gcIsFull(false),
741 gcTriggerReason(gcreason::NO_REASON),
742 gcStrictCompartmentChecking(false),
743 gcIncrementalState(gc::NO_INCREMENTAL),
744 gcLastMarkSlice(false),
745 gcInterFrameGC(0),
746 gcSliceBudget(SliceBudget::Unlimited),
747 gcIncrementalEnabled(true),
748 gcExactScanningEnabled(true),
749 gcPoke(false),
750 gcRunning(false),
751 #ifdef JS_GC_ZEAL
752 gcZeal_(0),
753 gcZealFrequency(0),
754 gcNextScheduled(0),
755 gcDeterministicOnly(false),
756 #endif
757 gcCallback(NULL),
758 gcSliceCallback(NULL),
759 gcFinalizeCallback(NULL),
760 gcBlackRootsTraceOp(NULL),
761 gcBlackRootsData(NULL),
762 gcGrayRootsTraceOp(NULL),
763 gcGrayRootsData(NULL),
764 autoGCRooters(NULL),
765 scriptAndCountsVector(NULL),
766 NaNValue(UndefinedValue()),
767 negativeInfinityValue(UndefinedValue()),
768 positiveInfinityValue(UndefinedValue()),
769 emptyString(NULL),
770 debugMode(false),
771 profilingScripts(false),
772 alwaysPreserveCode(false),
773 hadOutOfMemory(false),
774 data(NULL),
775 #ifdef JS_THREADSAFE
776 gcLock(NULL),
777 gcHelperThread(thisFromCtor()),
778 #endif
779 defaultFreeOp_(thisFromCtor(), false, false),
780 debuggerMutations(0),
781 securityCallbacks(const_cast<JSSecurityCallbacks *>(&NullSecurityCallbacks)),
782 destroyPrincipals(NULL),
783 structuredCloneCallbacks(NULL),
784 telemetryCallback(NULL),
785 propertyRemovals(0),
786 thousandsSeparator(0),
787 decimalSeparator(0),
788 numGrouping(0),
789 waiveGCQuota(false),
790 mathCache_(NULL),
791 dtoaState(NULL),
792 pendingProxyOperation(NULL),
793 trustedPrincipals_(NULL),
794 wrapObjectCallback(TransparentObjectWrapper),
795 preWrapObjectCallback(NULL),
796 preserveWrapperCallback(NULL),
797 #ifdef DEBUG
798 noGCOrAllocationCheck(0),
799 #endif
800 inOOMReport(0),
801 jitHardening(false)
803 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
804 JS_INIT_CLIST(&contextList);
805 JS_INIT_CLIST(&debuggerList);
807 PodZero(&debugHooks);
808 PodZero(&atomState);
810 #if JS_STACK_GROWTH_DIRECTION > 0
811 nativeStackLimit = UINTPTR_MAX;
812 #endif
815 bool
816 JSRuntime::init(uint32_t maxbytes)
818 #ifdef JS_THREADSAFE
819 ownerThread_ = PR_GetCurrentThread();
820 #endif
822 #ifdef JS_METHODJIT_SPEW
823 JMCheckLogging();
824 #endif
826 if (!js_InitGC(this, maxbytes))
827 return false;
829 if (!gcMarker.init())
830 return false;
832 const char *size = getenv("JSGC_MARK_STACK_LIMIT");
833 if (size)
834 SetMarkStackLimit(this, atoi(size));
836 if (!(atomsCompartment = this->new_<JSCompartment>(this)) ||
837 !atomsCompartment->init(NULL) ||
838 !compartments.append(atomsCompartment)) {
839 Foreground::delete_(atomsCompartment);
840 return false;
843 atomsCompartment->isSystemCompartment = true;
844 atomsCompartment->setGCLastBytes(8192, 8192, GC_NORMAL);
846 if (!js_InitAtomState(this))
847 return false;
849 if (!InitRuntimeNumberState(this))
850 return false;
852 dtoaState = js_NewDtoaState();
853 if (!dtoaState)
854 return false;
856 if (!stackSpace.init())
857 return false;
859 if (!scriptFilenameTable.init())
860 return false;
862 nativeStackBase = GetNativeStackBase();
863 return true;
866 JSRuntime::~JSRuntime()
869 * Even though all objects in the compartment are dead, we may have keep
870 * some filenames around because of gcKeepAtoms.
872 FreeScriptFilenames(this);
874 JS_ASSERT(onOwnerThread());
876 #ifdef DEBUG
877 /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
878 if (!JS_CLIST_IS_EMPTY(&contextList)) {
879 unsigned cxcount = 0;
880 for (ContextIter acx(this); !acx.done(); acx.next()) {
881 fprintf(stderr,
882 "JS API usage error: found live context at %p\n",
883 (void *) acx.get());
884 cxcount++;
886 fprintf(stderr,
887 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
888 cxcount, (cxcount == 1) ? "" : "s");
890 #endif
892 FinishRuntimeNumberState(this);
893 js_FinishAtomState(this);
895 if (dtoaState)
896 js_DestroyDtoaState(dtoaState);
898 js_FinishGC(this);
899 #ifdef JS_THREADSAFE
900 if (gcLock)
901 PR_DestroyLock(gcLock);
902 #endif
904 delete_(bumpAlloc_);
905 delete_(mathCache_);
906 #ifdef JS_METHODJIT
907 delete_(jaegerRuntime_);
908 #endif
909 delete_(execAlloc_); /* Delete after jaegerRuntime_. */
912 #ifdef JS_THREADSAFE
913 void
914 JSRuntime::setOwnerThread()
916 JS_ASSERT(ownerThread_ == (void *)0xc1ea12); /* "clear" */
917 JS_ASSERT(requestDepth == 0);
918 ownerThread_ = PR_GetCurrentThread();
919 nativeStackBase = GetNativeStackBase();
920 if (nativeStackQuota)
921 JS_SetNativeStackQuota(this, nativeStackQuota);
924 void
925 JSRuntime::clearOwnerThread()
927 JS_ASSERT(onOwnerThread());
928 JS_ASSERT(requestDepth == 0);
929 ownerThread_ = (void *)0xc1ea12; /* "clear" */
930 nativeStackBase = 0;
931 #if JS_STACK_GROWTH_DIRECTION > 0
932 nativeStackLimit = UINTPTR_MAX;
933 #else
934 nativeStackLimit = 0;
935 #endif
938 JS_FRIEND_API(bool)
939 JSRuntime::onOwnerThread() const
941 return ownerThread_ == PR_GetCurrentThread();
943 #endif /* JS_THREADSAFE */
945 JS_PUBLIC_API(JSRuntime *)
946 JS_NewRuntime(uint32_t maxbytes)
948 if (!js_NewRuntimeWasCalled) {
949 #ifdef DEBUG
951 * This code asserts that the numbers associated with the error names
952 * in jsmsg.def are monotonically increasing. It uses values for the
953 * error names enumerated in jscntxt.c. It's not a compile-time check
954 * but it's better than nothing.
956 int errorNumber = 0;
957 #define MSG_DEF(name, number, count, exception, format) \
958 JS_ASSERT(name == errorNumber++);
959 #include "js.msg"
960 #undef MSG_DEF
962 #define MSG_DEF(name, number, count, exception, format) \
963 JS_BEGIN_MACRO \
964 unsigned numfmtspecs = 0; \
965 const char *fmt; \
966 for (fmt = format; *fmt != '\0'; fmt++) { \
967 if (*fmt == '{' && isdigit(fmt[1])) \
968 ++numfmtspecs; \
970 JS_ASSERT(count == numfmtspecs); \
971 JS_END_MACRO;
972 #include "js.msg"
973 #undef MSG_DEF
974 #endif /* DEBUG */
976 InitMemorySubsystem();
978 js_NewRuntimeWasCalled = JS_TRUE;
981 JSRuntime *rt = OffTheBooks::new_<JSRuntime>();
982 if (!rt)
983 return NULL;
985 if (!rt->init(maxbytes)) {
986 JS_DestroyRuntime(rt);
987 return NULL;
990 Probes::createRuntime(rt);
991 return rt;
994 JS_PUBLIC_API(void)
995 JS_DestroyRuntime(JSRuntime *rt)
997 Probes::destroyRuntime(rt);
998 Foreground::delete_(rt);
1001 JS_PUBLIC_API(void)
1002 JS_ShutDown(void)
1004 Probes::shutdown();
1005 PRMJ_NowShutdown();
1008 JS_PUBLIC_API(void *)
1009 JS_GetRuntimePrivate(JSRuntime *rt)
1011 return rt->data;
1014 JS_PUBLIC_API(void)
1015 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
1017 rt->data = data;
1020 #ifdef JS_THREADSAFE
1021 static void
1022 StartRequest(JSContext *cx)
1024 JSRuntime *rt = cx->runtime;
1025 JS_ASSERT(rt->onOwnerThread());
1027 if (rt->requestDepth) {
1028 rt->requestDepth++;
1029 } else {
1030 /* Indicate that a request is running. */
1031 rt->requestDepth = 1;
1033 if (rt->activityCallback)
1034 rt->activityCallback(rt->activityCallbackArg, true);
1038 static void
1039 StopRequest(JSContext *cx)
1041 JSRuntime *rt = cx->runtime;
1042 JS_ASSERT(rt->onOwnerThread());
1043 JS_ASSERT(rt->requestDepth != 0);
1044 if (rt->requestDepth != 1) {
1045 rt->requestDepth--;
1046 } else {
1047 rt->conservativeGC.updateForRequestEnd(rt->suspendCount);
1048 rt->requestDepth = 0;
1050 if (rt->activityCallback)
1051 rt->activityCallback(rt->activityCallbackArg, false);
1054 #endif /* JS_THREADSAFE */
1056 JS_PUBLIC_API(void)
1057 JS_BeginRequest(JSContext *cx)
1059 #ifdef JS_THREADSAFE
1060 cx->outstandingRequests++;
1061 StartRequest(cx);
1062 #endif
1065 JS_PUBLIC_API(void)
1066 JS_EndRequest(JSContext *cx)
1068 #ifdef JS_THREADSAFE
1069 JS_ASSERT(cx->outstandingRequests != 0);
1070 cx->outstandingRequests--;
1071 StopRequest(cx);
1072 #endif
1075 /* Yield to pending GC operations, regardless of request depth */
1076 JS_PUBLIC_API(void)
1077 JS_YieldRequest(JSContext *cx)
1079 #ifdef JS_THREADSAFE
1080 CHECK_REQUEST(cx);
1081 JS_ResumeRequest(cx, JS_SuspendRequest(cx));
1082 #endif
1085 JS_PUBLIC_API(unsigned)
1086 JS_SuspendRequest(JSContext *cx)
1088 #ifdef JS_THREADSAFE
1089 JSRuntime *rt = cx->runtime;
1090 JS_ASSERT(rt->onOwnerThread());
1092 unsigned saveDepth = rt->requestDepth;
1093 if (!saveDepth)
1094 return 0;
1096 rt->suspendCount++;
1097 rt->requestDepth = 1;
1098 StopRequest(cx);
1099 return saveDepth;
1100 #else
1101 return 0;
1102 #endif
1105 JS_PUBLIC_API(void)
1106 JS_ResumeRequest(JSContext *cx, unsigned saveDepth)
1108 #ifdef JS_THREADSAFE
1109 JSRuntime *rt = cx->runtime;
1110 JS_ASSERT(rt->onOwnerThread());
1111 if (saveDepth == 0)
1112 return;
1113 JS_ASSERT(saveDepth >= 1);
1114 JS_ASSERT(!rt->requestDepth);
1115 JS_ASSERT(rt->suspendCount);
1116 StartRequest(cx);
1117 rt->requestDepth = saveDepth;
1118 rt->suspendCount--;
1119 #endif
1122 JS_PUBLIC_API(JSBool)
1123 JS_IsInRequest(JSRuntime *rt)
1125 #ifdef JS_THREADSAFE
1126 JS_ASSERT(rt->onOwnerThread());
1127 return rt->requestDepth != 0;
1128 #else
1129 return false;
1130 #endif
1133 JS_PUBLIC_API(JSBool)
1134 JS_IsInSuspendedRequest(JSRuntime *rt)
1136 #ifdef JS_THREADSAFE
1137 JS_ASSERT(rt->onOwnerThread());
1138 return rt->suspendCount != 0;
1139 #else
1140 return false;
1141 #endif
1144 JS_PUBLIC_API(JSContextCallback)
1145 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
1147 JSContextCallback old;
1149 old = rt->cxCallback;
1150 rt->cxCallback = cxCallback;
1151 return old;
1154 JS_PUBLIC_API(JSContext *)
1155 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
1157 return NewContext(rt, stackChunkSize);
1160 JS_PUBLIC_API(void)
1161 JS_DestroyContext(JSContext *cx)
1163 DestroyContext(cx, DCM_FORCE_GC);
1166 JS_PUBLIC_API(void)
1167 JS_DestroyContextNoGC(JSContext *cx)
1169 DestroyContext(cx, DCM_NO_GC);
1172 JS_PUBLIC_API(void *)
1173 JS_GetContextPrivate(JSContext *cx)
1175 return cx->data;
1178 JS_PUBLIC_API(void)
1179 JS_SetContextPrivate(JSContext *cx, void *data)
1181 cx->data = data;
1184 JS_PUBLIC_API(void *)
1185 JS_GetSecondContextPrivate(JSContext *cx)
1187 return cx->data2;
1190 JS_PUBLIC_API(void)
1191 JS_SetSecondContextPrivate(JSContext *cx, void *data)
1193 cx->data2 = data;
1196 JS_PUBLIC_API(JSRuntime *)
1197 JS_GetRuntime(JSContext *cx)
1199 return cx->runtime;
1202 JS_PUBLIC_API(JSContext *)
1203 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
1205 JSContext *cx = *iterp;
1206 JSCList *next = cx ? cx->link.next : rt->contextList.next;
1207 cx = (next == &rt->contextList) ? NULL : JSContext::fromLinkField(next);
1208 *iterp = cx;
1209 return cx;
1212 JS_PUBLIC_API(JSVersion)
1213 JS_GetVersion(JSContext *cx)
1215 return VersionNumber(cx->findVersion());
1218 JS_PUBLIC_API(JSVersion)
1219 JS_SetVersion(JSContext *cx, JSVersion newVersion)
1221 JS_ASSERT(VersionIsKnown(newVersion));
1222 JS_ASSERT(!VersionHasFlags(newVersion));
1223 JSVersion newVersionNumber = newVersion;
1225 #ifdef DEBUG
1226 unsigned coptsBefore = cx->getCompileOptions();
1227 #endif
1228 JSVersion oldVersion = cx->findVersion();
1229 JSVersion oldVersionNumber = VersionNumber(oldVersion);
1230 if (oldVersionNumber == newVersionNumber)
1231 return oldVersionNumber; /* No override actually occurs! */
1233 /* We no longer support 1.4 or below. */
1234 if (newVersionNumber != JSVERSION_DEFAULT && newVersionNumber <= JSVERSION_1_4)
1235 return oldVersionNumber;
1237 VersionCopyFlags(&newVersion, oldVersion);
1238 cx->maybeOverrideVersion(newVersion);
1239 JS_ASSERT(cx->getCompileOptions() == coptsBefore);
1240 return oldVersionNumber;
1243 static struct v2smap {
1244 JSVersion version;
1245 const char *string;
1246 } v2smap[] = {
1247 {JSVERSION_1_0, "1.0"},
1248 {JSVERSION_1_1, "1.1"},
1249 {JSVERSION_1_2, "1.2"},
1250 {JSVERSION_1_3, "1.3"},
1251 {JSVERSION_1_4, "1.4"},
1252 {JSVERSION_ECMA_3, "ECMAv3"},
1253 {JSVERSION_1_5, "1.5"},
1254 {JSVERSION_1_6, "1.6"},
1255 {JSVERSION_1_7, "1.7"},
1256 {JSVERSION_1_8, "1.8"},
1257 {JSVERSION_ECMA_5, "ECMAv5"},
1258 {JSVERSION_DEFAULT, js_default_str},
1259 {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
1262 JS_PUBLIC_API(const char *)
1263 JS_VersionToString(JSVersion version)
1265 int i;
1267 for (i = 0; v2smap[i].string; i++)
1268 if (v2smap[i].version == version)
1269 return v2smap[i].string;
1270 return "unknown";
1273 JS_PUBLIC_API(JSVersion)
1274 JS_StringToVersion(const char *string)
1276 int i;
1278 for (i = 0; v2smap[i].string; i++)
1279 if (strcmp(v2smap[i].string, string) == 0)
1280 return v2smap[i].version;
1281 return JSVERSION_UNKNOWN;
1284 JS_PUBLIC_API(uint32_t)
1285 JS_GetOptions(JSContext *cx)
1288 * Can't check option/version synchronization here.
1289 * We may have been synchronized with a script version that was formerly on
1290 * the stack, but has now been popped.
1292 return cx->allOptions();
1295 static unsigned
1296 SetOptionsCommon(JSContext *cx, unsigned options)
1298 JS_ASSERT((options & JSALLOPTION_MASK) == options);
1299 unsigned oldopts = cx->allOptions();
1300 unsigned newropts = options & JSRUNOPTION_MASK;
1301 unsigned newcopts = options & JSCOMPILEOPTION_MASK;
1302 cx->setRunOptions(newropts);
1303 cx->setCompileOptions(newcopts);
1304 cx->updateJITEnabled();
1305 return oldopts;
1308 JS_PUBLIC_API(uint32_t)
1309 JS_SetOptions(JSContext *cx, uint32_t options)
1311 return SetOptionsCommon(cx, options);
1314 JS_PUBLIC_API(uint32_t)
1315 JS_ToggleOptions(JSContext *cx, uint32_t options)
1317 unsigned oldopts = cx->allOptions();
1318 unsigned newopts = oldopts ^ options;
1319 return SetOptionsCommon(cx, newopts);
1322 JS_PUBLIC_API(void)
1323 JS_SetJitHardening(JSRuntime *rt, JSBool enabled)
1325 rt->setJitHardening(!!enabled);
1328 JS_PUBLIC_API(const char *)
1329 JS_GetImplementationVersion(void)
1331 return "JavaScript-C 1.8.5+ 2011-04-16";
1334 JS_PUBLIC_API(void)
1335 JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback callback)
1337 rt->destroyCompartmentCallback = callback;
1340 JS_PUBLIC_API(JSWrapObjectCallback)
1341 JS_SetWrapObjectCallbacks(JSRuntime *rt,
1342 JSWrapObjectCallback callback,
1343 JSPreWrapCallback precallback)
1345 JSWrapObjectCallback old = rt->wrapObjectCallback;
1346 rt->wrapObjectCallback = callback;
1347 rt->preWrapObjectCallback = precallback;
1348 return old;
1351 JS_PUBLIC_API(JSCrossCompartmentCall *)
1352 JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
1354 AssertNoGC(cx);
1355 CHECK_REQUEST(cx);
1357 JS_ASSERT(target);
1358 AutoCompartment *call = cx->new_<AutoCompartment>(cx, target);
1359 if (!call)
1360 return NULL;
1361 if (!call->enter()) {
1362 Foreground::delete_(call);
1363 return NULL;
1365 return reinterpret_cast<JSCrossCompartmentCall *>(call);
1368 namespace js {
1370 // Declared in jscompartment.h
1371 Class dummy_class = {
1372 "jdummy",
1373 JSCLASS_GLOBAL_FLAGS,
1374 JS_PropertyStub, JS_PropertyStub,
1375 JS_PropertyStub, JS_StrictPropertyStub,
1376 JS_EnumerateStub, JS_ResolveStub,
1377 JS_ConvertStub
1380 } /*namespace js */
1382 JS_PUBLIC_API(JSCrossCompartmentCall *)
1383 JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
1385 AssertNoGC(cx);
1386 CHECK_REQUEST(cx);
1387 JS_ASSERT(!target->isCachedEval);
1388 GlobalObject *global = target->globalObject;
1389 if (!global) {
1390 SwitchToCompartment sc(cx, target->compartment());
1391 global = GlobalObject::create(cx, &dummy_class);
1392 if (!global)
1393 return NULL;
1395 return JS_EnterCrossCompartmentCall(cx, global);
1398 JS_PUBLIC_API(JSCrossCompartmentCall *)
1399 JS_EnterCrossCompartmentCallStackFrame(JSContext *cx, JSStackFrame *target)
1401 AssertNoGC(cx);
1402 CHECK_REQUEST(cx);
1404 return JS_EnterCrossCompartmentCall(cx, &Valueify(target)->global());
1407 JS_PUBLIC_API(void)
1408 JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
1410 AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
1411 AssertNoGC(realcall->context);
1412 CHECK_REQUEST(realcall->context);
1413 realcall->leave();
1414 Foreground::delete_(realcall);
1417 bool
1418 JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target)
1420 AssertNoGC(cx);
1421 JS_ASSERT(state == STATE_UNENTERED);
1422 if (cx->compartment == target->compartment()) {
1423 state = STATE_SAME_COMPARTMENT;
1424 return true;
1427 JS_STATIC_ASSERT(sizeof(bytes) == sizeof(AutoCompartment));
1428 CHECK_REQUEST(cx);
1429 AutoCompartment *call = new (bytes) AutoCompartment(cx, target);
1430 if (call->enter()) {
1431 state = STATE_OTHER_COMPARTMENT;
1432 return true;
1434 return false;
1437 void
1438 JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target)
1440 (void) enter(cx, target);
1443 JSAutoEnterCompartment::~JSAutoEnterCompartment()
1445 if (state == STATE_OTHER_COMPARTMENT) {
1446 AutoCompartment* ac = getAutoCompartment();
1447 CHECK_REQUEST(ac->context);
1448 ac->~AutoCompartment();
1452 namespace JS {
1454 bool
1455 AutoEnterScriptCompartment::enter(JSContext *cx, JSScript *target)
1457 JS_ASSERT(!call);
1458 if (cx->compartment == target->compartment()) {
1459 call = reinterpret_cast<JSCrossCompartmentCall*>(1);
1460 return true;
1462 call = JS_EnterCrossCompartmentCallScript(cx, target);
1463 return call != NULL;
1466 bool
1467 AutoEnterFrameCompartment::enter(JSContext *cx, JSStackFrame *target)
1469 JS_ASSERT(!call);
1470 if (cx->compartment == Valueify(target)->scopeChain()->compartment()) {
1471 call = reinterpret_cast<JSCrossCompartmentCall*>(1);
1472 return true;
1474 call = JS_EnterCrossCompartmentCallStackFrame(cx, target);
1475 return call != NULL;
1478 } /* namespace JS */
1480 JS_PUBLIC_API(void)
1481 JS_SetCompartmentPrivate(JSCompartment *compartment, void *data)
1483 compartment->data = data;
1486 JS_PUBLIC_API(void *)
1487 JS_GetCompartmentPrivate(JSCompartment *compartment)
1489 return compartment->data;
1492 JS_PUBLIC_API(JSBool)
1493 JS_WrapObject(JSContext *cx, JSObject **objp)
1495 AssertNoGC(cx);
1496 CHECK_REQUEST(cx);
1497 return cx->compartment->wrap(cx, objp);
1500 JS_PUBLIC_API(JSBool)
1501 JS_WrapValue(JSContext *cx, jsval *vp)
1503 AssertNoGC(cx);
1504 CHECK_REQUEST(cx);
1505 return cx->compartment->wrap(cx, vp);
1508 JS_PUBLIC_API(JSObject *)
1509 JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target)
1511 AssertNoGC(cx);
1513 // This function is called when an object moves between two
1514 // different compartments. In that case, we need to "move" the
1515 // window from origobj's compartment to target's compartment.
1516 JSCompartment *destination = target->compartment();
1517 WrapperMap &map = destination->crossCompartmentWrappers;
1518 Value origv = ObjectValue(*origobj);
1519 JSObject *obj;
1521 if (origobj->compartment() == destination) {
1522 // If the original object is in the same compartment as the
1523 // destination, then we know that we won't find wrapper in the
1524 // destination's cross compartment map and that the same
1525 // object will continue to work. Note the rare case where
1526 // |origobj == target|. In that case, we can just treat this
1527 // as a same compartment navigation. The effect is to clear
1528 // all of the wrappers and their holders if they have
1529 // them. This would be cleaner as a separate API.
1530 if (origobj != target && !origobj->swap(cx, target))
1531 return NULL;
1532 obj = origobj;
1533 } else if (WrapperMap::Ptr p = map.lookup(origv)) {
1534 // There might already be a wrapper for the original object in
1535 // the new compartment. If there is, make it the primary outer
1536 // window proxy around the inner (accomplished by swapping
1537 // target's innards with the old, possibly security wrapper,
1538 // innards).
1539 obj = &p->value.toObject();
1540 map.remove(p);
1541 if (!obj->swap(cx, target))
1542 return NULL;
1543 } else {
1544 // Otherwise, this is going to be our outer window proxy in
1545 // the new compartment.
1546 obj = target;
1549 // Now, iterate through other scopes looking for references to the
1550 // old outer window. They need to be updated to point at the new
1551 // outer window. They also might transition between different
1552 // types of security wrappers based on whether the new compartment
1553 // is same origin with them.
1554 Value targetv = ObjectValue(*obj);
1555 CompartmentVector &vector = cx->runtime->compartments;
1556 AutoValueVector toTransplant(cx);
1557 if (!toTransplant.reserve(vector.length()))
1558 return NULL;
1560 for (JSCompartment **p = vector.begin(), **end = vector.end(); p != end; ++p) {
1561 WrapperMap &pmap = (*p)->crossCompartmentWrappers;
1562 if (WrapperMap::Ptr wp = pmap.lookup(origv)) {
1563 // We found a wrapper. Remember and root it.
1564 toTransplant.infallibleAppend(wp->value);
1568 for (Value *begin = toTransplant.begin(), *end = toTransplant.end(); begin != end; ++begin) {
1569 JSObject *wobj = &begin->toObject();
1570 JSCompartment *wcompartment = wobj->compartment();
1571 WrapperMap &pmap = wcompartment->crossCompartmentWrappers;
1572 JS_ASSERT(pmap.lookup(origv));
1573 pmap.remove(origv);
1575 // First, we wrap it in the new compartment. This will return
1576 // a new wrapper.
1577 AutoCompartment ac(cx, wobj);
1578 JSObject *tobj = obj;
1579 if (!ac.enter() || !wcompartment->wrap(cx, &tobj))
1580 return NULL;
1582 // Now, because we need to maintain object identity, we do a
1583 // brain transplant on the old object. At the same time, we
1584 // update the entry in the compartment's wrapper map to point
1585 // to the old wrapper.
1586 JS_ASSERT(tobj != wobj);
1587 if (!wobj->swap(cx, tobj))
1588 return NULL;
1589 pmap.put(targetv, ObjectValue(*wobj));
1592 // Lastly, update the original object to point to the new one.
1593 if (origobj->compartment() != destination) {
1594 AutoCompartment ac(cx, origobj);
1595 JSObject *tobj = obj;
1596 if (!ac.enter() || !JS_WrapObject(cx, &tobj))
1597 return NULL;
1598 if (!origobj->swap(cx, tobj))
1599 return NULL;
1600 origobj->compartment()->crossCompartmentWrappers.put(targetv, origv);
1603 return obj;
1607 * The location object is special. There is the location object itself and
1608 * then the location object wrapper. Because there are no direct references to
1609 * the location object itself, we don't want the old obj (|origobj| here) to
1610 * become the new wrapper but the wrapper itself instead. This leads to very
1611 * subtle differences between js_TransplantObjectWithWrapper and
1612 * JS_TransplantObject.
1614 JS_FRIEND_API(JSObject *)
1615 js_TransplantObjectWithWrapper(JSContext *cx,
1616 JSObject *origobj,
1617 JSObject *origwrapper,
1618 JSObject *targetobj,
1619 JSObject *targetwrapper)
1621 AssertNoGC(cx);
1623 JSObject *obj;
1624 JSCompartment *destination = targetobj->compartment();
1625 WrapperMap &map = destination->crossCompartmentWrappers;
1627 // |origv| is the map entry we're looking up. The map entries are going to
1628 // be for the location object itself.
1629 Value origv = ObjectValue(*origobj);
1631 // There might already be a wrapper for the original object in the new
1632 // compartment.
1633 if (WrapperMap::Ptr p = map.lookup(origv)) {
1634 // There is. Make the existing wrapper a same compartment location
1635 // wrapper (swapping it with the given new wrapper).
1636 obj = &p->value.toObject();
1637 map.remove(p);
1638 if (!obj->swap(cx, targetwrapper))
1639 return NULL;
1640 } else {
1641 // Otherwise, use the passed-in wrapper as the same compartment
1642 // location wrapper.
1643 obj = targetwrapper;
1646 // Now, iterate through other scopes looking for references to the old
1647 // location object. Note that the entries in the maps are for |origobj|
1648 // and not |origwrapper|. They need to be updated to point at the new
1649 // location object.
1650 Value targetv = ObjectValue(*targetobj);
1651 CompartmentVector &vector = cx->runtime->compartments;
1652 AutoValueVector toTransplant(cx);
1653 if (!toTransplant.reserve(vector.length()))
1654 return NULL;
1656 for (JSCompartment **p = vector.begin(), **end = vector.end(); p != end; ++p) {
1657 WrapperMap &pmap = (*p)->crossCompartmentWrappers;
1658 if (WrapperMap::Ptr wp = pmap.lookup(origv)) {
1659 // We found a wrapper. Remember and root it.
1660 toTransplant.infallibleAppend(wp->value);
1664 for (Value *begin = toTransplant.begin(), *end = toTransplant.end(); begin != end; ++begin) {
1665 JSObject *wobj = &begin->toObject();
1666 JSCompartment *wcompartment = wobj->compartment();
1667 WrapperMap &pmap = wcompartment->crossCompartmentWrappers;
1668 JS_ASSERT(pmap.lookup(origv));
1669 pmap.remove(origv);
1671 // First, we wrap it in the new compartment. This will return a
1672 // new wrapper.
1673 AutoCompartment ac(cx, wobj);
1675 JSObject *tobj = targetobj;
1676 if (!ac.enter() || !wcompartment->wrap(cx, &tobj))
1677 return NULL;
1679 // Now, because we need to maintain object identity, we do a brain
1680 // transplant on the old object. At the same time, we update the
1681 // entry in the compartment's wrapper map to point to the old
1682 // wrapper.
1683 JS_ASSERT(tobj != wobj);
1684 if (!wobj->swap(cx, tobj))
1685 return NULL;
1686 pmap.put(targetv, ObjectValue(*wobj));
1689 // Lastly, update the original object to point to the new one. However, as
1690 // mentioned above, we do the transplant on the wrapper, not the object
1691 // itself, since all of the references are to the object itself.
1693 AutoCompartment ac(cx, origobj);
1694 JSObject *tobj = obj;
1695 if (!ac.enter() || !JS_WrapObject(cx, &tobj))
1696 return NULL;
1697 if (!origwrapper->swap(cx, tobj))
1698 return NULL;
1699 origwrapper->compartment()->crossCompartmentWrappers.put(targetv,
1700 ObjectValue(*origwrapper));
1703 return obj;
1706 JS_PUBLIC_API(JSObject *)
1707 JS_GetGlobalObject(JSContext *cx)
1709 return cx->globalObject;
1712 JS_PUBLIC_API(void)
1713 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1715 AssertNoGC(cx);
1716 CHECK_REQUEST(cx);
1718 cx->globalObject = obj;
1719 if (!cx->hasfp())
1720 cx->resetCompartment();
1723 JS_PUBLIC_API(JSBool)
1724 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1726 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
1727 AssertNoGC(cx);
1728 CHECK_REQUEST(cx);
1731 * JS_SetGlobalObject might or might not change cx's compartment, so call
1732 * it before assertSameCompartment. (The API contract is that *after* this,
1733 * cx and obj must be in the same compartment.)
1735 if (!cx->globalObject)
1736 JS_SetGlobalObject(cx, obj);
1738 assertSameCompartment(cx, obj);
1740 return GlobalObject::initStandardClasses(cx, RootedVar<GlobalObject*>(cx, &obj->global()));
1743 #define CLASP(name) (&name##Class)
1744 #define TYPED_ARRAY_CLASP(type) (&TypedArray::classes[TypedArray::type])
1745 #define EAGER_ATOM(name) NAME_OFFSET(name)
1746 #define EAGER_CLASS_ATOM(name) CLASS_NAME_OFFSET(name)
1747 #define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
1749 typedef struct JSStdName {
1750 JSObjectOp init;
1751 size_t atomOffset; /* offset of atom pointer in JSAtomState */
1752 Class *clasp;
1753 } JSStdName;
1755 static PropertyName *
1756 StdNameToPropertyName(JSContext *cx, JSStdName *stdn)
1758 return OFFSET_TO_NAME(cx->runtime, stdn->atomOffset);
1762 * Table of class initializers and their atom offsets in rt->atomState.
1763 * If you add a "standard" class, remember to update this table.
1765 static JSStdName standard_class_atoms[] = {
1766 {js_InitFunctionClass, EAGER_ATOM_AND_CLASP(Function)},
1767 {js_InitObjectClass, EAGER_ATOM_AND_CLASP(Object)},
1768 {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)},
1769 {js_InitBooleanClass, EAGER_ATOM_AND_CLASP(Boolean)},
1770 {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)},
1771 {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)},
1772 {js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)},
1773 {js_InitStringClass, EAGER_ATOM_AND_CLASP(String)},
1774 {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)},
1775 {js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)},
1776 #if JS_HAS_XML_SUPPORT
1777 {js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)},
1778 {js_InitNamespaceClass, EAGER_ATOM_AND_CLASP(Namespace)},
1779 {js_InitQNameClass, EAGER_ATOM_AND_CLASP(QName)},
1780 #endif
1781 #if JS_HAS_GENERATORS
1782 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
1783 #endif
1784 {js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
1785 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBufferObject::protoClass},
1786 {js_InitWeakMapClass, EAGER_CLASS_ATOM(WeakMap), &js::WeakMapClass},
1787 {js_InitMapClass, EAGER_CLASS_ATOM(Map), &js::MapObject::class_},
1788 {js_InitSetClass, EAGER_CLASS_ATOM(Set), &js::SetObject::class_},
1789 {NULL, 0, NULL}
1793 * Table of top-level function and constant names and their init functions.
1794 * If you add a "standard" global function or property, remember to update
1795 * this table.
1797 static JSStdName standard_class_names[] = {
1798 {js_InitObjectClass, EAGER_ATOM(eval), CLASP(Object)},
1800 /* Global properties and functions defined by the Number class. */
1801 {js_InitNumberClass, EAGER_ATOM(NaN), CLASP(Number)},
1802 {js_InitNumberClass, EAGER_ATOM(Infinity), CLASP(Number)},
1803 {js_InitNumberClass, EAGER_ATOM(isNaN), CLASP(Number)},
1804 {js_InitNumberClass, EAGER_ATOM(isFinite), CLASP(Number)},
1805 {js_InitNumberClass, EAGER_ATOM(parseFloat), CLASP(Number)},
1806 {js_InitNumberClass, EAGER_ATOM(parseInt), CLASP(Number)},
1808 /* String global functions. */
1809 {js_InitStringClass, EAGER_ATOM(escape), CLASP(String)},
1810 {js_InitStringClass, EAGER_ATOM(unescape), CLASP(String)},
1811 {js_InitStringClass, EAGER_ATOM(decodeURI), CLASP(String)},
1812 {js_InitStringClass, EAGER_ATOM(encodeURI), CLASP(String)},
1813 {js_InitStringClass, EAGER_ATOM(decodeURIComponent), CLASP(String)},
1814 {js_InitStringClass, EAGER_ATOM(encodeURIComponent), CLASP(String)},
1815 #if JS_HAS_UNEVAL
1816 {js_InitStringClass, EAGER_ATOM(uneval), CLASP(String)},
1817 #endif
1819 /* Exception constructors. */
1820 {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)},
1821 {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
1822 {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
1823 {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
1824 {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
1825 {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
1826 {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
1827 {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)},
1829 #if JS_HAS_XML_SUPPORT
1830 {js_InitXMLClass, EAGER_ATOM(XMLList), CLASP(XML)},
1831 {js_InitXMLClass, EAGER_ATOM(isXMLName), CLASP(XML)},
1832 #endif
1834 #if JS_HAS_GENERATORS
1835 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)},
1836 #endif
1838 /* Typed Arrays */
1839 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &ArrayBufferClass},
1840 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int8Array), TYPED_ARRAY_CLASP(TYPE_INT8)},
1841 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8Array), TYPED_ARRAY_CLASP(TYPE_UINT8)},
1842 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int16Array), TYPED_ARRAY_CLASP(TYPE_INT16)},
1843 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint16Array), TYPED_ARRAY_CLASP(TYPE_UINT16)},
1844 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int32Array), TYPED_ARRAY_CLASP(TYPE_INT32)},
1845 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint32Array), TYPED_ARRAY_CLASP(TYPE_UINT32)},
1846 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float32Array), TYPED_ARRAY_CLASP(TYPE_FLOAT32)},
1847 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
1848 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8ClampedArray),
1849 TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
1850 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(DataView), &DataViewClass},
1852 {js_InitWeakMapClass, EAGER_ATOM_AND_CLASP(WeakMap)},
1853 {js_InitProxyClass, EAGER_ATOM_AND_CLASP(Proxy)},
1855 {NULL, 0, NULL}
1858 static JSStdName object_prototype_names[] = {
1859 /* Object.prototype properties (global delegates to Object.prototype). */
1860 {js_InitObjectClass, EAGER_ATOM(proto), CLASP(Object)},
1861 #if JS_HAS_TOSOURCE
1862 {js_InitObjectClass, EAGER_ATOM(toSource), CLASP(Object)},
1863 #endif
1864 {js_InitObjectClass, EAGER_ATOM(toString), CLASP(Object)},
1865 {js_InitObjectClass, EAGER_ATOM(toLocaleString), CLASP(Object)},
1866 {js_InitObjectClass, EAGER_ATOM(valueOf), CLASP(Object)},
1867 #if JS_HAS_OBJ_WATCHPOINT
1868 {js_InitObjectClass, EAGER_ATOM(watch), CLASP(Object)},
1869 {js_InitObjectClass, EAGER_ATOM(unwatch), CLASP(Object)},
1870 #endif
1871 {js_InitObjectClass, EAGER_ATOM(hasOwnProperty), CLASP(Object)},
1872 {js_InitObjectClass, EAGER_ATOM(isPrototypeOf), CLASP(Object)},
1873 {js_InitObjectClass, EAGER_ATOM(propertyIsEnumerable), CLASP(Object)},
1874 #if OLD_GETTER_SETTER_METHODS
1875 {js_InitObjectClass, EAGER_ATOM(defineGetter), CLASP(Object)},
1876 {js_InitObjectClass, EAGER_ATOM(defineSetter), CLASP(Object)},
1877 {js_InitObjectClass, EAGER_ATOM(lookupGetter), CLASP(Object)},
1878 {js_InitObjectClass, EAGER_ATOM(lookupSetter), CLASP(Object)},
1879 #endif
1881 {NULL, 0, NULL}
1884 JS_PUBLIC_API(JSBool)
1885 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
1887 JSString *idstr;
1888 JSRuntime *rt;
1889 JSAtom *atom;
1890 JSStdName *stdnm;
1891 unsigned i;
1893 RootObject objRoot(cx, &obj);
1895 AssertNoGC(cx);
1896 CHECK_REQUEST(cx);
1897 assertSameCompartment(cx, obj, id);
1898 *resolved = JS_FALSE;
1900 rt = cx->runtime;
1901 if (!rt->hasContexts() || !JSID_IS_ATOM(id))
1902 return JS_TRUE;
1904 idstr = JSID_TO_STRING(id);
1906 /* Check whether we're resolving 'undefined', and define it if so. */
1907 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1908 if (idstr == atom) {
1909 *resolved = JS_TRUE;
1910 return obj->defineProperty(cx, atom->asPropertyName(), UndefinedValue(),
1911 JS_PropertyStub, JS_StrictPropertyStub,
1912 JSPROP_PERMANENT | JSPROP_READONLY);
1915 /* Try for class constructors/prototypes named by well-known atoms. */
1916 stdnm = NULL;
1917 for (i = 0; standard_class_atoms[i].init; i++) {
1918 JS_ASSERT(standard_class_atoms[i].clasp);
1919 atom = OFFSET_TO_NAME(rt, standard_class_atoms[i].atomOffset);
1920 if (idstr == atom) {
1921 stdnm = &standard_class_atoms[i];
1922 break;
1926 if (!stdnm) {
1927 /* Try less frequently used top-level functions and constants. */
1928 for (i = 0; standard_class_names[i].init; i++) {
1929 JS_ASSERT(standard_class_names[i].clasp);
1930 atom = StdNameToPropertyName(cx, &standard_class_names[i]);
1931 if (!atom)
1932 return JS_FALSE;
1933 if (idstr == atom) {
1934 stdnm = &standard_class_names[i];
1935 break;
1939 if (!stdnm && !obj->getProto()) {
1941 * Try even less frequently used names delegated from the global
1942 * object to Object.prototype, but only if the Object class hasn't
1943 * yet been initialized.
1945 for (i = 0; object_prototype_names[i].init; i++) {
1946 JS_ASSERT(object_prototype_names[i].clasp);
1947 atom = StdNameToPropertyName(cx, &object_prototype_names[i]);
1948 if (!atom)
1949 return JS_FALSE;
1950 if (idstr == atom) {
1951 stdnm = &object_prototype_names[i];
1952 break;
1958 if (stdnm) {
1960 * If this standard class is anonymous, then we don't want to resolve
1961 * by name.
1963 JS_ASSERT(obj->isGlobal());
1964 if (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)
1965 return JS_TRUE;
1967 if (IsStandardClassResolved(obj, stdnm->clasp))
1968 return JS_TRUE;
1970 if (!stdnm->init(cx, obj))
1971 return JS_FALSE;
1972 *resolved = JS_TRUE;
1974 return JS_TRUE;
1977 JS_PUBLIC_API(JSBool)
1978 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj_)
1980 JSRuntime *rt;
1981 unsigned i;
1983 AssertNoGC(cx);
1984 CHECK_REQUEST(cx);
1985 assertSameCompartment(cx, obj_);
1986 rt = cx->runtime;
1988 RootedVarObject obj(cx, obj_);
1991 * Check whether we need to bind 'undefined' and define it if so.
1992 * Since ES5 15.1.1.3 undefined can't be deleted.
1994 PropertyName *name = rt->atomState.typeAtoms[JSTYPE_VOID];
1995 if (!obj->nativeContains(cx, NameToId(name)) &&
1996 !obj->defineProperty(cx, name, UndefinedValue(),
1997 JS_PropertyStub, JS_StrictPropertyStub,
1998 JSPROP_PERMANENT | JSPROP_READONLY)) {
1999 return JS_FALSE;
2002 /* Initialize any classes that have not been initialized yet. */
2003 for (i = 0; standard_class_atoms[i].init; i++) {
2004 if (!js::IsStandardClassResolved(obj, standard_class_atoms[i].clasp) &&
2005 !standard_class_atoms[i].init(cx, obj))
2007 return JS_FALSE;
2011 return JS_TRUE;
2014 static JSIdArray *
2015 NewIdArray(JSContext *cx, int length)
2017 JSIdArray *ida;
2019 ida = (JSIdArray *)
2020 cx->calloc_(offsetof(JSIdArray, vector) + length * sizeof(jsval));
2021 if (ida)
2022 ida->length = length;
2023 return ida;
2027 * Unlike realloc(3), this function frees ida on failure.
2029 static JSIdArray *
2030 SetIdArrayLength(JSContext *cx, JSIdArray *ida, int length)
2032 JSIdArray *rida;
2034 rida = (JSIdArray *)
2035 JS_realloc(cx, ida,
2036 offsetof(JSIdArray, vector) + length * sizeof(jsval));
2037 if (!rida) {
2038 JS_DestroyIdArray(cx, ida);
2039 } else {
2040 rida->length = length;
2042 return rida;
2045 static JSIdArray *
2046 AddNameToArray(JSContext *cx, PropertyName *name, JSIdArray *ida, int *ip)
2048 int i = *ip;
2049 int length = ida->length;
2050 if (i >= length) {
2051 ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
2052 if (!ida)
2053 return NULL;
2054 JS_ASSERT(i < ida->length);
2056 ida->vector[i].init(NameToId(name));
2057 *ip = i + 1;
2058 return ida;
2061 static JSIdArray *
2062 EnumerateIfResolved(JSContext *cx, JSObject *obj, PropertyName *name, JSIdArray *ida,
2063 int *ip, JSBool *foundp)
2065 *foundp = obj->nativeContains(cx, NameToId(name));
2066 if (*foundp)
2067 ida = AddNameToArray(cx, name, ida, ip);
2068 return ida;
2071 JS_PUBLIC_API(JSIdArray *)
2072 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, JSIdArray *ida)
2074 JSRuntime *rt;
2075 int i, j, k;
2076 PropertyName *name;
2077 JSBool found;
2078 JSObjectOp init;
2080 AssertNoGC(cx);
2081 CHECK_REQUEST(cx);
2082 assertSameCompartment(cx, obj, ida);
2083 rt = cx->runtime;
2084 if (ida) {
2085 i = ida->length;
2086 } else {
2087 ida = NewIdArray(cx, 8);
2088 if (!ida)
2089 return NULL;
2090 i = 0;
2093 /* Check whether 'undefined' has been resolved and enumerate it if so. */
2094 name = rt->atomState.typeAtoms[JSTYPE_VOID];
2095 ida = EnumerateIfResolved(cx, obj, name, ida, &i, &found);
2096 if (!ida)
2097 return NULL;
2099 /* Enumerate only classes that *have* been resolved. */
2100 for (j = 0; standard_class_atoms[j].init; j++) {
2101 name = OFFSET_TO_NAME(rt, standard_class_atoms[j].atomOffset);
2102 ida = EnumerateIfResolved(cx, obj, name, ida, &i, &found);
2103 if (!ida)
2104 return NULL;
2106 if (found) {
2107 init = standard_class_atoms[j].init;
2109 for (k = 0; standard_class_names[k].init; k++) {
2110 if (standard_class_names[k].init == init) {
2111 name = StdNameToPropertyName(cx, &standard_class_names[k]);
2112 ida = AddNameToArray(cx, name, ida, &i);
2113 if (!ida)
2114 return NULL;
2118 if (init == js_InitObjectClass) {
2119 for (k = 0; object_prototype_names[k].init; k++) {
2120 name = StdNameToPropertyName(cx, &object_prototype_names[k]);
2121 ida = AddNameToArray(cx, name, ida, &i);
2122 if (!ida)
2123 return NULL;
2129 /* Trim to exact length. */
2130 return SetIdArrayLength(cx, ida, i);
2133 #undef CLASP
2134 #undef EAGER_ATOM
2135 #undef EAGER_CLASS_ATOM
2136 #undef EAGER_ATOM_CLASP
2138 JS_PUBLIC_API(JSBool)
2139 JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp)
2141 AssertNoGC(cx);
2142 CHECK_REQUEST(cx);
2143 assertSameCompartment(cx, obj);
2144 return js_GetClassObject(cx, obj, key, objp);
2147 JS_PUBLIC_API(JSObject *)
2148 JS_GetObjectPrototype(JSContext *cx, JSObject *forObj)
2150 CHECK_REQUEST(cx);
2151 assertSameCompartment(cx, forObj);
2152 return forObj->global().getOrCreateObjectPrototype(cx);
2155 JS_PUBLIC_API(JSObject *)
2156 JS_GetFunctionPrototype(JSContext *cx, JSObject *forObj)
2158 CHECK_REQUEST(cx);
2159 assertSameCompartment(cx, forObj);
2160 return forObj->global().getOrCreateFunctionPrototype(cx);
2163 JS_PUBLIC_API(JSObject *)
2164 JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
2166 AssertNoGC(cx);
2167 assertSameCompartment(cx, obj);
2168 return &obj->global();
2171 JS_PUBLIC_API(JSObject *)
2172 JS_GetGlobalForScopeChain(JSContext *cx)
2174 AssertNoGC(cx);
2175 CHECK_REQUEST(cx);
2176 return GetGlobalForScopeChain(cx);
2179 JS_PUBLIC_API(jsval)
2180 JS_ComputeThis(JSContext *cx, jsval *vp)
2182 AssertNoGC(cx);
2183 assertSameCompartment(cx, JSValueArray(vp, 2));
2184 CallReceiver call = CallReceiverFromVp(vp);
2185 if (!BoxNonStrictThis(cx, call))
2186 return JSVAL_NULL;
2187 return call.thisv();
2190 JS_PUBLIC_API(void)
2191 JS_MallocInCompartment(JSCompartment *comp, size_t nbytes)
2193 comp->mallocInCompartment(nbytes);
2196 JS_PUBLIC_API(void)
2197 JS_FreeInCompartment(JSCompartment *comp, size_t nbytes)
2199 comp->freeInCompartment(nbytes);
2202 JS_PUBLIC_API(void *)
2203 JS_malloc(JSContext *cx, size_t nbytes)
2205 AssertNoGC(cx);
2206 CHECK_REQUEST(cx);
2207 return cx->malloc_(nbytes);
2210 JS_PUBLIC_API(void *)
2211 JS_realloc(JSContext *cx, void *p, size_t nbytes)
2213 AssertNoGC(cx);
2214 CHECK_REQUEST(cx);
2215 return cx->realloc_(p, nbytes);
2218 JS_PUBLIC_API(void)
2219 JS_free(JSContext *cx, void *p)
2221 return cx->free_(p);
2224 JS_PUBLIC_API(void)
2225 JS_freeop(JSFreeOp *fop, void *p)
2227 return FreeOp::get(fop)->free_(p);
2230 JS_PUBLIC_API(JSFreeOp *)
2231 JS_GetDefaultFreeOp(JSRuntime *rt)
2233 return rt->defaultFreeOp();
2236 JS_PUBLIC_API(void)
2237 JS_updateMallocCounter(JSContext *cx, size_t nbytes)
2239 return cx->runtime->updateMallocCounter(cx, nbytes);
2242 JS_PUBLIC_API(char *)
2243 JS_strdup(JSContext *cx, const char *s)
2245 AssertNoGC(cx);
2246 size_t n = strlen(s) + 1;
2247 void *p = cx->malloc_(n);
2248 if (!p)
2249 return NULL;
2250 return (char *)js_memcpy(p, s, n);
2253 JS_PUBLIC_API(JSBool)
2254 JS_NewNumberValue(JSContext *cx, double d, jsval *rval)
2256 AssertNoGC(cx);
2257 d = JS_CANONICALIZE_NAN(d);
2258 rval->setNumber(d);
2259 return JS_TRUE;
2262 #undef JS_AddRoot
2264 JS_PUBLIC_API(JSBool)
2265 JS_AddValueRoot(JSContext *cx, jsval *vp)
2267 AssertNoGC(cx);
2268 CHECK_REQUEST(cx);
2269 return js_AddRoot(cx, vp, NULL);
2272 JS_PUBLIC_API(JSBool)
2273 JS_AddStringRoot(JSContext *cx, JSString **rp)
2275 AssertNoGC(cx);
2276 CHECK_REQUEST(cx);
2277 return js_AddGCThingRoot(cx, (void **)rp, NULL);
2280 JS_PUBLIC_API(JSBool)
2281 JS_AddObjectRoot(JSContext *cx, JSObject **rp)
2283 AssertNoGC(cx);
2284 CHECK_REQUEST(cx);
2285 return js_AddGCThingRoot(cx, (void **)rp, NULL);
2288 JS_PUBLIC_API(JSBool)
2289 JS_AddGCThingRoot(JSContext *cx, void **rp)
2291 AssertNoGC(cx);
2292 CHECK_REQUEST(cx);
2293 return js_AddGCThingRoot(cx, (void **)rp, NULL);
2296 JS_PUBLIC_API(JSBool)
2297 JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name)
2299 AssertNoGC(cx);
2300 CHECK_REQUEST(cx);
2301 return js_AddRoot(cx, vp, name);
2304 JS_PUBLIC_API(JSBool)
2305 JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name)
2307 AssertNoGC(cx);
2308 CHECK_REQUEST(cx);
2309 return js_AddGCThingRoot(cx, (void **)rp, name);
2312 JS_PUBLIC_API(JSBool)
2313 JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name)
2315 AssertNoGC(cx);
2316 CHECK_REQUEST(cx);
2317 return js_AddGCThingRoot(cx, (void **)rp, name);
2320 JS_PUBLIC_API(JSBool)
2321 JS_AddNamedScriptRoot(JSContext *cx, JSScript **rp, const char *name)
2323 AssertNoGC(cx);
2324 CHECK_REQUEST(cx);
2325 return js_AddGCThingRoot(cx, (void **)rp, name);
2328 JS_PUBLIC_API(JSBool)
2329 JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name)
2331 AssertNoGC(cx);
2332 CHECK_REQUEST(cx);
2333 return js_AddGCThingRoot(cx, (void **)rp, name);
2336 /* We allow unrooting from finalizers within the GC */
2338 JS_PUBLIC_API(void)
2339 JS_RemoveValueRoot(JSContext *cx, jsval *vp)
2341 CHECK_REQUEST(cx);
2342 js_RemoveRoot(cx->runtime, (void *)vp);
2345 JS_PUBLIC_API(void)
2346 JS_RemoveStringRoot(JSContext *cx, JSString **rp)
2348 CHECK_REQUEST(cx);
2349 js_RemoveRoot(cx->runtime, (void *)rp);
2352 JS_PUBLIC_API(void)
2353 JS_RemoveObjectRoot(JSContext *cx, JSObject **rp)
2355 CHECK_REQUEST(cx);
2356 js_RemoveRoot(cx->runtime, (void *)rp);
2359 JS_PUBLIC_API(void)
2360 JS_RemoveScriptRoot(JSContext *cx, JSScript **rp)
2362 CHECK_REQUEST(cx);
2363 js_RemoveRoot(cx->runtime, (void *)rp);
2366 JS_PUBLIC_API(void)
2367 JS_RemoveGCThingRoot(JSContext *cx, void **rp)
2369 CHECK_REQUEST(cx);
2370 js_RemoveRoot(cx->runtime, (void *)rp);
2373 JS_PUBLIC_API(void)
2374 JS_RemoveValueRootRT(JSRuntime *rt, jsval *vp)
2376 js_RemoveRoot(rt, (void *)vp);
2379 JS_PUBLIC_API(void)
2380 JS_RemoveStringRootRT(JSRuntime *rt, JSString **rp)
2382 js_RemoveRoot(rt, (void *)rp);
2385 JS_PUBLIC_API(void)
2386 JS_RemoveObjectRootRT(JSRuntime *rt, JSObject **rp)
2388 js_RemoveRoot(rt, (void *)rp);
2391 JS_PUBLIC_API(void)
2392 JS_RemoveScriptRoot(JSRuntime *rt, JSScript **rp)
2394 js_RemoveRoot(rt, (void *)rp);
2397 JS_NEVER_INLINE JS_PUBLIC_API(void)
2398 JS_AnchorPtr(void *p)
2402 #ifdef DEBUG
2404 JS_PUBLIC_API(void)
2405 JS_DumpNamedRoots(JSRuntime *rt,
2406 void (*dump)(const char *name, void *rp, JSGCRootType type, void *data),
2407 void *data)
2409 js_DumpNamedRoots(rt, dump, data);
2412 #endif /* DEBUG */
2414 JS_PUBLIC_API(uint32_t)
2415 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
2417 return js_MapGCRoots(rt, map, data);
2420 JS_PUBLIC_API(JSBool)
2421 JS_LockGCThing(JSContext *cx, void *thing)
2423 JSBool ok;
2425 AssertNoGC(cx);
2426 CHECK_REQUEST(cx);
2427 ok = js_LockGCThingRT(cx->runtime, thing);
2428 if (!ok)
2429 JS_ReportOutOfMemory(cx);
2430 return ok;
2433 JS_PUBLIC_API(JSBool)
2434 JS_LockGCThingRT(JSRuntime *rt, void *thing)
2436 return js_LockGCThingRT(rt, thing);
2439 JS_PUBLIC_API(JSBool)
2440 JS_UnlockGCThing(JSContext *cx, void *thing)
2442 AssertNoGC(cx);
2443 CHECK_REQUEST(cx);
2444 js_UnlockGCThingRT(cx->runtime, thing);
2445 return true;
2448 JS_PUBLIC_API(JSBool)
2449 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
2451 js_UnlockGCThingRT(rt, thing);
2452 return true;
2455 JS_PUBLIC_API(void)
2456 JS_SetExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
2458 AssertNoGC(rt);
2459 rt->gcBlackRootsTraceOp = traceOp;
2460 rt->gcBlackRootsData = data;
2463 JS_PUBLIC_API(void)
2464 JS_TracerInit(JSTracer *trc, JSRuntime *rt, JSTraceCallback callback)
2466 InitTracer(trc, rt, callback);
2469 JS_PUBLIC_API(void)
2470 JS_TraceRuntime(JSTracer *trc)
2472 AssertNoGC(trc->runtime);
2473 TraceRuntime(trc);
2476 JS_PUBLIC_API(void)
2477 JS_TraceChildren(JSTracer *trc, void *thing, JSGCTraceKind kind)
2479 js::TraceChildren(trc, thing, kind);
2482 JS_PUBLIC_API(void)
2483 JS_CallTracer(JSTracer *trc, void *thing, JSGCTraceKind kind)
2485 js::CallTracer(trc, thing, kind);
2488 #ifdef DEBUG
2490 JS_PUBLIC_API(void)
2491 JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing,
2492 JSGCTraceKind kind, JSBool details)
2494 const char *name = NULL; /* silence uninitialized warning */
2495 size_t n;
2497 if (bufsize == 0)
2498 return;
2500 switch (kind) {
2501 case JSTRACE_OBJECT:
2503 name = static_cast<JSObject *>(thing)->getClass()->name;
2504 break;
2507 case JSTRACE_STRING:
2508 name = ((JSString *)thing)->isDependent()
2509 ? "substring"
2510 : "string";
2511 break;
2513 case JSTRACE_SCRIPT:
2514 name = "script";
2515 break;
2517 case JSTRACE_SHAPE:
2518 name = "shape";
2519 break;
2521 case JSTRACE_BASE_SHAPE:
2522 name = "base_shape";
2523 break;
2525 case JSTRACE_TYPE_OBJECT:
2526 name = "type_object";
2527 break;
2529 #if JS_HAS_XML_SUPPORT
2530 case JSTRACE_XML:
2531 name = "xml";
2532 break;
2533 #endif
2536 n = strlen(name);
2537 if (n > bufsize - 1)
2538 n = bufsize - 1;
2539 js_memcpy(buf, name, n + 1);
2540 buf += n;
2541 bufsize -= n;
2542 *buf = '\0';
2544 if (details && bufsize > 2) {
2545 switch (kind) {
2546 case JSTRACE_OBJECT:
2548 JSObject *obj = (JSObject *)thing;
2549 Class *clasp = obj->getClass();
2550 if (clasp == &FunctionClass) {
2551 JSFunction *fun = obj->toFunction();
2552 if (!fun) {
2553 JS_snprintf(buf, bufsize, " <newborn>");
2554 } else if (fun != obj) {
2555 JS_snprintf(buf, bufsize, " %p", fun);
2556 } else {
2557 if (fun->atom) {
2558 *buf++ = ' ';
2559 bufsize--;
2560 PutEscapedString(buf, bufsize, fun->atom, 0);
2563 } else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
2564 JS_snprintf(buf, bufsize, " %p", obj->getPrivate());
2565 } else {
2566 JS_snprintf(buf, bufsize, " <no private>");
2568 break;
2571 case JSTRACE_STRING:
2573 *buf++ = ' ';
2574 bufsize--;
2575 JSString *str = (JSString *)thing;
2576 if (str->isLinear())
2577 PutEscapedString(buf, bufsize, &str->asLinear(), 0);
2578 else
2579 JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
2580 break;
2583 case JSTRACE_SCRIPT:
2585 JSScript *script = static_cast<JSScript *>(thing);
2586 JS_snprintf(buf, bufsize, " %s:%u", script->filename, unsigned(script->lineno));
2587 break;
2590 case JSTRACE_SHAPE:
2591 case JSTRACE_BASE_SHAPE:
2592 case JSTRACE_TYPE_OBJECT:
2593 break;
2595 #if JS_HAS_XML_SUPPORT
2596 case JSTRACE_XML:
2598 extern const char *js_xml_class_str[];
2599 JSXML *xml = (JSXML *)thing;
2601 JS_snprintf(buf, bufsize, " %s", js_xml_class_str[xml->xml_class]);
2602 break;
2604 #endif
2607 buf[bufsize - 1] = '\0';
2610 extern JS_PUBLIC_API(const char *)
2611 JS_GetTraceEdgeName(JSTracer *trc, char *buffer, int bufferSize)
2613 if (trc->debugPrinter) {
2614 trc->debugPrinter(trc, buffer, bufferSize);
2615 return buffer;
2617 if (trc->debugPrintIndex != (size_t) - 1) {
2618 JS_snprintf(buffer, bufferSize, "%s[%lu]",
2619 (const char *)trc->debugPrintArg,
2620 trc->debugPrintIndex);
2621 return buffer;
2623 return (const char*)trc->debugPrintArg;
2626 typedef struct JSHeapDumpNode JSHeapDumpNode;
2628 struct JSHeapDumpNode {
2629 void *thing;
2630 JSGCTraceKind kind;
2631 JSHeapDumpNode *next; /* next sibling */
2632 JSHeapDumpNode *parent; /* node with the thing that refer to thing
2633 from this node */
2634 char edgeName[1]; /* name of the edge from parent->thing
2635 into thing */
2638 typedef HashSet<void *, PointerHasher<void *, 3>, SystemAllocPolicy> VisitedSet;
2640 typedef struct JSDumpingTracer {
2641 JSTracer base;
2642 VisitedSet visited;
2643 bool ok;
2644 void *startThing;
2645 void *thingToFind;
2646 void *thingToIgnore;
2647 JSHeapDumpNode *parentNode;
2648 JSHeapDumpNode **lastNodep;
2649 char buffer[200];
2650 } JSDumpingTracer;
2652 static void
2653 DumpNotify(JSTracer *trc, void **thingp, JSGCTraceKind kind)
2655 JS_ASSERT(trc->callback == DumpNotify);
2657 JSDumpingTracer *dtrc = (JSDumpingTracer *)trc;
2658 void *thing = *thingp;
2660 if (!dtrc->ok || thing == dtrc->thingToIgnore)
2661 return;
2664 * Check if we have already seen thing unless it is thingToFind to include
2665 * it to the graph each time we reach it and print all live things that
2666 * refer to thingToFind.
2668 * This does not print all possible paths leading to thingToFind since
2669 * when a thing A refers directly or indirectly to thingToFind and A is
2670 * present several times in the graph, we will print only the first path
2671 * leading to A and thingToFind, other ways to reach A will be ignored.
2673 if (dtrc->thingToFind != thing) {
2675 * The startThing check allows to avoid putting startThing into the
2676 * hash table before tracing startThing in JS_DumpHeap.
2678 if (thing == dtrc->startThing)
2679 return;
2680 VisitedSet::AddPtr p = dtrc->visited.lookupForAdd(thing);
2681 if (p)
2682 return;
2683 if (!dtrc->visited.add(p, thing)) {
2684 dtrc->ok = false;
2685 return;
2689 const char *edgeName = JS_GetTraceEdgeName(&dtrc->base, dtrc->buffer, sizeof(dtrc->buffer));
2690 size_t edgeNameSize = strlen(edgeName) + 1;
2691 size_t bytes = offsetof(JSHeapDumpNode, edgeName) + edgeNameSize;
2692 JSHeapDumpNode *node = (JSHeapDumpNode *) OffTheBooks::malloc_(bytes);
2693 if (!node) {
2694 dtrc->ok = false;
2695 return;
2698 node->thing = thing;
2699 node->kind = kind;
2700 node->next = NULL;
2701 node->parent = dtrc->parentNode;
2702 js_memcpy(node->edgeName, edgeName, edgeNameSize);
2704 JS_ASSERT(!*dtrc->lastNodep);
2705 *dtrc->lastNodep = node;
2706 dtrc->lastNodep = &node->next;
2709 /* Dump node and the chain that leads to thing it contains. */
2710 static JSBool
2711 DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
2713 JSHeapDumpNode *prev, *following;
2714 size_t chainLimit;
2715 enum { MAX_PARENTS_TO_PRINT = 10 };
2717 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2718 &dtrc->base, node->thing, node->kind, JS_TRUE);
2719 if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
2720 return JS_FALSE;
2723 * We need to print the parent chain in the reverse order. To do it in
2724 * O(N) time where N is the chain length we first reverse the chain while
2725 * searching for the top and then print each node while restoring the
2726 * chain order.
2728 chainLimit = MAX_PARENTS_TO_PRINT;
2729 prev = NULL;
2730 for (;;) {
2731 following = node->parent;
2732 node->parent = prev;
2733 prev = node;
2734 node = following;
2735 if (!node)
2736 break;
2737 if (chainLimit == 0) {
2738 if (fputs("...", fp) < 0)
2739 return JS_FALSE;
2740 break;
2742 --chainLimit;
2745 node = prev;
2746 prev = following;
2747 bool ok = true;
2748 do {
2749 /* Loop must continue even when !ok to restore the parent chain. */
2750 if (ok) {
2751 if (!prev) {
2752 /* Print edge from some runtime root or startThing. */
2753 if (fputs(node->edgeName, fp) < 0)
2754 ok = false;
2755 } else {
2756 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2757 &dtrc->base, prev->thing, prev->kind,
2758 JS_FALSE);
2759 if (fprintf(fp, "(%p %s).%s",
2760 prev->thing, dtrc->buffer, node->edgeName) < 0) {
2761 ok = false;
2765 following = node->parent;
2766 node->parent = prev;
2767 prev = node;
2768 node = following;
2769 } while (node);
2771 return ok && putc('\n', fp) >= 0;
2774 JS_PUBLIC_API(JSBool)
2775 JS_DumpHeap(JSRuntime *rt, FILE *fp, void* startThing, JSGCTraceKind startKind,
2776 void *thingToFind, size_t maxDepth, void *thingToIgnore)
2778 if (maxDepth == 0)
2779 return true;
2781 JSDumpingTracer dtrc;
2782 if (!dtrc.visited.init())
2783 return false;
2784 JS_TracerInit(&dtrc.base, rt, DumpNotify);
2785 dtrc.ok = true;
2786 dtrc.startThing = startThing;
2787 dtrc.thingToFind = thingToFind;
2788 dtrc.thingToIgnore = thingToIgnore;
2789 dtrc.parentNode = NULL;
2790 JSHeapDumpNode *node = NULL;
2791 dtrc.lastNodep = &node;
2792 if (!startThing) {
2793 JS_ASSERT(startKind == JSTRACE_OBJECT);
2794 TraceRuntime(&dtrc.base);
2795 } else {
2796 JS_TraceChildren(&dtrc.base, startThing, startKind);
2799 if (!node)
2800 return dtrc.ok;
2802 size_t depth = 1;
2803 JSHeapDumpNode *children, *next, *parent;
2804 bool thingToFindWasTraced = thingToFind && thingToFind == startThing;
2805 for (;;) {
2807 * Loop must continue even when !dtrc.ok to free all nodes allocated
2808 * so far.
2810 if (dtrc.ok) {
2811 if (thingToFind == NULL || thingToFind == node->thing)
2812 dtrc.ok = DumpNode(&dtrc, fp, node);
2814 /* Descend into children. */
2815 if (dtrc.ok &&
2816 depth < maxDepth &&
2817 (thingToFind != node->thing || !thingToFindWasTraced)) {
2818 dtrc.parentNode = node;
2819 children = NULL;
2820 dtrc.lastNodep = &children;
2821 JS_TraceChildren(&dtrc.base, node->thing, node->kind);
2822 if (thingToFind == node->thing)
2823 thingToFindWasTraced = JS_TRUE;
2824 if (children != NULL) {
2825 ++depth;
2826 node = children;
2827 continue;
2832 /* Move to next or parents next and free the node. */
2833 for (;;) {
2834 next = node->next;
2835 parent = node->parent;
2836 Foreground::free_(node);
2837 node = next;
2838 if (node)
2839 break;
2840 if (!parent)
2841 return dtrc.ok;
2842 JS_ASSERT(depth > 1);
2843 --depth;
2844 node = parent;
2848 JS_ASSERT(depth == 1);
2849 return dtrc.ok;
2852 #endif /* DEBUG */
2854 extern JS_PUBLIC_API(JSBool)
2855 JS_IsGCMarkingTracer(JSTracer *trc)
2857 return IS_GC_MARKING_TRACER(trc);
2860 JS_PUBLIC_API(void)
2861 JS_GC(JSRuntime *rt)
2863 AssertNoGC(rt);
2864 PrepareForFullGC(rt);
2865 GC(rt, GC_NORMAL, gcreason::API);
2868 JS_PUBLIC_API(void)
2869 JS_MaybeGC(JSContext *cx)
2871 MaybeGC(cx);
2874 JS_PUBLIC_API(void)
2875 JS_SetGCCallback(JSRuntime *rt, JSGCCallback cb)
2877 AssertNoGC(rt);
2878 rt->gcCallback = cb;
2881 JS_PUBLIC_API(void)
2882 JS_SetFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb)
2884 AssertNoGC(rt);
2885 rt->gcFinalizeCallback = cb;
2888 JS_PUBLIC_API(JSBool)
2889 JS_IsAboutToBeFinalized(void *thing)
2891 gc::Cell *t = static_cast<gc::Cell *>(thing);
2892 return IsAboutToBeFinalized(t);
2895 JS_PUBLIC_API(void)
2896 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32_t value)
2898 switch (key) {
2899 case JSGC_MAX_BYTES: {
2900 JS_ASSERT(value >= rt->gcBytes);
2901 rt->gcMaxBytes = value;
2902 break;
2904 case JSGC_MAX_MALLOC_BYTES:
2905 rt->setGCMaxMallocBytes(value);
2906 break;
2907 case JSGC_SLICE_TIME_BUDGET:
2908 rt->gcSliceBudget = SliceBudget::TimeBudget(value);
2909 break;
2910 case JSGC_MARK_STACK_LIMIT:
2911 js::SetMarkStackLimit(rt, value);
2912 break;
2913 default:
2914 JS_ASSERT(key == JSGC_MODE);
2915 rt->gcMode = JSGCMode(value);
2916 JS_ASSERT(rt->gcMode == JSGC_MODE_GLOBAL ||
2917 rt->gcMode == JSGC_MODE_COMPARTMENT ||
2918 rt->gcMode == JSGC_MODE_INCREMENTAL);
2919 return;
2923 JS_PUBLIC_API(uint32_t)
2924 JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
2926 switch (key) {
2927 case JSGC_MAX_BYTES:
2928 return uint32_t(rt->gcMaxBytes);
2929 case JSGC_MAX_MALLOC_BYTES:
2930 return rt->gcMaxMallocBytes;
2931 case JSGC_BYTES:
2932 return uint32_t(rt->gcBytes);
2933 case JSGC_MODE:
2934 return uint32_t(rt->gcMode);
2935 case JSGC_UNUSED_CHUNKS:
2936 return uint32_t(rt->gcChunkPool.getEmptyCount());
2937 case JSGC_TOTAL_CHUNKS:
2938 return uint32_t(rt->gcChunkSet.count() + rt->gcChunkPool.getEmptyCount());
2939 case JSGC_SLICE_TIME_BUDGET:
2940 return uint32_t(rt->gcSliceBudget > 0 ? rt->gcSliceBudget / PRMJ_USEC_PER_MSEC : 0);
2941 case JSGC_MARK_STACK_LIMIT:
2942 return rt->gcMarker.sizeLimit();
2943 default:
2944 JS_ASSERT(key == JSGC_NUMBER);
2945 return uint32_t(rt->gcNumber);
2949 JS_PUBLIC_API(void)
2950 JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32_t value)
2952 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2955 JS_PUBLIC_API(uint32_t)
2956 JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key)
2958 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2959 return 0;
2962 JS_PUBLIC_API(JSString *)
2963 JS_NewExternalString(JSContext *cx, const jschar *chars, size_t length,
2964 const JSStringFinalizer *fin)
2966 AssertNoGC(cx);
2967 CHECK_REQUEST(cx);
2968 JSString *s = JSExternalString::new_(cx, chars, length, fin);
2969 Probes::createString(cx, s, length);
2970 return s;
2973 extern JS_PUBLIC_API(JSBool)
2974 JS_IsExternalString(JSString *str)
2976 return str->isExternal();
2979 extern JS_PUBLIC_API(const JSStringFinalizer *)
2980 JS_GetExternalStringFinalizer(JSString *str)
2982 return str->asExternal().externalFinalizer();
2985 JS_PUBLIC_API(void)
2986 JS_SetNativeStackQuota(JSRuntime *rt, size_t stackSize)
2988 rt->nativeStackQuota = stackSize;
2989 if (!rt->nativeStackBase)
2990 return;
2992 #if JS_STACK_GROWTH_DIRECTION > 0
2993 if (stackSize == 0) {
2994 rt->nativeStackLimit = UINTPTR_MAX;
2995 } else {
2996 JS_ASSERT(rt->nativeStackBase <= size_t(-1) - stackSize);
2997 rt->nativeStackLimit = rt->nativeStackBase + stackSize - 1;
2999 #else
3000 if (stackSize == 0) {
3001 rt->nativeStackLimit = 0;
3002 } else {
3003 JS_ASSERT(rt->nativeStackBase >= stackSize);
3004 rt->nativeStackLimit = rt->nativeStackBase - (stackSize - 1);
3006 #endif
3009 /************************************************************************/
3011 JS_PUBLIC_API(int)
3012 JS_IdArrayLength(JSContext *cx, JSIdArray *ida)
3014 return ida->length;
3017 JS_PUBLIC_API(jsid)
3018 JS_IdArrayGet(JSContext *cx, JSIdArray *ida, int index)
3020 JS_ASSERT(index >= 0 && index < ida->length);
3021 return ida->vector[index];
3024 JS_PUBLIC_API(void)
3025 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
3027 DestroyIdArray(cx->runtime->defaultFreeOp(), ida);
3030 JS_PUBLIC_API(JSBool)
3031 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
3033 AssertNoGC(cx);
3034 CHECK_REQUEST(cx);
3035 assertSameCompartment(cx, v);
3036 return ValueToId(cx, v, idp);
3039 JS_PUBLIC_API(JSBool)
3040 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
3042 AssertNoGC(cx);
3043 CHECK_REQUEST(cx);
3044 *vp = IdToJsval(id);
3045 assertSameCompartment(cx, *vp);
3046 return JS_TRUE;
3049 JS_PUBLIC_API(JSBool)
3050 JS_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
3052 AssertNoGC(cx);
3053 CHECK_REQUEST(cx);
3054 JS_ASSERT(obj != NULL);
3055 JS_ASSERT(hint == JSTYPE_VOID || hint == JSTYPE_STRING || hint == JSTYPE_NUMBER);
3056 return obj->defaultValue(cx, hint, vp);
3059 JS_PUBLIC_API(JSBool)
3060 JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3062 return JS_TRUE;
3065 JS_PUBLIC_API(JSBool)
3066 JS_StrictPropertyStub(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
3068 return JS_TRUE;
3071 JS_PUBLIC_API(JSBool)
3072 JS_EnumerateStub(JSContext *cx, JSObject *obj)
3074 return JS_TRUE;
3077 JS_PUBLIC_API(JSBool)
3078 JS_ResolveStub(JSContext *cx, JSObject *obj, jsid id)
3080 return JS_TRUE;
3083 JS_PUBLIC_API(JSBool)
3084 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
3086 JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION);
3087 JS_ASSERT(obj);
3088 return DefaultValue(cx, RootedVarObject(cx, obj), type, vp);
3091 JS_PUBLIC_API(JSObject *)
3092 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
3093 JSClass *clasp, JSNative constructor, unsigned nargs,
3094 JSPropertySpec *ps, JSFunctionSpec *fs,
3095 JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
3097 AssertNoGC(cx);
3098 CHECK_REQUEST(cx);
3099 assertSameCompartment(cx, obj, parent_proto);
3100 RootObject objRoot(cx, &obj);
3101 return js_InitClass(cx, objRoot, parent_proto, Valueify(clasp), constructor,
3102 nargs, ps, fs, static_ps, static_fs);
3105 JS_PUBLIC_API(JSBool)
3106 JS_LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor, JSObject *proto)
3108 return LinkConstructorAndPrototype(cx, ctor, proto);
3111 JS_PUBLIC_API(JSClass *)
3112 JS_GetClass(JSObject *obj)
3114 return obj->getJSClass();
3117 JS_PUBLIC_API(JSBool)
3118 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
3120 AssertNoGC(cx);
3121 CHECK_REQUEST(cx);
3122 #ifdef DEBUG
3123 if (argv) {
3124 assertSameCompartment(cx, obj);
3125 assertSameCompartment(cx, JSValueArray(argv - 2, 2));
3127 #endif
3128 if (!obj || obj->getJSClass() != clasp) {
3129 if (argv)
3130 ReportIncompatibleMethod(cx, CallReceiverFromArgv(argv), Valueify(clasp));
3131 return false;
3133 return true;
3136 JS_PUBLIC_API(JSBool)
3137 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
3139 AssertNoGC(cx);
3140 assertSameCompartment(cx, obj, v);
3141 return HasInstance(cx, obj, &v, bp);
3144 JS_PUBLIC_API(void *)
3145 JS_GetPrivate(JSObject *obj)
3147 /* This function can be called by a finalizer. */
3148 return obj->getPrivate();
3151 JS_PUBLIC_API(void)
3152 JS_SetPrivate(JSObject *obj, void *data)
3154 /* This function can be called by a finalizer. */
3155 obj->setPrivate(data);
3158 JS_PUBLIC_API(void *)
3159 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
3161 if (!JS_InstanceOf(cx, obj, clasp, argv))
3162 return NULL;
3163 return obj->getPrivate();
3166 JS_PUBLIC_API(JSObject *)
3167 JS_GetPrototype(JSObject *obj)
3169 return obj->getProto();
3172 JS_PUBLIC_API(JSBool)
3173 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
3175 AssertNoGC(cx);
3176 CHECK_REQUEST(cx);
3177 assertSameCompartment(cx, obj, proto);
3178 return SetProto(cx, RootedVarObject(cx, obj), RootedVarObject(cx, proto), JS_FALSE);
3181 JS_PUBLIC_API(JSObject *)
3182 JS_GetParent(JSObject *obj)
3184 JS_ASSERT(!obj->isScope());
3185 return obj->getParent();
3188 JS_PUBLIC_API(JSBool)
3189 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
3191 AssertNoGC(cx);
3192 CHECK_REQUEST(cx);
3193 JS_ASSERT(!obj->isScope());
3194 JS_ASSERT(parent || !obj->getParent());
3195 assertSameCompartment(cx, obj, parent);
3196 return JSObject::setParent(cx, RootedVarObject(cx, obj), RootedVarObject(cx, parent));
3199 JS_PUBLIC_API(JSObject *)
3200 JS_GetConstructor(JSContext *cx, JSObject *proto)
3202 Value cval;
3204 AssertNoGC(cx);
3205 CHECK_REQUEST(cx);
3206 assertSameCompartment(cx, proto);
3208 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3210 if (!proto->getProperty(cx, cx->runtime->atomState.constructorAtom, &cval))
3211 return NULL;
3213 if (!IsFunctionObject(cval)) {
3214 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
3215 proto->getClass()->name);
3216 return NULL;
3218 return &cval.toObject();
3221 JS_PUBLIC_API(JSBool)
3222 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
3224 AssertNoGC(cx);
3225 assertSameCompartment(cx, obj);
3226 *idp = OBJECT_TO_JSID(obj);
3227 return JS_TRUE;
3230 JS_PUBLIC_API(JSObject *)
3231 JS_NewGlobalObject(JSContext *cx, JSClass *clasp)
3233 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
3234 AssertNoGC(cx);
3235 CHECK_REQUEST(cx);
3237 return GlobalObject::create(cx, Valueify(clasp));
3240 class AutoHoldCompartment {
3241 public:
3242 explicit AutoHoldCompartment(JSCompartment *compartment JS_GUARD_OBJECT_NOTIFIER_PARAM)
3243 : holdp(&compartment->hold)
3245 JS_GUARD_OBJECT_NOTIFIER_INIT;
3246 *holdp = true;
3249 ~AutoHoldCompartment() {
3250 *holdp = false;
3252 private:
3253 bool *holdp;
3254 JS_DECL_USE_GUARD_OBJECT_NOTIFIER
3257 JS_PUBLIC_API(JSObject *)
3258 JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals)
3260 AssertNoGC(cx);
3261 CHECK_REQUEST(cx);
3262 JSCompartment *compartment = NewCompartment(cx, principals);
3263 if (!compartment)
3264 return NULL;
3266 AutoHoldCompartment hold(compartment);
3268 JSCompartment *saved = cx->compartment;
3269 cx->setCompartment(compartment);
3270 JSObject *obj = JS_NewGlobalObject(cx, clasp);
3271 cx->setCompartment(saved);
3273 return obj;
3276 JS_PUBLIC_API(JSObject *)
3277 JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
3279 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
3280 AssertNoGC(cx);
3281 CHECK_REQUEST(cx);
3282 assertSameCompartment(cx, proto, parent);
3284 Class *clasp = Valueify(jsclasp);
3285 if (!clasp)
3286 clasp = &ObjectClass; /* default class is Object */
3288 JS_ASSERT(clasp != &FunctionClass);
3289 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
3291 if (proto && !proto->setNewTypeUnknown(cx))
3292 return NULL;
3294 JSObject *obj = NewObjectWithClassProto(cx, clasp, proto, parent);
3295 if (obj) {
3296 if (clasp->ext.equality)
3297 MarkTypeObjectFlags(cx, obj, OBJECT_FLAG_SPECIAL_EQUALITY);
3298 MarkTypeObjectUnknownProperties(cx, obj->type());
3301 JS_ASSERT_IF(obj, obj->getParent());
3302 return obj;
3305 JS_PUBLIC_API(JSObject *)
3306 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
3308 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
3309 AssertNoGC(cx);
3310 CHECK_REQUEST(cx);
3311 assertSameCompartment(cx, proto, parent);
3313 Class *clasp = Valueify(jsclasp);
3314 if (!clasp)
3315 clasp = &ObjectClass; /* default class is Object */
3317 JS_ASSERT(clasp != &FunctionClass);
3318 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
3320 JSObject *obj = NewObjectWithGivenProto(cx, clasp, proto, parent);
3321 if (obj)
3322 MarkTypeObjectUnknownProperties(cx, obj->type());
3323 return obj;
3326 JS_PUBLIC_API(JSObject *)
3327 JS_NewObjectForConstructor(JSContext *cx, JSClass *clasp, const jsval *vp)
3329 AssertNoGC(cx);
3330 CHECK_REQUEST(cx);
3331 assertSameCompartment(cx, *vp);
3333 return js_CreateThis(cx, Valueify(clasp), JSVAL_TO_OBJECT(*vp));
3336 JS_PUBLIC_API(JSBool)
3337 JS_IsExtensible(JSObject *obj)
3339 return obj->isExtensible();
3342 JS_PUBLIC_API(JSBool)
3343 JS_IsNative(JSObject *obj)
3345 return obj->isNative();
3348 JS_PUBLIC_API(JSRuntime *)
3349 JS_GetObjectRuntime(JSObject *obj)
3351 return obj->compartment()->rt;
3354 JS_PUBLIC_API(JSBool)
3355 JS_FreezeObject(JSContext *cx, JSObject *obj)
3357 AssertNoGC(cx);
3358 CHECK_REQUEST(cx);
3359 assertSameCompartment(cx, obj);
3361 return obj->freeze(cx);
3364 JS_PUBLIC_API(JSBool)
3365 JS_DeepFreezeObject(JSContext *cx, JSObject *obj)
3367 AssertNoGC(cx);
3368 CHECK_REQUEST(cx);
3369 assertSameCompartment(cx, obj);
3371 /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */
3372 if (!obj->isExtensible())
3373 return true;
3375 if (!obj->freeze(cx))
3376 return false;
3378 /* Walk slots in obj and if any value is a non-null object, seal it. */
3379 for (uint32_t i = 0, n = obj->slotSpan(); i < n; ++i) {
3380 const Value &v = obj->getSlot(i);
3381 if (v.isPrimitive())
3382 continue;
3383 if (!JS_DeepFreezeObject(cx, &v.toObject()))
3384 return false;
3387 return true;
3390 JS_PUBLIC_API(JSObject *)
3391 JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *parent)
3393 return JS_ConstructObjectWithArguments(cx, jsclasp, parent, 0, NULL);
3396 JS_PUBLIC_API(JSObject *)
3397 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *parent,
3398 unsigned argc, jsval *argv)
3400 AssertNoGC(cx);
3401 CHECK_REQUEST(cx);
3402 assertSameCompartment(cx, parent, JSValueArray(argv, argc));
3404 AutoArrayRooter argtvr(cx, argc, argv);
3406 Class *clasp = Valueify(jsclasp);
3407 if (!clasp)
3408 clasp = &ObjectClass; /* default class is Object */
3410 JSProtoKey protoKey = GetClassProtoKey(clasp);
3412 /* Protect constructor in case a crazy getter for .prototype uproots it. */
3413 RootedVarValue value(cx);
3414 if (!js_FindClassObject(cx, parent, protoKey, value.address(), clasp))
3415 return NULL;
3417 Value rval;
3418 if (!InvokeConstructor(cx, value, argc, argv, &rval))
3419 return NULL;
3422 * If the instance's class differs from what was requested, throw a type
3423 * error.
3425 if (!rval.isObject() || rval.toObject().getClass() != clasp) {
3426 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3427 JSMSG_WRONG_CONSTRUCTOR, clasp->name);
3428 return NULL;
3430 return &rval.toObject();
3433 static JSBool
3434 LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
3435 JSObject **objp, JSProperty **propp)
3437 AssertNoGC(cx);
3438 CHECK_REQUEST(cx);
3439 assertSameCompartment(cx, obj, id);
3441 JSAutoResolveFlags rf(cx, flags);
3442 return obj->lookupGeneric(cx, id, objp, propp);
3445 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
3447 static JSBool
3448 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, jsid id,
3449 JSProperty *prop, Value *vp)
3451 if (!prop) {
3452 /* XXX bad API: no way to tell "not defined" from "void value" */
3453 vp->setUndefined();
3454 return JS_TRUE;
3457 if (obj2->isNative()) {
3458 Shape *shape = (Shape *) prop;
3460 /* Peek at the native property's slot value, without doing a Get. */
3461 if (shape->hasSlot()) {
3462 *vp = obj2->nativeGetSlot(shape->slot());
3463 return true;
3465 } else {
3466 if (obj2->isDenseArray())
3467 return js_GetDenseArrayElementValue(cx, obj2, id, vp);
3468 if (obj2->isProxy()) {
3469 AutoPropertyDescriptorRooter desc(cx);
3470 if (!Proxy::getPropertyDescriptor(cx, obj2, id, false, &desc))
3471 return false;
3472 if (!(desc.attrs & JSPROP_SHARED)) {
3473 *vp = desc.value;
3474 return true;
3479 /* XXX bad API: no way to return "defined but value unknown" */
3480 vp->setBoolean(true);
3481 return true;
3484 JS_PUBLIC_API(JSBool)
3485 JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3487 JSObject *obj2;
3488 JSProperty *prop;
3489 return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) &&
3490 LookupResult(cx, obj, obj2, id, prop, vp);
3493 JS_PUBLIC_API(JSBool)
3494 JS_LookupElement(JSContext *cx, JSObject *obj, uint32_t index, jsval *vp)
3496 CHECK_REQUEST(cx);
3497 jsid id;
3498 if (!IndexToId(cx, index, &id))
3499 return false;
3500 return JS_LookupPropertyById(cx, obj, id, vp);
3503 JS_PUBLIC_API(JSBool)
3504 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3506 JSAtom *atom = js_Atomize(cx, name, strlen(name));
3507 return atom && JS_LookupPropertyById(cx, obj, AtomToId(atom), vp);
3510 JS_PUBLIC_API(JSBool)
3511 JS_LookupUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3513 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
3514 return atom && JS_LookupPropertyById(cx, obj, AtomToId(atom), vp);
3517 JS_PUBLIC_API(JSBool)
3518 JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
3519 JSObject **objp, jsval *vp)
3521 JSBool ok;
3522 JSProperty *prop;
3524 AssertNoGC(cx);
3525 CHECK_REQUEST(cx);
3526 assertSameCompartment(cx, obj, id);
3527 ok = obj->isNative()
3528 ? LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop)
3529 : obj->lookupGeneric(cx, id, objp, &prop);
3530 return ok && LookupResult(cx, obj, *objp, id, prop, vp);
3533 JS_PUBLIC_API(JSBool)
3534 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, unsigned flags, jsval *vp)
3536 JSObject *obj2;
3537 JSAtom *atom = js_Atomize(cx, name, strlen(name));
3538 return atom && JS_LookupPropertyWithFlagsById(cx, obj, AtomToId(atom), flags, &obj2, vp);
3541 JS_PUBLIC_API(JSBool)
3542 JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3544 JSObject *obj2;
3545 JSProperty *prop;
3546 JSBool ok = LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3547 &obj2, &prop);
3548 *foundp = (prop != NULL);
3549 return ok;
3552 JS_PUBLIC_API(JSBool)
3553 JS_HasElement(JSContext *cx, JSObject *obj, uint32_t index, JSBool *foundp)
3555 AssertNoGC(cx);
3556 CHECK_REQUEST(cx);
3557 jsid id;
3558 if (!IndexToId(cx, index, &id))
3559 return false;
3560 return JS_HasPropertyById(cx, obj, id, foundp);
3563 JS_PUBLIC_API(JSBool)
3564 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3566 JSAtom *atom = js_Atomize(cx, name, strlen(name));
3567 return atom && JS_HasPropertyById(cx, obj, AtomToId(atom), foundp);
3570 JS_PUBLIC_API(JSBool)
3571 JS_HasUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, JSBool *foundp)
3573 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
3574 return atom && JS_HasPropertyById(cx, obj, AtomToId(atom), foundp);
3577 JS_PUBLIC_API(JSBool)
3578 JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3580 AssertNoGC(cx);
3581 CHECK_REQUEST(cx);
3582 assertSameCompartment(cx, obj, id);
3584 if (!obj->isNative()) {
3585 JSObject *obj2;
3586 JSProperty *prop;
3588 if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3589 &obj2, &prop)) {
3590 return JS_FALSE;
3592 *foundp = (obj == obj2);
3593 return JS_TRUE;
3596 *foundp = obj->nativeContains(cx, id);
3597 return JS_TRUE;
3600 JS_PUBLIC_API(JSBool)
3601 JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, uint32_t index, JSBool *foundp)
3603 AssertNoGC(cx);
3604 CHECK_REQUEST(cx);
3605 jsid id;
3606 if (!IndexToId(cx, index, &id))
3607 return false;
3608 return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
3611 JS_PUBLIC_API(JSBool)
3612 JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3614 JSAtom *atom = js_Atomize(cx, name, strlen(name));
3615 return atom && JS_AlreadyHasOwnPropertyById(cx, obj, AtomToId(atom), foundp);
3618 JS_PUBLIC_API(JSBool)
3619 JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3620 JSBool *foundp)
3622 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
3623 return atom && JS_AlreadyHasOwnPropertyById(cx, obj, AtomToId(atom), foundp);
3626 static JSBool
3627 DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
3628 PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
3629 unsigned flags, int tinyid)
3632 * JSPROP_READONLY has no meaning when accessors are involved. Ideally we'd
3633 * throw if this happens, but we've accepted it for long enough that it's
3634 * not worth trying to make callers change their ways. Just flip it off on
3635 * its way through the API layer so that we can enforce this internally.
3637 if (attrs & (JSPROP_GETTER | JSPROP_SETTER))
3638 attrs &= ~JSPROP_READONLY;
3641 * When we use DefineProperty, we need full scriptable Function objects rather
3642 * than JSNatives. However, we might be pulling this property descriptor off
3643 * of something with JSNative property descriptors. If we are, wrap them in
3644 * JS Function objects.
3646 if (attrs & JSPROP_NATIVE_ACCESSORS) {
3647 JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
3648 attrs &= ~JSPROP_NATIVE_ACCESSORS;
3649 if (getter) {
3650 JSObject *getobj = JS_NewFunction(cx, (Native) getter, 0, 0, &obj->global(), NULL);
3651 if (!getobj)
3652 return false;
3653 getter = JS_DATA_TO_FUNC_PTR(PropertyOp, getobj);
3654 attrs |= JSPROP_GETTER;
3656 if (setter) {
3657 RootObject getRoot(cx, (JSObject **) &getter);
3658 JSObject *setobj = JS_NewFunction(cx, (Native) setter, 1, 0, &obj->global(), NULL);
3659 if (!setobj)
3660 return false;
3661 setter = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setobj);
3662 attrs |= JSPROP_SETTER;
3667 AssertNoGC(cx);
3668 CHECK_REQUEST(cx);
3669 assertSameCompartment(cx, obj, id, value,
3670 (attrs & JSPROP_GETTER)
3671 ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
3672 : NULL,
3673 (attrs & JSPROP_SETTER)
3674 ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
3675 : NULL);
3677 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
3678 if (flags != 0 && obj->isNative()) {
3679 return !!DefineNativeProperty(cx, obj, id, value, getter, setter,
3680 attrs, flags, tinyid);
3682 return obj->defineGeneric(cx, id, value, getter, setter, attrs);
3685 JS_PUBLIC_API(JSBool)
3686 JS_DefinePropertyById(JSContext *cx, JSObject *obj_, jsid id_, jsval value_,
3687 JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
3689 RootedVarObject obj(cx, obj_);
3690 RootedVarId id(cx, id_);
3691 RootedVarValue value(cx, value_);
3692 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, 0, 0);
3695 JS_PUBLIC_API(JSBool)
3696 JS_DefineElement(JSContext *cx, JSObject *obj_, uint32_t index, jsval value_,
3697 JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
3699 RootedVarObject obj(cx, obj_);
3700 RootedVarValue value(cx, value_);
3701 RootGetterSetter gsRoot(cx, attrs, &getter, &setter);
3702 AssertNoGC(cx);
3703 CHECK_REQUEST(cx);
3704 RootedVarId id(cx);
3705 if (!IndexToId(cx, index, id.address()))
3706 return false;
3707 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, 0, 0);
3710 static JSBool
3711 DefineProperty(JSContext *cx, JSObject *obj_, const char *name, const Value &value_,
3712 PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
3713 unsigned flags, int tinyid)
3715 RootedVarObject obj(cx, obj_);
3716 RootedVarValue value(cx, value_);
3717 RootGetterSetter gsRoot(cx, attrs, &getter, &setter);
3718 RootedVarId id(cx);
3720 if (attrs & JSPROP_INDEX) {
3721 id = INT_TO_JSID(intptr_t(name));
3722 attrs &= ~JSPROP_INDEX;
3723 } else {
3724 JSAtom *atom = js_Atomize(cx, name, strlen(name));
3725 if (!atom)
3726 return JS_FALSE;
3727 id = AtomToId(atom);
3730 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid);
3733 JS_PUBLIC_API(JSBool)
3734 JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
3735 PropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
3737 return DefineProperty(cx, obj, name, value, getter, setter, attrs, 0, 0);
3740 JS_PUBLIC_API(JSBool)
3741 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, int8_t tinyid,
3742 jsval value, PropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
3744 return DefineProperty(cx, obj, name, value, getter, setter, attrs, Shape::HAS_SHORTID, tinyid);
3747 static JSBool
3748 DefineUCProperty(JSContext *cx, JSObject *obj_, const jschar *name, size_t namelen,
3749 const Value &value_, PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
3750 unsigned flags, int tinyid)
3752 RootedVarObject obj(cx, obj_);
3753 RootedVarValue value(cx, value_);
3754 RootGetterSetter gsRoot(cx, attrs, &getter, &setter);
3755 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
3756 if (!atom)
3757 return false;
3758 RootedVarId id(cx, AtomToId(atom));
3759 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid);
3762 JS_PUBLIC_API(JSBool)
3763 JS_DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3764 jsval value, JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
3766 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0, 0);
3769 JS_PUBLIC_API(JSBool)
3770 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3771 int8_t tinyid, jsval value,
3772 JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
3774 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs,
3775 Shape::HAS_SHORTID, tinyid);
3778 JS_PUBLIC_API(JSBool)
3779 JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp)
3781 AssertNoGC(cx);
3782 CHECK_REQUEST(cx);
3783 assertSameCompartment(cx, obj, id, descriptor);
3784 return js_DefineOwnProperty(cx, RootedVarObject(cx, obj), RootedVarId(cx, id), descriptor, bp);
3787 JS_PUBLIC_API(JSObject *)
3788 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp,
3789 JSObject *proto, unsigned attrs)
3791 AssertNoGC(cx);
3792 CHECK_REQUEST(cx);
3793 assertSameCompartment(cx, obj, proto);
3795 Class *clasp = Valueify(jsclasp);
3796 if (!clasp)
3797 clasp = &ObjectClass; /* default class is Object */
3799 RootObject root(cx, &obj);
3800 RootedVarObject nobj(cx);
3802 nobj = NewObjectWithClassProto(cx, clasp, proto, obj);
3803 if (!nobj)
3804 return NULL;
3806 if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
3807 return NULL;
3809 return nobj;
3812 JS_PUBLIC_API(JSBool)
3813 JS_DefineConstDoubles(JSContext *cx, JSObject *obj_, JSConstDoubleSpec *cds)
3815 RootedVarObject obj(cx, obj_);
3817 JSBool ok;
3818 unsigned attrs;
3820 AssertNoGC(cx);
3821 CHECK_REQUEST(cx);
3822 for (ok = JS_TRUE; cds->name; cds++) {
3823 Value value = DoubleValue(cds->dval);
3824 attrs = cds->flags;
3825 if (!attrs)
3826 attrs = JSPROP_READONLY | JSPROP_PERMANENT;
3827 ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
3828 if (!ok)
3829 break;
3831 return ok;
3834 JS_PUBLIC_API(JSBool)
3835 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
3837 JSBool ok;
3838 RootObject root(cx, &obj);
3840 for (ok = true; ps->name; ps++) {
3841 ok = DefineProperty(cx, obj, ps->name, UndefinedValue(), ps->getter, ps->setter,
3842 ps->flags, Shape::HAS_SHORTID, ps->tinyid);
3843 if (!ok)
3844 break;
3846 return ok;
3849 static JSBool
3850 GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
3851 JSBool own, PropertyDescriptor *desc)
3853 JSObject *obj2;
3854 JSProperty *prop;
3856 if (!LookupPropertyById(cx, obj, id, flags, &obj2, &prop))
3857 return JS_FALSE;
3859 if (!prop || (own && obj != obj2)) {
3860 desc->obj = NULL;
3861 desc->attrs = 0;
3862 desc->getter = NULL;
3863 desc->setter = NULL;
3864 desc->value.setUndefined();
3865 return JS_TRUE;
3868 desc->obj = obj2;
3869 if (obj2->isNative()) {
3870 Shape *shape = (Shape *) prop;
3871 desc->attrs = shape->attributes();
3872 desc->getter = shape->getter();
3873 desc->setter = shape->setter();
3874 if (shape->hasSlot())
3875 desc->value = obj2->nativeGetSlot(shape->slot());
3876 else
3877 desc->value.setUndefined();
3878 } else {
3879 if (obj2->isProxy()) {
3880 JSAutoResolveFlags rf(cx, flags);
3881 return own
3882 ? Proxy::getOwnPropertyDescriptor(cx, obj2, id, false, desc)
3883 : Proxy::getPropertyDescriptor(cx, obj2, id, false, desc);
3885 if (!obj2->getGenericAttributes(cx, id, &desc->attrs))
3886 return false;
3887 desc->getter = NULL;
3888 desc->setter = NULL;
3889 desc->value.setUndefined();
3891 return true;
3894 JS_PUBLIC_API(JSBool)
3895 JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
3896 JSPropertyDescriptor *desc)
3898 return GetPropertyDescriptorById(cx, obj, id, flags, JS_FALSE, desc);
3901 JS_PUBLIC_API(JSBool)
3902 JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *obj, jsid id,
3903 unsigned *attrsp, JSBool *foundp,
3904 JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
3906 PropertyDescriptor desc;
3907 if (!GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, JS_FALSE, &desc))
3908 return false;
3910 *attrsp = desc.attrs;
3911 *foundp = (desc.obj != NULL);
3912 if (getterp)
3913 *getterp = desc.getter;
3914 if (setterp)
3915 *setterp = desc.setter;
3916 return true;
3919 JS_PUBLIC_API(JSBool)
3920 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3921 unsigned *attrsp, JSBool *foundp)
3923 JSAtom *atom = js_Atomize(cx, name, strlen(name));
3924 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, AtomToId(atom),
3925 attrsp, foundp, NULL, NULL);
3928 JS_PUBLIC_API(JSBool)
3929 JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3930 unsigned *attrsp, JSBool *foundp)
3932 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
3933 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, AtomToId(atom),
3934 attrsp, foundp, NULL, NULL);
3937 JS_PUBLIC_API(JSBool)
3938 JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, const char *name,
3939 unsigned *attrsp, JSBool *foundp,
3940 JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
3942 JSAtom *atom = js_Atomize(cx, name, strlen(name));
3943 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, AtomToId(atom),
3944 attrsp, foundp, getterp, setterp);
3947 JS_PUBLIC_API(JSBool)
3948 JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
3949 const jschar *name, size_t namelen,
3950 unsigned *attrsp, JSBool *foundp,
3951 JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
3953 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
3954 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, AtomToId(atom),
3955 attrsp, foundp, getterp, setterp);
3958 JS_PUBLIC_API(JSBool)
3959 JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3961 AssertNoGC(cx);
3962 CHECK_REQUEST(cx);
3963 return GetOwnPropertyDescriptor(cx, RootedVarObject(cx, obj), RootedVarId(cx, id), vp);
3966 static JSBool
3967 SetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, unsigned attrs, JSBool *foundp)
3969 JSObject *obj2;
3970 JSProperty *prop;
3972 if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
3973 return false;
3974 if (!prop || obj != obj2) {
3975 *foundp = false;
3976 return true;
3978 Shape *shape = (Shape *) prop;
3979 JSBool ok = obj->isNative()
3980 ? obj->changePropertyAttributes(cx, shape, attrs)
3981 : obj->setGenericAttributes(cx, id, &attrs);
3982 if (ok)
3983 *foundp = true;
3984 return ok;
3987 JS_PUBLIC_API(JSBool)
3988 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3989 unsigned attrs, JSBool *foundp)
3991 JSAtom *atom = js_Atomize(cx, name, strlen(name));
3992 return atom && SetPropertyAttributesById(cx, obj, AtomToId(atom), attrs, foundp);
3995 JS_PUBLIC_API(JSBool)
3996 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3997 unsigned attrs, JSBool *foundp)
3999 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
4000 return atom && SetPropertyAttributesById(cx, obj, AtomToId(atom), attrs, foundp);
4003 JS_PUBLIC_API(JSBool)
4004 JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
4006 return JS_ForwardGetPropertyTo(cx, obj, id, obj, vp);
4009 JS_PUBLIC_API(JSBool)
4010 JS_ForwardGetPropertyTo(JSContext *cx, JSObject *obj, jsid id, JSObject *onBehalfOf, jsval *vp)
4012 AssertNoGC(cx);
4013 CHECK_REQUEST(cx);
4014 assertSameCompartment(cx, obj, id);
4015 assertSameCompartment(cx, onBehalfOf);
4016 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
4017 return obj->getGeneric(cx, onBehalfOf, id, vp);
4020 JS_PUBLIC_API(JSBool)
4021 JS_GetPropertyByIdDefault(JSContext *cx, JSObject *obj, jsid id, jsval def, jsval *vp)
4023 return GetPropertyDefault(cx, RootedVarObject(cx, obj), RootedVarId(cx, id), def, vp);
4026 JS_PUBLIC_API(JSBool)
4027 JS_GetElement(JSContext *cx, JSObject *obj, uint32_t index, jsval *vp)
4029 return JS_ForwardGetElementTo(cx, obj, index, obj, vp);
4032 JS_PUBLIC_API(JSBool)
4033 JS_ForwardGetElementTo(JSContext *cx, JSObject *obj, uint32_t index, JSObject *onBehalfOf, jsval *vp)
4035 AssertNoGC(cx);
4036 CHECK_REQUEST(cx);
4037 assertSameCompartment(cx, obj);
4038 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
4039 return obj->getElement(cx, onBehalfOf, index, vp);
4042 JS_PUBLIC_API(JSBool)
4043 JS_GetElementIfPresent(JSContext *cx, JSObject *obj, uint32_t index, JSObject *onBehalfOf, jsval *vp, JSBool* present)
4045 AssertNoGC(cx);
4046 CHECK_REQUEST(cx);
4047 assertSameCompartment(cx, obj);
4048 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
4049 bool isPresent;
4050 if (!obj->getElementIfPresent(cx, onBehalfOf, index, vp, &isPresent))
4051 return false;
4052 *present = isPresent;
4053 return true;
4056 JS_PUBLIC_API(JSBool)
4057 JS_GetProperty(JSContext *cx, JSObject *obj_, const char *name, jsval *vp)
4059 RootedVarObject obj(cx, obj_);
4060 JSAtom *atom = js_Atomize(cx, name, strlen(name));
4061 return atom && JS_GetPropertyById(cx, obj, AtomToId(atom), vp);
4064 JS_PUBLIC_API(JSBool)
4065 JS_GetPropertyDefault(JSContext *cx, JSObject *obj_, const char *name, jsval def, jsval *vp)
4067 RootedVarObject obj(cx, obj_);
4068 JSAtom *atom = js_Atomize(cx, name, strlen(name));
4069 return atom && JS_GetPropertyByIdDefault(cx, obj, AtomToId(atom), def, vp);
4072 JS_PUBLIC_API(JSBool)
4073 JS_GetUCProperty(JSContext *cx, JSObject *obj_, const jschar *name, size_t namelen, jsval *vp)
4075 RootedVarObject obj(cx, obj_);
4076 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
4077 return atom && JS_GetPropertyById(cx, obj, AtomToId(atom), vp);
4080 JS_PUBLIC_API(JSBool)
4081 JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval *vp)
4083 AssertNoGC(cx);
4084 CHECK_REQUEST(cx);
4085 assertSameCompartment(cx, obj, id);
4086 if (!js_GetMethod(cx, RootedVarObject(cx, obj), id, 0, vp))
4087 return JS_FALSE;
4088 if (objp)
4089 *objp = obj;
4090 return JS_TRUE;
4093 JS_PUBLIC_API(JSBool)
4094 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, jsval *vp)
4096 JSAtom *atom = js_Atomize(cx, name, strlen(name));
4097 return atom && JS_GetMethodById(cx, obj, AtomToId(atom), objp, vp);
4100 JS_PUBLIC_API(JSBool)
4101 JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
4103 AssertNoGC(cx);
4104 CHECK_REQUEST(cx);
4105 assertSameCompartment(cx, obj, id);
4106 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
4107 return obj->setGeneric(cx, id, vp, false);
4110 JS_PUBLIC_API(JSBool)
4111 JS_SetElement(JSContext *cx, JSObject *obj_, uint32_t index, jsval *vp)
4113 AssertNoGC(cx);
4114 CHECK_REQUEST(cx);
4115 assertSameCompartment(cx, obj_, *vp);
4116 RootedVarObject obj(cx, obj_);
4117 RootValue vpRoot(cx, vp);
4118 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
4119 return obj->setElement(cx, index, vp, false);
4122 JS_PUBLIC_API(JSBool)
4123 JS_SetProperty(JSContext *cx, JSObject *obj_, const char *name, jsval *vp)
4125 RootedVarObject obj(cx, obj_);
4126 RootValue vpRoot(cx, vp);
4127 JSAtom *atom = js_Atomize(cx, name, strlen(name));
4128 return atom && JS_SetPropertyById(cx, obj, AtomToId(atom), vp);
4131 JS_PUBLIC_API(JSBool)
4132 JS_SetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
4134 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
4135 return atom && JS_SetPropertyById(cx, obj, AtomToId(atom), vp);
4138 JS_PUBLIC_API(JSBool)
4139 JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
4141 AssertNoGC(cx);
4142 CHECK_REQUEST(cx);
4143 assertSameCompartment(cx, obj, id);
4144 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
4146 if (JSID_IS_SPECIAL(id))
4147 return obj->deleteSpecial(cx, JSID_TO_SPECIALID(id), rval, false);
4149 return obj->deleteByValue(cx, IdToValue(id), rval, false);
4152 JS_PUBLIC_API(JSBool)
4153 JS_DeleteElement2(JSContext *cx, JSObject *obj, uint32_t index, jsval *rval)
4155 AssertNoGC(cx);
4156 CHECK_REQUEST(cx);
4157 assertSameCompartment(cx, obj);
4158 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
4159 return obj->deleteElement(cx, index, rval, false);
4162 JS_PUBLIC_API(JSBool)
4163 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name, jsval *rval)
4165 CHECK_REQUEST(cx);
4166 assertSameCompartment(cx, obj);
4167 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
4169 JSAtom *atom = js_Atomize(cx, name, strlen(name));
4170 if (!atom)
4171 return false;
4173 return obj->deleteByValue(cx, StringValue(atom), rval, false);
4176 JS_PUBLIC_API(JSBool)
4177 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *rval)
4179 CHECK_REQUEST(cx);
4180 assertSameCompartment(cx, obj);
4181 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
4183 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
4184 if (!atom)
4185 return false;
4187 return obj->deleteByValue(cx, StringValue(atom), rval, false);
4190 JS_PUBLIC_API(JSBool)
4191 JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id)
4193 jsval junk;
4194 return JS_DeletePropertyById2(cx, obj, id, &junk);
4197 JS_PUBLIC_API(JSBool)
4198 JS_DeleteElement(JSContext *cx, JSObject *obj, uint32_t index)
4200 jsval junk;
4201 return JS_DeleteElement2(cx, obj, index, &junk);
4204 JS_PUBLIC_API(JSBool)
4205 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
4207 jsval junk;
4208 return JS_DeleteProperty2(cx, obj, name, &junk);
4211 JS_PUBLIC_API(void)
4212 JS_ClearScope(JSContext *cx, JSObject *obj)
4214 AssertNoGC(cx);
4215 CHECK_REQUEST(cx);
4216 assertSameCompartment(cx, obj);
4218 ClearOp clearOp = obj->getOps()->clear;
4219 if (clearOp)
4220 clearOp(cx, obj);
4222 if (obj->isNative())
4223 js_ClearNative(cx, obj);
4225 /* Clear cached class objects on the global object. */
4226 if (obj->isGlobal())
4227 obj->asGlobal().clear(cx);
4229 js_InitRandom(cx);
4232 JS_PUBLIC_API(JSIdArray *)
4233 JS_Enumerate(JSContext *cx, JSObject *obj)
4235 AssertNoGC(cx);
4236 CHECK_REQUEST(cx);
4237 assertSameCompartment(cx, obj);
4239 AutoIdVector props(cx);
4240 JSIdArray *ida;
4241 if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida))
4242 return NULL;
4243 return ida;
4247 * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
4248 * prop_iterator_class somehow...
4249 * + preserve the obj->enumerate API while optimizing the native object case
4250 * + native case here uses a Shape *, but that iterates in reverse!
4251 * + so we make non-native match, by reverse-iterating after JS_Enumerating
4253 const uint32_t JSSLOT_ITER_INDEX = 0;
4255 static void
4256 prop_iter_finalize(FreeOp *fop, JSObject *obj)
4258 void *pdata = obj->getPrivate();
4259 if (!pdata)
4260 return;
4262 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) {
4263 /* Non-native case: destroy the ida enumerated when obj was created. */
4264 JSIdArray *ida = (JSIdArray *) pdata;
4265 DestroyIdArray(fop, ida);
4269 static void
4270 prop_iter_trace(JSTracer *trc, JSObject *obj)
4272 void *pdata = obj->getPrivate();
4273 if (!pdata)
4274 return;
4276 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
4278 * Native case: just mark the next property to visit. We don't need a
4279 * barrier here because the pointer is updated via setPrivate, which
4280 * always takes a barrier.
4282 Shape *tmp = (Shape *)pdata;
4283 MarkShapeUnbarriered(trc, &tmp, "prop iter shape");
4284 obj->setPrivateUnbarriered(tmp);
4285 } else {
4286 /* Non-native case: mark each id in the JSIdArray private. */
4287 JSIdArray *ida = (JSIdArray *) pdata;
4288 MarkIdRange(trc, ida->length, ida->vector, "prop iter");
4292 static Class prop_iter_class = {
4293 "PropertyIterator",
4294 JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(1),
4295 JS_PropertyStub, /* addProperty */
4296 JS_PropertyStub, /* delProperty */
4297 JS_PropertyStub, /* getProperty */
4298 JS_StrictPropertyStub, /* setProperty */
4299 JS_EnumerateStub,
4300 JS_ResolveStub,
4301 JS_ConvertStub,
4302 prop_iter_finalize,
4303 NULL, /* checkAccess */
4304 NULL, /* call */
4305 NULL, /* construct */
4306 NULL, /* hasInstance */
4307 prop_iter_trace
4310 JS_PUBLIC_API(JSObject *)
4311 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
4313 JSObject *iterobj;
4314 void *pdata;
4315 int index;
4316 JSIdArray *ida;
4318 AssertNoGC(cx);
4319 CHECK_REQUEST(cx);
4320 assertSameCompartment(cx, obj);
4321 iterobj = NewObjectWithClassProto(cx, &prop_iter_class, NULL, obj);
4322 if (!iterobj)
4323 return NULL;
4325 if (obj->isNative()) {
4326 /* Native case: start with the last property in obj. */
4327 pdata = (void *)obj->lastProperty();
4328 index = -1;
4329 } else {
4331 * Non-native case: enumerate a JSIdArray and keep it via private.
4333 * Note: we have to make sure that we root obj around the call to
4334 * JS_Enumerate to protect against multiple allocations under it.
4336 ida = JS_Enumerate(cx, obj);
4337 if (!ida)
4338 return NULL;
4339 pdata = ida;
4340 index = ida->length;
4343 /* iterobj cannot escape to other threads here. */
4344 iterobj->setPrivate(pdata);
4345 iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(index));
4346 return iterobj;
4349 JS_PUBLIC_API(JSBool)
4350 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
4352 int32_t i;
4353 const Shape *shape;
4354 JSIdArray *ida;
4356 AssertNoGC(cx);
4357 CHECK_REQUEST(cx);
4358 assertSameCompartment(cx, iterobj);
4359 i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
4360 if (i < 0) {
4361 /* Native case: private data is a property tree node pointer. */
4362 JS_ASSERT(iterobj->getParent()->isNative());
4363 shape = (Shape *) iterobj->getPrivate();
4365 while (shape->previous() && !shape->enumerable())
4366 shape = shape->previous();
4368 if (!shape->previous()) {
4369 JS_ASSERT(shape->isEmptyShape());
4370 *idp = JSID_VOID;
4371 } else {
4372 iterobj->setPrivate(const_cast<Shape *>(shape->previous().get()));
4373 *idp = shape->propid();
4375 } else {
4376 /* Non-native case: use the ida enumerated when iterobj was created. */
4377 ida = (JSIdArray *) iterobj->getPrivate();
4378 JS_ASSERT(i <= ida->length);
4379 STATIC_ASSUME(i <= ida->length);
4380 if (i == 0) {
4381 *idp = JSID_VOID;
4382 } else {
4383 *idp = ida->vector[--i];
4384 iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i));
4387 return JS_TRUE;
4390 JS_PUBLIC_API(JSObject *)
4391 JS_NewElementIterator(JSContext *cx, JSObject *obj)
4393 AssertNoGC(cx);
4394 CHECK_REQUEST(cx);
4395 assertSameCompartment(cx, obj);
4396 return ElementIteratorObject::create(cx, RootedVarObject(cx, obj));
4399 JS_PUBLIC_API(JSObject *)
4400 JS_ElementIteratorStub(JSContext *cx, JSObject *obj, JSBool keysonly)
4402 JS_ASSERT(!keysonly);
4403 return JS_NewElementIterator(cx, obj);
4406 JS_PUBLIC_API(jsval)
4407 JS_GetReservedSlot(JSObject *obj, uint32_t index)
4409 return obj->getReservedSlot(index);
4412 JS_PUBLIC_API(void)
4413 JS_SetReservedSlot(JSObject *obj, uint32_t index, jsval v)
4415 obj->setReservedSlot(index, v);
4418 JS_PUBLIC_API(JSObject *)
4419 JS_NewArrayObject(JSContext *cx, int length, jsval *vector)
4421 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4422 AssertNoGC(cx);
4423 CHECK_REQUEST(cx);
4425 assertSameCompartment(cx, JSValueArray(vector, vector ? (uint32_t)length : 0));
4426 return NewDenseCopiedArray(cx, (uint32_t)length, vector);
4429 JS_PUBLIC_API(JSBool)
4430 JS_IsArrayObject(JSContext *cx, JSObject *obj)
4432 assertSameCompartment(cx, obj);
4433 return ObjectClassIs(*obj, ESClass_Array, cx);
4436 JS_PUBLIC_API(JSBool)
4437 JS_GetArrayLength(JSContext *cx, JSObject *obj, uint32_t *lengthp)
4439 AssertNoGC(cx);
4440 CHECK_REQUEST(cx);
4441 assertSameCompartment(cx, obj);
4442 return js_GetLengthProperty(cx, obj, lengthp);
4445 JS_PUBLIC_API(JSBool)
4446 JS_SetArrayLength(JSContext *cx, JSObject *obj, uint32_t length)
4448 AssertNoGC(cx);
4449 CHECK_REQUEST(cx);
4450 assertSameCompartment(cx, obj);
4451 return js_SetLengthProperty(cx, obj, length);
4454 JS_PUBLIC_API(JSBool)
4455 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
4456 jsval *vp, unsigned *attrsp)
4458 AssertNoGC(cx);
4459 CHECK_REQUEST(cx);
4460 assertSameCompartment(cx, obj, id);
4461 return CheckAccess(cx, obj, id, mode, vp, attrsp);
4464 JS_PUBLIC_API(void)
4465 JS_HoldPrincipals(JSPrincipals *principals)
4467 JS_ATOMIC_INCREMENT(&principals->refcount);
4470 JS_PUBLIC_API(void)
4471 JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals)
4473 int rc = JS_ATOMIC_DECREMENT(&principals->refcount);
4474 if (rc == 0)
4475 rt->destroyPrincipals(principals);
4478 JS_PUBLIC_API(void)
4479 JS_SetSecurityCallbacks(JSRuntime *rt, const JSSecurityCallbacks *scb)
4481 JS_ASSERT(scb != &NullSecurityCallbacks);
4482 rt->securityCallbacks = scb ? scb : &NullSecurityCallbacks;
4485 JS_PUBLIC_API(const JSSecurityCallbacks *)
4486 JS_GetSecurityCallbacks(JSRuntime *rt)
4488 return (rt->securityCallbacks != &NullSecurityCallbacks) ? rt->securityCallbacks : NULL;
4491 JS_PUBLIC_API(void)
4492 JS_SetTrustedPrincipals(JSRuntime *rt, JSPrincipals *prin)
4494 rt->setTrustedPrincipals(prin);
4497 extern JS_PUBLIC_API(void)
4498 JS_InitDestroyPrincipalsCallback(JSRuntime *rt, JSDestroyPrincipalsOp destroyPrincipals)
4500 JS_ASSERT(destroyPrincipals);
4501 JS_ASSERT(!rt->destroyPrincipals);
4502 rt->destroyPrincipals = destroyPrincipals;
4505 JS_PUBLIC_API(JSFunction *)
4506 JS_NewFunction(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
4507 JSObject *parent, const char *name)
4509 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4510 JSAtom *atom;
4512 AssertNoGC(cx);
4513 CHECK_REQUEST(cx);
4514 assertSameCompartment(cx, parent);
4516 if (!name) {
4517 atom = NULL;
4518 } else {
4519 atom = js_Atomize(cx, name, strlen(name));
4520 if (!atom)
4521 return NULL;
4524 RootObject parentRoot(cx, &parent);
4525 return js_NewFunction(cx, NULL, native, nargs, flags, parentRoot, atom);
4528 JS_PUBLIC_API(JSFunction *)
4529 JS_NewFunctionById(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parent,
4530 jsid id)
4532 JS_ASSERT(JSID_IS_STRING(id));
4533 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4534 AssertNoGC(cx);
4535 CHECK_REQUEST(cx);
4536 assertSameCompartment(cx, parent);
4538 RootObject parentRoot(cx, &parent);
4539 return js_NewFunction(cx, NULL, native, nargs, flags, parentRoot, JSID_TO_ATOM(id));
4542 JS_PUBLIC_API(JSObject *)
4543 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent_)
4545 AssertNoGC(cx);
4546 CHECK_REQUEST(cx);
4547 assertSameCompartment(cx, parent_); // XXX no funobj for now
4549 RootedVarObject parent(cx, parent_);
4551 if (!parent) {
4552 if (cx->hasfp())
4553 parent = cx->fp()->scopeChain();
4554 if (!parent)
4555 parent = cx->globalObject;
4556 JS_ASSERT(parent);
4559 if (!funobj->isFunction()) {
4561 * We cannot clone this object, so fail (we used to return funobj, bad
4562 * idea, but we changed incompatibly to teach any abusers a lesson!).
4564 Value v = ObjectValue(*funobj);
4565 js_ReportIsNotFunction(cx, &v, 0);
4566 return NULL;
4569 RootedVarFunction fun(cx, funobj->toFunction());
4570 if (fun->isInterpreted() && fun->script()->compileAndGo) {
4571 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4572 JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
4573 return NULL;
4577 return CloneFunctionObject(cx, fun, parent, fun->getAllocKind());
4580 JS_PUBLIC_API(JSObject *)
4581 JS_GetFunctionObject(JSFunction *fun)
4583 return fun;
4586 JS_PUBLIC_API(JSString *)
4587 JS_GetFunctionId(JSFunction *fun)
4589 return fun->atom;
4592 JS_PUBLIC_API(unsigned)
4593 JS_GetFunctionFlags(JSFunction *fun)
4595 return fun->flags;
4598 JS_PUBLIC_API(uint16_t)
4599 JS_GetFunctionArity(JSFunction *fun)
4601 return fun->nargs;
4604 JS_PUBLIC_API(JSBool)
4605 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
4607 return obj->isFunction();
4610 JS_PUBLIC_API(JSBool)
4611 JS_ObjectIsCallable(JSContext *cx, JSObject *obj)
4613 return obj->isCallable();
4616 JS_PUBLIC_API(JSBool)
4617 JS_IsNativeFunction(JSObject *funobj, JSNative call)
4619 if (!funobj->isFunction())
4620 return false;
4621 JSFunction *fun = funobj->toFunction();
4622 return fun->isNative() && fun->native() == call;
4625 JS_PUBLIC_API(JSObject*)
4626 JS_BindCallable(JSContext *cx, JSObject *callable, JSObject *newThis)
4628 RootedVarObject target(cx, callable);
4629 RootedVarValue thisArg(cx, ObjectValue(*newThis));
4630 return js_fun_bind(cx, target, thisArg, NULL, 0);
4633 JSBool
4634 js_generic_native_method_dispatcher(JSContext *cx, unsigned argc, Value *vp)
4636 JSFunctionSpec *fs = (JSFunctionSpec *)
4637 vp->toObject().toFunction()->getExtendedSlot(0).toPrivate();
4638 JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
4640 if (argc < 1) {
4641 js_ReportMissingArg(cx, *vp, 0);
4642 return JS_FALSE;
4646 * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
4647 * which is almost always the class constructor object, e.g. Array. Then
4648 * call the corresponding prototype native method with our first argument
4649 * passed as |this|.
4651 memmove(vp + 1, vp + 2, argc * sizeof(jsval));
4653 /* Clear the last parameter in case too few arguments were passed. */
4654 vp[2 + --argc].setUndefined();
4656 return fs->call(cx, argc, vp);
4659 JS_PUBLIC_API(JSBool)
4660 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
4662 RootObject objRoot(cx, &obj);
4664 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4665 unsigned flags;
4666 RootedVarObject ctor(cx);
4667 JSFunction *fun;
4669 AssertNoGC(cx);
4670 CHECK_REQUEST(cx);
4671 assertSameCompartment(cx, obj);
4672 for (; fs->name; fs++) {
4673 flags = fs->flags;
4675 JSAtom *atom = js_Atomize(cx, fs->name, strlen(fs->name));
4676 if (!atom)
4677 return JS_FALSE;
4680 * Define a generic arity N+1 static method for the arity N prototype
4681 * method if flags contains JSFUN_GENERIC_NATIVE.
4683 if (flags & JSFUN_GENERIC_NATIVE) {
4684 RootAtom root(cx, &atom);
4686 if (!ctor) {
4687 ctor = JS_GetConstructor(cx, obj);
4688 if (!ctor)
4689 return JS_FALSE;
4692 flags &= ~JSFUN_GENERIC_NATIVE;
4693 fun = js_DefineFunction(cx, ctor, AtomToId(atom),
4694 js_generic_native_method_dispatcher,
4695 fs->nargs + 1,
4696 flags,
4697 JSFunction::ExtendedFinalizeKind);
4698 if (!fun)
4699 return JS_FALSE;
4702 * As jsapi.h notes, fs must point to storage that lives as long
4703 * as fun->object lives.
4705 fun->setExtendedSlot(0, PrivateValue(fs));
4708 fun = js_DefineFunction(cx, objRoot,
4709 AtomToId(atom), fs->call, fs->nargs, flags);
4710 if (!fun)
4711 return JS_FALSE;
4713 return JS_TRUE;
4716 JS_PUBLIC_API(JSFunction *)
4717 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
4718 unsigned nargs, unsigned attrs)
4720 RootObject objRoot(cx, &obj);
4722 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4723 AssertNoGC(cx);
4724 CHECK_REQUEST(cx);
4725 assertSameCompartment(cx, obj);
4726 JSAtom *atom = js_Atomize(cx, name, strlen(name));
4727 if (!atom)
4728 return NULL;
4729 return js_DefineFunction(cx, objRoot, AtomToId(atom), call, nargs, attrs);
4732 JS_PUBLIC_API(JSFunction *)
4733 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
4734 const jschar *name, size_t namelen, JSNative call,
4735 unsigned nargs, unsigned attrs)
4737 RootObject objRoot(cx, &obj);
4739 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4740 AssertNoGC(cx);
4741 CHECK_REQUEST(cx);
4742 assertSameCompartment(cx, obj);
4743 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
4744 if (!atom)
4745 return NULL;
4746 return js_DefineFunction(cx, objRoot, AtomToId(atom), call, nargs, attrs);
4749 extern JS_PUBLIC_API(JSFunction *)
4750 JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call,
4751 unsigned nargs, unsigned attrs)
4753 RootObject objRoot(cx, &obj);
4755 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4756 AssertNoGC(cx);
4757 CHECK_REQUEST(cx);
4758 assertSameCompartment(cx, obj);
4759 return js_DefineFunction(cx, objRoot, id, call, nargs, attrs);
4762 struct AutoLastFrameCheck {
4763 AutoLastFrameCheck(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM)
4764 : cx(cx) {
4765 JS_ASSERT(cx);
4766 JS_GUARD_OBJECT_NOTIFIER_INIT;
4769 ~AutoLastFrameCheck() {
4770 if (cx->isExceptionPending() &&
4771 !JS_IsRunning(cx) &&
4772 !cx->hasRunOption(JSOPTION_DONT_REPORT_UNCAUGHT)) {
4773 js_ReportUncaughtException(cx);
4777 private:
4778 JSContext *cx;
4779 JS_DECL_USE_GUARD_OBJECT_NOTIFIER
4782 inline static uint32_t
4783 JS_OPTIONS_TO_TCFLAGS(JSContext *cx)
4785 return (cx->hasRunOption(JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) |
4786 (cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0);
4789 static JSScript *
4790 CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj,
4791 JSPrincipals *principals, JSPrincipals *originPrincipals,
4792 const jschar *chars, size_t length,
4793 const char *filename, unsigned lineno, JSVersion version)
4795 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4796 AssertNoGC(cx);
4797 CHECK_REQUEST(cx);
4798 assertSameCompartment(cx, obj, principals);
4799 AutoLastFrameCheck lfc(cx);
4801 uint32_t tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_SCRIPT_GLOBAL;
4802 return frontend::CompileScript(cx, obj, NULL, principals, originPrincipals, tcflags,
4803 chars, length, filename, lineno, version);
4806 extern JS_PUBLIC_API(JSScript *)
4807 JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4808 JSPrincipals *principals,
4809 const jschar *chars, size_t length,
4810 const char *filename, unsigned lineno,
4811 JSVersion version)
4813 AutoVersionAPI avi(cx, version);
4814 return CompileUCScriptForPrincipalsCommon(cx, obj, principals, NULL, chars, length,
4815 filename, lineno, avi.version());
4818 extern JS_PUBLIC_API(JSScript *)
4819 JS_CompileUCScriptForPrincipalsVersionOrigin(JSContext *cx, JSObject *obj,
4820 JSPrincipals *principals,
4821 JSPrincipals *originPrincipals,
4822 const jschar *chars, size_t length,
4823 const char *filename, unsigned lineno,
4824 JSVersion version)
4826 AutoVersionAPI avi(cx, version);
4827 return CompileUCScriptForPrincipalsCommon(cx, obj, principals, originPrincipals,
4828 chars, length, filename, lineno, avi.version());
4831 JS_PUBLIC_API(JSScript *)
4832 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4833 const jschar *chars, size_t length,
4834 const char *filename, unsigned lineno)
4836 return CompileUCScriptForPrincipalsCommon(cx, obj, principals, NULL, chars, length,
4837 filename, lineno, cx->findVersion());
4840 JS_PUBLIC_API(JSScript *)
4841 JS_CompileUCScript(JSContext *cx, JSObject *obj, const jschar *chars, size_t length,
4842 const char *filename, unsigned lineno)
4844 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4845 return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno);
4848 JS_PUBLIC_API(JSScript *)
4849 JS_CompileScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4850 JSPrincipals *principals,
4851 const char *bytes, size_t length,
4852 const char *filename, unsigned lineno,
4853 JSVersion version)
4855 AutoVersionAPI ava(cx, version);
4856 return JS_CompileScriptForPrincipals(cx, obj, principals, bytes, length, filename, lineno);
4859 JS_PUBLIC_API(JSScript *)
4860 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
4861 JSPrincipals *principals,
4862 const char *bytes, size_t length,
4863 const char *filename, unsigned lineno)
4865 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4866 AssertNoGC(cx);
4867 CHECK_REQUEST(cx);
4869 jschar *chars = InflateString(cx, bytes, &length);
4870 if (!chars)
4871 return NULL;
4872 JSScript *script =
4873 JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno);
4874 cx->free_(chars);
4875 return script;
4878 JS_PUBLIC_API(JSScript *)
4879 JS_CompileScript(JSContext *cx, JSObject *obj, const char *bytes, size_t length,
4880 const char *filename, unsigned lineno)
4882 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4883 return JS_CompileScriptForPrincipals(cx, obj, NULL, bytes, length, filename, lineno);
4886 JS_PUBLIC_API(JSBool)
4887 JS_BufferIsCompilableUnit(JSContext *cx, JSBool bytes_are_utf8, JSObject *obj, const char *bytes, size_t length)
4889 jschar *chars;
4890 JSBool result;
4891 JSExceptionState *exnState;
4892 JSErrorReporter older;
4894 AssertNoGC(cx);
4895 CHECK_REQUEST(cx);
4896 assertSameCompartment(cx, obj);
4897 if (bytes_are_utf8)
4898 chars = InflateString(cx, bytes, &length, CESU8Encoding);
4899 else
4900 chars = InflateString(cx, bytes, &length);
4901 if (!chars)
4902 return JS_TRUE;
4905 * Return true on any out-of-memory error, so our caller doesn't try to
4906 * collect more buffered source.
4908 result = JS_TRUE;
4909 exnState = JS_SaveExceptionState(cx);
4911 Parser parser(cx);
4912 if (parser.init(chars, length, NULL, 1, cx->findVersion())) {
4913 older = JS_SetErrorReporter(cx, NULL);
4914 if (!parser.parse(obj) &&
4915 parser.tokenStream.isUnexpectedEOF()) {
4917 * We ran into an error. If it was because we ran out of
4918 * source, we return false so our caller knows to try to
4919 * collect more buffered source.
4921 result = JS_FALSE;
4923 JS_SetErrorReporter(cx, older);
4926 cx->free_(chars);
4927 JS_RestoreExceptionState(cx, exnState);
4928 return result;
4931 /* Use the fastest available getc. */
4932 #if defined(HAVE_GETC_UNLOCKED)
4933 # define fast_getc getc_unlocked
4934 #elif defined(HAVE__GETC_NOLOCK)
4935 # define fast_getc _getc_nolock
4936 #else
4937 # define fast_getc getc
4938 #endif
4940 static JSScript *
4941 CompileUTF8FileHelper(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4942 const char* filename, FILE *fp)
4944 struct stat st;
4945 int ok = fstat(fileno(fp), &st);
4946 if (ok != 0)
4947 return NULL;
4949 char *buf = NULL;
4950 size_t len = st.st_size;
4951 size_t i = 0;
4952 JSScript *script;
4954 /* Read in the whole file, then compile it. */
4955 if (fp == stdin) {
4956 if (len == 0)
4957 len = 8; /* start with a small buffer, expand as necessary */
4959 int c;
4960 bool hitEOF = false;
4961 while (!hitEOF) {
4962 len *= 2;
4963 char* tmpbuf = (char *) cx->realloc_(buf, len * sizeof(char));
4964 if (!tmpbuf) {
4965 cx->free_(buf);
4966 return NULL;
4968 buf = tmpbuf;
4970 while (i < len) {
4971 c = fast_getc(fp);
4972 if (c == EOF) {
4973 hitEOF = true;
4974 break;
4976 buf[i++] = c;
4979 } else {
4980 buf = (char *) cx->malloc_(len * sizeof(char));
4981 if (!buf)
4982 return NULL;
4984 int c;
4985 // The |i < len| is necessary for files that lie about their length,
4986 // e.g. /dev/zero and /dev/random. See bug 669434.
4987 while (i < len && (c = fast_getc(fp)) != EOF)
4988 buf[i++] = c;
4991 JS_ASSERT(i <= len);
4992 len = i;
4993 size_t decodelen = len;
4994 jschar *decodebuf = (jschar *)cx->malloc_(decodelen * sizeof(jschar));
4995 if (JS_DecodeUTF8(cx, buf, len, decodebuf, &decodelen)) {
4996 uint32_t tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_SCRIPT_GLOBAL;
4997 script = frontend::CompileScript(cx, obj, NULL, principals, NULL,
4998 tcflags, decodebuf, decodelen,
4999 filename, 1, cx->findVersion());
5000 } else {
5001 script = NULL;
5003 cx->free_(buf);
5004 cx->free_(decodebuf);
5005 return script;
5008 JS_PUBLIC_API(JSScript *)
5009 JS_CompileUTF8File(JSContext *cx, JSObject *obj, const char *filename)
5011 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5012 AssertNoGC(cx);
5013 CHECK_REQUEST(cx);
5014 assertSameCompartment(cx, obj);
5015 AutoLastFrameCheck lfc(cx);
5017 FILE *fp;
5018 if (!filename || strcmp(filename, "-") == 0) {
5019 fp = stdin;
5020 } else {
5021 fp = fopen(filename, "r");
5022 if (!fp) {
5023 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
5024 filename, "No such file or directory");
5025 return NULL;
5029 JSScript *script = CompileUTF8FileHelper(cx, obj, NULL, filename, fp);
5030 if (fp != stdin)
5031 fclose(fp);
5032 return script;
5035 JS_PUBLIC_API(JSScript *)
5036 JS_CompileUTF8FileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *filename,
5037 FILE *file, JSPrincipals *principals)
5039 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5040 AssertNoGC(cx);
5041 CHECK_REQUEST(cx);
5042 assertSameCompartment(cx, obj, principals);
5043 AutoLastFrameCheck lfc(cx);
5045 return CompileUTF8FileHelper(cx, obj, principals, filename, file);
5048 JS_PUBLIC_API(JSScript *)
5049 JS_CompileUTF8FileHandleForPrincipalsVersion(JSContext *cx, JSObject *obj, const char *filename,
5050 FILE *file, JSPrincipals *principals, JSVersion version)
5052 AutoVersionAPI ava(cx, version);
5053 return JS_CompileUTF8FileHandleForPrincipals(cx, obj, filename, file, principals);
5056 JS_PUBLIC_API(JSScript *)
5057 JS_CompileUTF8FileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *file)
5059 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5060 return JS_CompileUTF8FileHandleForPrincipals(cx, obj, filename, file, NULL);
5063 JS_PUBLIC_API(JSObject *)
5064 JS_GetGlobalFromScript(JSScript *script)
5066 JS_ASSERT(!script->isCachedEval);
5067 JS_ASSERT(script->globalObject);
5069 return script->globalObject;
5072 static JSFunction *
5073 CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj,
5074 JSPrincipals *principals, const char *name,
5075 unsigned nargs, const char **argnames,
5076 const jschar *chars, size_t length,
5077 const char *filename, unsigned lineno, JSVersion version)
5079 RootObject objRoot(cx, &obj);
5081 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5082 AssertNoGC(cx);
5083 CHECK_REQUEST(cx);
5084 assertSameCompartment(cx, obj, principals);
5085 AutoLastFrameCheck lfc(cx);
5087 RootedVarAtom funAtom(cx);
5088 if (name) {
5089 funAtom = js_Atomize(cx, name, strlen(name));
5090 if (!funAtom)
5091 return NULL;
5094 Bindings bindings(cx);
5095 for (unsigned i = 0; i < nargs; i++) {
5096 uint16_t dummy;
5097 RootedVarAtom argAtom(cx, js_Atomize(cx, argnames[i], strlen(argnames[i])));
5098 if (!argAtom || !bindings.addArgument(cx, argAtom, &dummy))
5099 return NULL;
5102 JSFunction *fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, objRoot, funAtom);
5103 if (!fun)
5104 return NULL;
5106 if (!frontend::CompileFunctionBody(cx, fun, principals, NULL, &bindings,
5107 chars, length, filename, lineno, version))
5109 return NULL;
5112 if (obj && funAtom &&
5113 !obj->defineGeneric(cx, AtomToId(funAtom), ObjectValue(*fun), NULL, NULL,
5114 JSPROP_ENUMERATE))
5116 return NULL;
5119 return fun;
5122 JS_PUBLIC_API(JSFunction *)
5123 JS_CompileUCFunctionForPrincipalsVersion(JSContext *cx, JSObject *obj,
5124 JSPrincipals *principals, const char *name,
5125 unsigned nargs, const char **argnames,
5126 const jschar *chars, size_t length,
5127 const char *filename, unsigned lineno,
5128 JSVersion version)
5130 AutoVersionAPI avi(cx, version);
5131 return CompileUCFunctionForPrincipalsCommon(cx, obj, principals, name, nargs, argnames, chars,
5132 length, filename, lineno, avi.version());
5135 JS_PUBLIC_API(JSFunction *)
5136 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
5137 JSPrincipals *principals, const char *name,
5138 unsigned nargs, const char **argnames,
5139 const jschar *chars, size_t length,
5140 const char *filename, unsigned lineno)
5142 return CompileUCFunctionForPrincipalsCommon(cx, obj, principals, name, nargs, argnames, chars,
5143 length, filename, lineno, cx->findVersion());
5146 JS_PUBLIC_API(JSFunction *)
5147 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
5148 unsigned nargs, const char **argnames,
5149 const jschar *chars, size_t length,
5150 const char *filename, unsigned lineno)
5152 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5153 return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames,
5154 chars, length, filename, lineno);
5157 JS_PUBLIC_API(JSFunction *)
5158 JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
5159 JSPrincipals *principals, const char *name,
5160 unsigned nargs, const char **argnames,
5161 const char *bytes, size_t length,
5162 const char *filename, unsigned lineno)
5164 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5165 jschar *chars = InflateString(cx, bytes, &length);
5166 if (!chars)
5167 return NULL;
5168 JSFunction *fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
5169 nargs, argnames, chars, length,
5170 filename, lineno);
5171 cx->free_(chars);
5172 return fun;
5175 JS_PUBLIC_API(JSFunction *)
5176 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
5177 unsigned nargs, const char **argnames,
5178 const char *bytes, size_t length,
5179 const char *filename, unsigned lineno)
5181 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5182 return JS_CompileFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames, bytes, length,
5183 filename, lineno);
5186 JS_PUBLIC_API(JSString *)
5187 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, unsigned indent)
5189 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5190 JSPrinter *jp;
5191 JSString *str;
5193 AssertNoGC(cx);
5194 CHECK_REQUEST(cx);
5195 #ifdef DEBUG
5196 if (cx->compartment != script->compartment())
5197 CompartmentChecker::fail(cx->compartment, script->compartment());
5198 #endif
5199 jp = js_NewPrinter(cx, name, NULL,
5200 indent & ~JS_DONT_PRETTY_PRINT,
5201 !(indent & JS_DONT_PRETTY_PRINT),
5202 false, false);
5203 if (!jp)
5204 return NULL;
5205 if (js_DecompileScript(jp, script))
5206 str = js_GetPrinterOutput(jp);
5207 else
5208 str = NULL;
5209 js_DestroyPrinter(jp);
5210 return str;
5213 JS_PUBLIC_API(JSString *)
5214 JS_DecompileFunction(JSContext *cx, JSFunction *fun, unsigned indent)
5216 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5217 AssertNoGC(cx);
5218 CHECK_REQUEST(cx);
5219 assertSameCompartment(cx, fun);
5220 return js_DecompileToString(cx, "JS_DecompileFunction", fun,
5221 indent & ~JS_DONT_PRETTY_PRINT,
5222 !(indent & JS_DONT_PRETTY_PRINT),
5223 false, false, js_DecompileFunction);
5226 JS_PUBLIC_API(JSString *)
5227 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, unsigned indent)
5229 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5230 AssertNoGC(cx);
5231 CHECK_REQUEST(cx);
5232 assertSameCompartment(cx, fun);
5233 return js_DecompileToString(cx, "JS_DecompileFunctionBody", fun,
5234 indent & ~JS_DONT_PRETTY_PRINT,
5235 !(indent & JS_DONT_PRETTY_PRINT),
5236 false, false, js_DecompileFunctionBody);
5239 JS_NEVER_INLINE JS_PUBLIC_API(JSBool)
5240 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *scriptArg, jsval *rval)
5242 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5243 AssertNoGC(cx);
5244 CHECK_REQUEST(cx);
5245 assertSameCompartment(cx, obj);
5246 if (cx->compartment != obj->compartment())
5247 *(volatile int *) 0 = 0xf0;
5248 AutoLastFrameCheck lfc(cx);
5250 JS::Anchor<JSScript *> script;
5253 * Mozilla caches pre-compiled scripts (e.g., in the XUL prototype cache)
5254 * and runs them against multiple globals. With a compartment per global,
5255 * this requires cloning the pre-compiled script into each new global.
5256 * Since each script gets run once, there is no point in trying to cache
5257 * this clone. Ideally, this would be handled at some pinch point in
5258 * mozilla, but there doesn't seem to be one, so we handle it here.
5260 if (scriptArg->compartment() != obj->compartment()) {
5261 script = CloneScript(cx, scriptArg);
5262 if (!script.get())
5263 return false;
5264 } else {
5265 script = scriptArg;
5268 return Execute(cx, script.get(), *obj, rval);
5271 JS_PUBLIC_API(JSBool)
5272 JS_ExecuteScriptVersion(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval,
5273 JSVersion version)
5275 AutoVersionAPI ava(cx, version);
5276 return JS_ExecuteScript(cx, obj, script, rval);
5279 bool
5280 EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj_,
5281 JSPrincipals *principals, JSPrincipals *originPrincipals,
5282 const jschar *chars, unsigned length,
5283 const char *filename, unsigned lineno,
5284 jsval *rval, JSVersion compileVersion)
5286 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5288 RootedVarObject obj(cx, obj_);
5290 uint32_t flags = TCF_COMPILE_N_GO | TCF_NEED_SCRIPT_GLOBAL;
5291 if (!rval)
5292 flags |= TCF_NO_SCRIPT_RVAL;
5294 CHECK_REQUEST(cx);
5295 AutoLastFrameCheck lfc(cx);
5296 JSScript *script = frontend::CompileScript(cx, obj, NULL, principals, originPrincipals,
5297 flags, chars, length, filename, lineno,
5298 compileVersion);
5299 if (!script)
5300 return false;
5302 JS_ASSERT(script->getVersion() == compileVersion);
5304 return Execute(cx, script, *obj, rval);
5307 JS_PUBLIC_API(JSBool)
5308 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
5309 JSPrincipals *principals,
5310 const jschar *chars, unsigned length,
5311 const char *filename, unsigned lineno,
5312 jsval *rval)
5314 return EvaluateUCScriptForPrincipalsCommon(cx, obj, principals, NULL, chars, length,
5315 filename, lineno, rval, cx->findVersion());
5318 JS_PUBLIC_API(JSBool)
5319 JS_EvaluateUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
5320 JSPrincipals *principals,
5321 const jschar *chars, unsigned length,
5322 const char *filename, unsigned lineno,
5323 jsval *rval, JSVersion version)
5325 AutoVersionAPI avi(cx, version);
5326 return EvaluateUCScriptForPrincipalsCommon(cx, obj, principals, NULL, chars, length,
5327 filename, lineno, rval, avi.version());
5330 extern JS_PUBLIC_API(JSBool)
5331 JS_EvaluateUCScriptForPrincipalsVersionOrigin(JSContext *cx, JSObject *obj,
5332 JSPrincipals *principals,
5333 JSPrincipals *originPrincipals,
5334 const jschar *chars, unsigned length,
5335 const char *filename, unsigned lineno,
5336 jsval *rval, JSVersion version)
5338 AutoVersionAPI avi(cx, version);
5339 return EvaluateUCScriptForPrincipalsCommon(cx, obj, principals, originPrincipals,
5340 chars, length, filename, lineno, rval,
5341 avi.version());
5344 JS_PUBLIC_API(JSBool)
5345 JS_EvaluateUCScript(JSContext *cx, JSObject *obj, const jschar *chars, unsigned length,
5346 const char *filename, unsigned lineno, jsval *rval)
5348 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5349 return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno, rval);
5352 /* Ancient unsigned nbytes is part of API/ABI, so use size_t length local. */
5353 JS_PUBLIC_API(JSBool)
5354 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
5355 const char *bytes, unsigned nbytes,
5356 const char *filename, unsigned lineno, jsval *rval)
5358 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5359 size_t length = nbytes;
5360 jschar *chars = InflateString(cx, bytes, &length);
5361 if (!chars)
5362 return JS_FALSE;
5363 JSBool ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
5364 filename, lineno, rval);
5365 cx->free_(chars);
5366 return ok;
5369 JS_PUBLIC_API(JSBool)
5370 JS_EvaluateScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, JSPrincipals *principals,
5371 const char *bytes, unsigned nbytes,
5372 const char *filename, unsigned lineno, jsval *rval, JSVersion version)
5374 AutoVersionAPI avi(cx, version);
5375 return JS_EvaluateScriptForPrincipals(cx, obj, principals, bytes, nbytes, filename, lineno,
5376 rval);
5379 JS_PUBLIC_API(JSBool)
5380 JS_EvaluateScript(JSContext *cx, JSObject *obj, const char *bytes, unsigned nbytes,
5381 const char *filename, unsigned lineno, jsval *rval)
5383 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5384 return JS_EvaluateScriptForPrincipals(cx, obj, NULL, bytes, nbytes, filename, lineno, rval);
5387 JS_PUBLIC_API(JSBool)
5388 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, unsigned argc, jsval *argv,
5389 jsval *rval)
5391 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5392 AssertNoGC(cx);
5393 CHECK_REQUEST(cx);
5394 assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc));
5395 AutoLastFrameCheck lfc(cx);
5397 return Invoke(cx, ObjectOrNullValue(obj), ObjectValue(*fun), argc, argv, rval);
5400 JS_PUBLIC_API(JSBool)
5401 JS_CallFunctionName(JSContext *cx, JSObject *obj_, const char *name, unsigned argc, jsval *argv,
5402 jsval *rval)
5404 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5405 AssertNoGC(cx);
5406 CHECK_REQUEST(cx);
5407 assertSameCompartment(cx, obj_, JSValueArray(argv, argc));
5408 AutoLastFrameCheck lfc(cx);
5410 RootedVarObject obj(cx, obj_);
5412 Value v;
5413 JSAtom *atom = js_Atomize(cx, name, strlen(name));
5414 return atom &&
5415 js_GetMethod(cx, obj, AtomToId(atom), 0, &v) &&
5416 Invoke(cx, ObjectOrNullValue(obj), v, argc, argv, rval);
5419 JS_PUBLIC_API(JSBool)
5420 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, unsigned argc, jsval *argv,
5421 jsval *rval)
5423 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5424 AssertNoGC(cx);
5425 CHECK_REQUEST(cx);
5426 assertSameCompartment(cx, obj, fval, JSValueArray(argv, argc));
5427 AutoLastFrameCheck lfc(cx);
5429 return Invoke(cx, ObjectOrNullValue(obj), fval, argc, argv, rval);
5432 namespace JS {
5434 JS_PUBLIC_API(bool)
5435 Call(JSContext *cx, jsval thisv, jsval fval, unsigned argc, jsval *argv, jsval *rval)
5437 AssertNoGC(cx);
5438 CHECK_REQUEST(cx);
5439 assertSameCompartment(cx, thisv, fval, JSValueArray(argv, argc));
5440 AutoLastFrameCheck lfc(cx);
5442 return Invoke(cx, thisv, fval, argc, argv, rval);
5445 } // namespace JS
5447 JS_PUBLIC_API(JSObject *)
5448 JS_New(JSContext *cx, JSObject *ctor, unsigned argc, jsval *argv)
5450 AssertNoGC(cx);
5451 CHECK_REQUEST(cx);
5452 assertSameCompartment(cx, ctor, JSValueArray(argv, argc));
5453 AutoLastFrameCheck lfc(cx);
5455 // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
5456 // is not a simple variation of JSOP_CALL. We have to determine what class
5457 // of object to create, create it, and clamp the return value to an object,
5458 // among other details. InvokeConstructor does the hard work.
5459 InvokeArgsGuard args;
5460 if (!cx->stack.pushInvokeArgs(cx, argc, &args))
5461 return NULL;
5463 args.calleev().setObject(*ctor);
5464 args.thisv().setNull();
5465 PodCopy(args.array(), argv, argc);
5467 if (!InvokeConstructor(cx, args))
5468 return NULL;
5470 if (!args.rval().isObject()) {
5472 * Although constructors may return primitives (via proxies), this
5473 * API is asking for an object, so we report an error.
5475 JSAutoByteString bytes;
5476 if (js_ValueToPrintable(cx, args.rval(), &bytes)) {
5477 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_NEW_RESULT,
5478 bytes.ptr());
5480 return NULL;
5483 return &args.rval().toObject();
5486 JS_PUBLIC_API(JSOperationCallback)
5487 JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback)
5489 JSOperationCallback old = cx->operationCallback;
5490 cx->operationCallback = callback;
5491 return old;
5494 JS_PUBLIC_API(JSOperationCallback)
5495 JS_GetOperationCallback(JSContext *cx)
5497 return cx->operationCallback;
5500 JS_PUBLIC_API(void)
5501 JS_TriggerOperationCallback(JSRuntime *rt)
5503 rt->triggerOperationCallback();
5506 JS_PUBLIC_API(JSBool)
5507 JS_IsRunning(JSContext *cx)
5509 StackFrame *fp = cx->maybefp();
5510 while (fp && fp->isDummyFrame())
5511 fp = fp->prev();
5512 return fp != NULL;
5515 JS_PUBLIC_API(JSBool)
5516 JS_SaveFrameChain(JSContext *cx)
5518 AssertNoGC(cx);
5519 CHECK_REQUEST(cx);
5520 return cx->stack.saveFrameChain();
5523 JS_PUBLIC_API(void)
5524 JS_RestoreFrameChain(JSContext *cx)
5526 AssertNoGC(cx);
5527 CHECK_REQUEST(cx);
5528 cx->stack.restoreFrameChain();
5531 #ifdef MOZ_TRACE_JSCALLS
5532 JS_PUBLIC_API(void)
5533 JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb)
5535 cx->functionCallback = fcb;
5538 JS_PUBLIC_API(JSFunctionCallback)
5539 JS_GetFunctionCallback(JSContext *cx)
5541 return cx->functionCallback;
5543 #endif
5545 /************************************************************************/
5546 JS_PUBLIC_API(JSString *)
5547 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
5549 AssertNoGC(cx);
5550 CHECK_REQUEST(cx);
5551 return js_NewStringCopyN(cx, s, n);
5554 JS_PUBLIC_API(JSString *)
5555 JS_NewStringCopyZ(JSContext *cx, const char *s)
5557 size_t n;
5558 jschar *js;
5559 JSString *str;
5561 AssertNoGC(cx);
5562 CHECK_REQUEST(cx);
5563 if (!s || !*s)
5564 return cx->runtime->emptyString;
5565 n = strlen(s);
5566 js = InflateString(cx, s, &n);
5567 if (!js)
5568 return NULL;
5569 str = js_NewString(cx, js, n);
5570 if (!str)
5571 cx->free_(js);
5572 return str;
5575 JS_PUBLIC_API(JSBool)
5576 JS_StringHasBeenInterned(JSContext *cx, JSString *str)
5578 AssertNoGC(cx);
5579 CHECK_REQUEST(cx);
5581 if (!str->isAtom())
5582 return false;
5584 return AtomIsInterned(cx, &str->asAtom());
5587 JS_PUBLIC_API(jsid)
5588 INTERNED_STRING_TO_JSID(JSContext *cx, JSString *str)
5590 JS_ASSERT(str);
5591 JS_ASSERT(((size_t)str & JSID_TYPE_MASK) == 0);
5592 JS_ASSERT_IF(cx, JS_StringHasBeenInterned(cx, str));
5593 return AtomToId(&str->asAtom());
5596 JS_PUBLIC_API(JSString *)
5597 JS_InternJSString(JSContext *cx, JSString *str)
5599 AssertNoGC(cx);
5600 CHECK_REQUEST(cx);
5601 JSAtom *atom = js_AtomizeString(cx, str, InternAtom);
5602 JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
5603 return atom;
5606 JS_PUBLIC_API(JSString *)
5607 JS_InternString(JSContext *cx, const char *s)
5609 AssertNoGC(cx);
5610 CHECK_REQUEST(cx);
5611 JSAtom *atom = js_Atomize(cx, s, strlen(s), InternAtom);
5612 JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
5613 return atom;
5616 JS_PUBLIC_API(JSString *)
5617 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
5619 AssertNoGC(cx);
5620 CHECK_REQUEST(cx);
5621 return js_NewString(cx, chars, length);
5624 JS_PUBLIC_API(JSString *)
5625 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
5627 AssertNoGC(cx);
5628 CHECK_REQUEST(cx);
5629 return js_NewStringCopyN(cx, s, n);
5632 JS_PUBLIC_API(JSString *)
5633 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
5635 AssertNoGC(cx);
5636 CHECK_REQUEST(cx);
5637 if (!s)
5638 return cx->runtime->emptyString;
5639 return js_NewStringCopyZ(cx, s);
5642 JS_PUBLIC_API(JSString *)
5643 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
5645 AssertNoGC(cx);
5646 CHECK_REQUEST(cx);
5647 JSAtom *atom = js_AtomizeChars(cx, s, length, InternAtom);
5648 JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
5649 return atom;
5652 JS_PUBLIC_API(JSString *)
5653 JS_InternUCString(JSContext *cx, const jschar *s)
5655 return JS_InternUCStringN(cx, s, js_strlen(s));
5658 JS_PUBLIC_API(size_t)
5659 JS_GetStringLength(JSString *str)
5661 return str->length();
5664 JS_PUBLIC_API(const jschar *)
5665 JS_GetStringCharsZ(JSContext *cx, JSString *str)
5667 AssertNoGCOrFlatString(cx, str);
5668 CHECK_REQUEST(cx);
5669 assertSameCompartment(cx, str);
5670 return str->getCharsZ(cx);
5673 JS_PUBLIC_API(const jschar *)
5674 JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength)
5676 AssertNoGCOrFlatString(cx, str);
5677 CHECK_REQUEST(cx);
5678 assertSameCompartment(cx, str);
5679 *plength = str->length();
5680 return str->getCharsZ(cx);
5683 JS_PUBLIC_API(const jschar *)
5684 JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
5686 AssertNoGCOrFlatString(cx, str);
5687 CHECK_REQUEST(cx);
5688 assertSameCompartment(cx, str);
5689 *plength = str->length();
5690 return str->getChars(cx);
5693 JS_PUBLIC_API(const jschar *)
5694 JS_GetInternedStringChars(JSString *str)
5696 return str->asAtom().chars();
5699 JS_PUBLIC_API(const jschar *)
5700 JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength)
5702 JSAtom &atom = str->asAtom();
5703 *plength = atom.length();
5704 return atom.chars();
5707 extern JS_PUBLIC_API(JSFlatString *)
5708 JS_FlattenString(JSContext *cx, JSString *str)
5710 AssertNoGC(cx);
5711 CHECK_REQUEST(cx);
5712 assertSameCompartment(cx, str);
5713 return str->getCharsZ(cx) ? (JSFlatString *)str : NULL;
5716 extern JS_PUBLIC_API(const jschar *)
5717 JS_GetFlatStringChars(JSFlatString *str)
5719 return str->chars();
5722 JS_PUBLIC_API(JSBool)
5723 JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result)
5725 AssertNoGC(cx);
5726 CHECK_REQUEST(cx);
5728 return CompareStrings(cx, str1, str2, result);
5731 JS_PUBLIC_API(JSBool)
5732 JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match)
5734 AssertNoGC(cx);
5735 CHECK_REQUEST(cx);
5737 JSLinearString *linearStr = str->ensureLinear(cx);
5738 if (!linearStr)
5739 return false;
5740 *match = StringEqualsAscii(linearStr, asciiBytes);
5741 return true;
5744 JS_PUBLIC_API(JSBool)
5745 JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes)
5747 return StringEqualsAscii(str, asciiBytes);
5750 JS_PUBLIC_API(size_t)
5751 JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote)
5753 return PutEscapedString(buffer, size, str, quote);
5756 JS_PUBLIC_API(size_t)
5757 JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote)
5759 AssertNoGC(cx);
5760 JSLinearString *linearStr = str->ensureLinear(cx);
5761 if (!linearStr)
5762 return size_t(-1);
5763 return PutEscapedString(buffer, size, linearStr, quote);
5766 JS_PUBLIC_API(JSBool)
5767 JS_FileEscapedString(FILE *fp, JSString *str, char quote)
5769 JSLinearString *linearStr = str->ensureLinear(NULL);
5770 return linearStr && FileEscapedString(fp, linearStr, quote);
5773 JS_PUBLIC_API(JSString *)
5774 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
5776 AssertNoGC(cx);
5777 CHECK_REQUEST(cx);
5778 return js_NewString(cx, chars, length);
5781 JS_PUBLIC_API(JSString *)
5782 JS_NewDependentString(JSContext *cx, JSString *str, size_t start, size_t length)
5784 AssertNoGC(cx);
5785 CHECK_REQUEST(cx);
5786 return js_NewDependentString(cx, str, start, length);
5789 JS_PUBLIC_API(JSString *)
5790 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
5792 AssertNoGC(cx);
5793 CHECK_REQUEST(cx);
5794 return js_ConcatStrings(cx, RootedVarString(cx, left), RootedVarString(cx, right));
5797 JS_PUBLIC_API(const jschar *)
5798 JS_UndependString(JSContext *cx, JSString *str)
5800 AssertNoGC(cx);
5801 CHECK_REQUEST(cx);
5802 return str->getCharsZ(cx);
5805 JS_PUBLIC_API(JSBool)
5806 JS_MakeStringImmutable(JSContext *cx, JSString *str)
5808 AssertNoGC(cx);
5809 CHECK_REQUEST(cx);
5810 return !!str->ensureFixed(cx);
5813 JS_PUBLIC_API(JSBool)
5814 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, size_t *dstlenp)
5816 AssertNoGC(cx);
5817 CHECK_REQUEST(cx);
5819 size_t n;
5820 if (!dst) {
5821 n = GetDeflatedStringLength(cx, src, srclen);
5822 if (n == (size_t)-1) {
5823 *dstlenp = 0;
5824 return JS_FALSE;
5826 *dstlenp = n;
5827 return JS_TRUE;
5830 return DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5833 JS_PUBLIC_API(JSBool)
5834 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp)
5836 AssertNoGC(cx);
5837 CHECK_REQUEST(cx);
5838 return InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5841 JS_PUBLIC_API(JSBool)
5842 JS_DecodeUTF8(JSContext *cx, const char *src, size_t srclen, jschar *dst,
5843 size_t *dstlenp)
5845 AssertNoGC(cx);
5846 CHECK_REQUEST(cx);
5847 return InflateUTF8StringToBuffer(cx, src, srclen, dst, dstlenp);
5850 JS_PUBLIC_API(char *)
5851 JS_EncodeString(JSContext *cx, JSString *str)
5853 AssertNoGC(cx);
5854 CHECK_REQUEST(cx);
5856 const jschar *chars = str->getChars(cx);
5857 if (!chars)
5858 return NULL;
5859 return DeflateString(cx, chars, str->length());
5862 JS_PUBLIC_API(size_t)
5863 JS_GetStringEncodingLength(JSContext *cx, JSString *str)
5865 /* jsd calls us with a NULL cx. Ugh. */
5866 if (cx) {
5867 AssertNoGC(cx);
5868 CHECK_REQUEST(cx);
5871 const jschar *chars = str->getChars(cx);
5872 if (!chars)
5873 return size_t(-1);
5874 return GetDeflatedStringLength(cx, chars, str->length());
5877 JS_PUBLIC_API(size_t)
5878 JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length)
5881 * FIXME bug 612141 - fix DeflateStringToBuffer interface so the result
5882 * would allow to distinguish between insufficient buffer and encoding
5883 * error.
5885 size_t writtenLength = length;
5886 const jschar *chars = str->getChars(NULL);
5887 if (!chars)
5888 return size_t(-1);
5889 if (DeflateStringToBuffer(NULL, chars, str->length(), buffer, &writtenLength)) {
5890 JS_ASSERT(writtenLength <= length);
5891 return writtenLength;
5893 JS_ASSERT(writtenLength <= length);
5894 size_t necessaryLength = GetDeflatedStringLength(NULL, chars, str->length());
5895 if (necessaryLength == size_t(-1))
5896 return size_t(-1);
5897 if (writtenLength != length) {
5898 /* Make sure that the buffer contains only valid UTF-8 sequences. */
5899 JS_ASSERT(js_CStringsAreUTF8);
5900 PodZero(buffer + writtenLength, length - writtenLength);
5902 return necessaryLength;
5905 JS_PUBLIC_API(JSBool)
5906 JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
5907 JSONWriteCallback callback, void *data)
5909 AssertNoGC(cx);
5910 CHECK_REQUEST(cx);
5911 assertSameCompartment(cx, replacer, space);
5912 StringBuffer sb(cx);
5913 if (!js_Stringify(cx, vp, replacer, space, sb))
5914 return false;
5915 if (sb.empty()) {
5916 JSAtom *nullAtom = cx->runtime->atomState.nullAtom;
5917 return callback(nullAtom->chars(), nullAtom->length(), data);
5919 return callback(sb.begin(), sb.length(), data);
5922 JS_PUBLIC_API(JSBool)
5923 JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, jsval *vp)
5925 AssertNoGC(cx);
5926 CHECK_REQUEST(cx);
5928 return ParseJSONWithReviver(cx, chars, len, NullValue(), vp);
5931 JS_PUBLIC_API(JSBool)
5932 JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, jsval reviver, jsval *vp)
5934 AssertNoGC(cx);
5935 CHECK_REQUEST(cx);
5937 return ParseJSONWithReviver(cx, chars, len, reviver, vp);
5940 JS_PUBLIC_API(JSBool)
5941 JS_ReadStructuredClone(JSContext *cx, const uint64_t *buf, size_t nbytes,
5942 uint32_t version, jsval *vp,
5943 const JSStructuredCloneCallbacks *optionalCallbacks,
5944 void *closure)
5946 AssertNoGC(cx);
5947 CHECK_REQUEST(cx);
5949 if (version > JS_STRUCTURED_CLONE_VERSION) {
5950 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CLONE_VERSION);
5951 return false;
5953 const JSStructuredCloneCallbacks *callbacks =
5954 optionalCallbacks ?
5955 optionalCallbacks :
5956 cx->runtime->structuredCloneCallbacks;
5957 return ReadStructuredClone(cx, buf, nbytes, vp, callbacks, closure);
5960 JS_PUBLIC_API(JSBool)
5961 JS_WriteStructuredClone(JSContext *cx, jsval v, uint64_t **bufp, size_t *nbytesp,
5962 const JSStructuredCloneCallbacks *optionalCallbacks,
5963 void *closure)
5965 AssertNoGC(cx);
5966 CHECK_REQUEST(cx);
5967 assertSameCompartment(cx, v);
5969 const JSStructuredCloneCallbacks *callbacks =
5970 optionalCallbacks ?
5971 optionalCallbacks :
5972 cx->runtime->structuredCloneCallbacks;
5973 return WriteStructuredClone(cx, v, (uint64_t **) bufp, nbytesp, callbacks, closure);
5976 JS_PUBLIC_API(JSBool)
5977 JS_StructuredClone(JSContext *cx, jsval v, jsval *vp,
5978 const JSStructuredCloneCallbacks *optionalCallbacks,
5979 void *closure)
5981 AssertNoGC(cx);
5982 CHECK_REQUEST(cx);
5983 assertSameCompartment(cx, v);
5985 const JSStructuredCloneCallbacks *callbacks =
5986 optionalCallbacks ?
5987 optionalCallbacks :
5988 cx->runtime->structuredCloneCallbacks;
5989 JSAutoStructuredCloneBuffer buf;
5990 return buf.write(cx, v, callbacks, closure) &&
5991 buf.read(cx, vp, callbacks, closure);
5994 void
5995 JSAutoStructuredCloneBuffer::clear()
5997 if (data_) {
5998 Foreground::free_(data_);
5999 data_ = NULL;
6000 nbytes_ = 0;
6001 version_ = 0;
6005 void
6006 JSAutoStructuredCloneBuffer::adopt(uint64_t *data, size_t nbytes, uint32_t version)
6008 clear();
6009 data_ = data;
6010 nbytes_ = nbytes;
6011 version_ = version;
6014 bool
6015 JSAutoStructuredCloneBuffer::copy(const uint64_t *srcData, size_t nbytes, uint32_t version)
6017 uint64_t *newData = static_cast<uint64_t *>(OffTheBooks::malloc_(nbytes));
6018 if (!newData)
6019 return false;
6021 js_memcpy(newData, srcData, nbytes);
6023 clear();
6024 data_ = newData;
6025 nbytes_ = nbytes;
6026 version_ = version;
6027 return true;
6029 void
6030 JSAutoStructuredCloneBuffer::steal(uint64_t **datap, size_t *nbytesp, uint32_t *versionp)
6032 *datap = data_;
6033 *nbytesp = nbytes_;
6034 if (versionp)
6035 *versionp = version_;
6037 data_ = NULL;
6038 nbytes_ = 0;
6039 version_ = 0;
6042 bool
6043 JSAutoStructuredCloneBuffer::read(JSContext *cx, jsval *vp,
6044 const JSStructuredCloneCallbacks *optionalCallbacks,
6045 void *closure) const
6047 JS_ASSERT(cx);
6048 JS_ASSERT(data_);
6049 return !!JS_ReadStructuredClone(cx, data_, nbytes_, version_, vp,
6050 optionalCallbacks, closure);
6053 bool
6054 JSAutoStructuredCloneBuffer::write(JSContext *cx, jsval v,
6055 const JSStructuredCloneCallbacks *optionalCallbacks,
6056 void *closure)
6058 clear();
6059 bool ok = !!JS_WriteStructuredClone(cx, v, &data_, &nbytes_,
6060 optionalCallbacks, closure);
6061 if (!ok) {
6062 data_ = NULL;
6063 nbytes_ = 0;
6064 version_ = JS_STRUCTURED_CLONE_VERSION;
6066 return ok;
6069 void
6070 JSAutoStructuredCloneBuffer::swap(JSAutoStructuredCloneBuffer &other)
6072 uint64_t *data = other.data_;
6073 size_t nbytes = other.nbytes_;
6074 uint32_t version = other.version_;
6076 other.data_ = this->data_;
6077 other.nbytes_ = this->nbytes_;
6078 other.version_ = this->version_;
6080 this->data_ = data;
6081 this->nbytes_ = nbytes;
6082 this->version_ = version;
6085 JS_PUBLIC_API(void)
6086 JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks)
6088 rt->structuredCloneCallbacks = callbacks;
6091 JS_PUBLIC_API(JSBool)
6092 JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2)
6094 return r->input().readPair((uint32_t *) p1, (uint32_t *) p2);
6097 JS_PUBLIC_API(JSBool)
6098 JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len)
6100 return r->input().readBytes(p, len);
6103 JS_PUBLIC_API(JSBool)
6104 JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data)
6106 return w->output().writePair(tag, data);
6109 JS_PUBLIC_API(JSBool)
6110 JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len)
6112 return w->output().writeBytes(p, len);
6116 * The following determines whether C Strings are to be treated as UTF-8
6117 * or ISO-8859-1. For correct operation, it must be set prior to the
6118 * first call to JS_NewRuntime.
6120 #ifndef JS_C_STRINGS_ARE_UTF8
6121 JSBool js_CStringsAreUTF8 = JS_FALSE;
6122 #endif
6124 JS_PUBLIC_API(JSBool)
6125 JS_CStringsAreUTF8()
6127 return js_CStringsAreUTF8;
6130 JS_PUBLIC_API(void)
6131 JS_SetCStringsAreUTF8()
6133 JS_ASSERT(!js_NewRuntimeWasCalled);
6135 #ifndef JS_C_STRINGS_ARE_UTF8
6136 js_CStringsAreUTF8 = JS_TRUE;
6137 #endif
6140 /************************************************************************/
6142 JS_PUBLIC_API(void)
6143 JS_ReportError(JSContext *cx, const char *format, ...)
6145 va_list ap;
6147 AssertNoGC(cx);
6148 va_start(ap, format);
6149 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
6150 va_end(ap);
6153 JS_PUBLIC_API(void)
6154 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
6155 void *userRef, const unsigned errorNumber, ...)
6157 va_list ap;
6159 AssertNoGC(cx);
6160 va_start(ap, errorNumber);
6161 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
6162 errorNumber, JS_TRUE, ap);
6163 va_end(ap);
6166 JS_PUBLIC_API(void)
6167 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
6168 void *userRef, const unsigned errorNumber, ...)
6170 va_list ap;
6172 AssertNoGC(cx);
6173 va_start(ap, errorNumber);
6174 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
6175 errorNumber, JS_FALSE, ap);
6176 va_end(ap);
6179 JS_PUBLIC_API(JSBool)
6180 JS_ReportWarning(JSContext *cx, const char *format, ...)
6182 va_list ap;
6183 JSBool ok;
6185 AssertNoGC(cx);
6186 va_start(ap, format);
6187 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
6188 va_end(ap);
6189 return ok;
6192 JS_PUBLIC_API(JSBool)
6193 JS_ReportErrorFlagsAndNumber(JSContext *cx, unsigned flags,
6194 JSErrorCallback errorCallback, void *userRef,
6195 const unsigned errorNumber, ...)
6197 va_list ap;
6198 JSBool ok;
6200 AssertNoGC(cx);
6201 va_start(ap, errorNumber);
6202 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
6203 errorNumber, JS_TRUE, ap);
6204 va_end(ap);
6205 return ok;
6208 JS_PUBLIC_API(JSBool)
6209 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, unsigned flags,
6210 JSErrorCallback errorCallback, void *userRef,
6211 const unsigned errorNumber, ...)
6213 va_list ap;
6214 JSBool ok;
6216 AssertNoGC(cx);
6217 va_start(ap, errorNumber);
6218 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
6219 errorNumber, JS_FALSE, ap);
6220 va_end(ap);
6221 return ok;
6224 JS_PUBLIC_API(void)
6225 JS_ReportOutOfMemory(JSContext *cx)
6227 js_ReportOutOfMemory(cx);
6230 JS_PUBLIC_API(void)
6231 JS_ReportAllocationOverflow(JSContext *cx)
6233 js_ReportAllocationOverflow(cx);
6236 JS_PUBLIC_API(JSErrorReporter)
6237 JS_GetErrorReporter(JSContext *cx)
6239 return cx->errorReporter;
6242 JS_PUBLIC_API(JSErrorReporter)
6243 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
6245 JSErrorReporter older;
6247 older = cx->errorReporter;
6248 cx->errorReporter = er;
6249 return older;
6252 /************************************************************************/
6255 * Dates.
6257 JS_PUBLIC_API(JSObject *)
6258 JS_NewDateObject(JSContext *cx, int year, int mon, int mday, int hour, int min, int sec)
6260 AssertNoGC(cx);
6261 CHECK_REQUEST(cx);
6262 return js_NewDateObject(cx, year, mon, mday, hour, min, sec);
6265 JS_PUBLIC_API(JSObject *)
6266 JS_NewDateObjectMsec(JSContext *cx, double msec)
6268 AssertNoGC(cx);
6269 CHECK_REQUEST(cx);
6270 return js_NewDateObjectMsec(cx, msec);
6273 JS_PUBLIC_API(JSBool)
6274 JS_ObjectIsDate(JSContext *cx, JSObject *obj)
6276 AssertNoGC(cx);
6277 JS_ASSERT(obj);
6278 return obj->isDate();
6281 /************************************************************************/
6284 * Regular Expressions.
6286 JS_PUBLIC_API(JSObject *)
6287 JS_NewRegExpObject(JSContext *cx, JSObject *obj, char *bytes, size_t length, unsigned flags)
6289 AssertNoGC(cx);
6290 CHECK_REQUEST(cx);
6291 jschar *chars = InflateString(cx, bytes, &length);
6292 if (!chars)
6293 return NULL;
6295 RegExpStatics *res = obj->asGlobal().getRegExpStatics();
6296 RegExpObject *reobj = RegExpObject::create(cx, res, chars, length, RegExpFlag(flags), NULL);
6297 cx->free_(chars);
6298 return reobj;
6301 JS_PUBLIC_API(JSObject *)
6302 JS_NewUCRegExpObject(JSContext *cx, JSObject *obj, jschar *chars, size_t length, unsigned flags)
6304 AssertNoGC(cx);
6305 CHECK_REQUEST(cx);
6306 RegExpStatics *res = obj->asGlobal().getRegExpStatics();
6307 return RegExpObject::create(cx, res, chars, length, RegExpFlag(flags), NULL);
6310 JS_PUBLIC_API(void)
6311 JS_SetRegExpInput(JSContext *cx, JSObject *obj, JSString *input, JSBool multiline)
6313 AssertNoGC(cx);
6314 CHECK_REQUEST(cx);
6315 assertSameCompartment(cx, input);
6317 obj->asGlobal().getRegExpStatics()->reset(cx, input, !!multiline);
6320 JS_PUBLIC_API(void)
6321 JS_ClearRegExpStatics(JSContext *cx, JSObject *obj)
6323 AssertNoGC(cx);
6324 CHECK_REQUEST(cx);
6325 JS_ASSERT(obj);
6327 obj->asGlobal().getRegExpStatics()->clear();
6330 JS_PUBLIC_API(JSBool)
6331 JS_ExecuteRegExp(JSContext *cx, JSObject *obj, JSObject *reobj, jschar *chars, size_t length,
6332 size_t *indexp, JSBool test, jsval *rval)
6334 AssertNoGC(cx);
6335 CHECK_REQUEST(cx);
6337 RegExpStatics *res = obj->asGlobal().getRegExpStatics();
6338 return ExecuteRegExp(cx, res, reobj->asRegExp(), NULL, chars, length,
6339 indexp, test ? RegExpTest : RegExpExec, rval);
6342 JS_PUBLIC_API(JSObject *)
6343 JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, unsigned flags)
6345 AssertNoGC(cx);
6346 CHECK_REQUEST(cx);
6347 jschar *chars = InflateString(cx, bytes, &length);
6348 if (!chars)
6349 return NULL;
6350 RegExpObject *reobj = RegExpObject::createNoStatics(cx, chars, length, RegExpFlag(flags), NULL);
6351 cx->free_(chars);
6352 return reobj;
6355 JS_PUBLIC_API(JSObject *)
6356 JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, unsigned flags)
6358 AssertNoGC(cx);
6359 CHECK_REQUEST(cx);
6360 return RegExpObject::createNoStatics(cx, chars, length, RegExpFlag(flags), NULL);
6363 JS_PUBLIC_API(JSBool)
6364 JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *obj, jschar *chars, size_t length,
6365 size_t *indexp, JSBool test, jsval *rval)
6367 AssertNoGC(cx);
6368 CHECK_REQUEST(cx);
6370 return ExecuteRegExp(cx, NULL, obj->asRegExp(), NULL, chars, length, indexp,
6371 test ? RegExpTest : RegExpExec, rval);
6374 JS_PUBLIC_API(JSBool)
6375 JS_ObjectIsRegExp(JSContext *cx, JSObject *obj)
6377 AssertNoGC(cx);
6378 JS_ASSERT(obj);
6379 return obj->isRegExp();
6382 JS_PUBLIC_API(unsigned)
6383 JS_GetRegExpFlags(JSContext *cx, JSObject *obj)
6385 AssertNoGC(cx);
6386 CHECK_REQUEST(cx);
6388 return obj->asRegExp().getFlags();
6391 JS_PUBLIC_API(JSString *)
6392 JS_GetRegExpSource(JSContext *cx, JSObject *obj)
6394 AssertNoGC(cx);
6395 CHECK_REQUEST(cx);
6397 return obj->asRegExp().getSource();
6400 /************************************************************************/
6402 JS_PUBLIC_API(void)
6403 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
6405 AssertNoGC(cx);
6406 cx->localeCallbacks = callbacks;
6409 JS_PUBLIC_API(JSLocaleCallbacks *)
6410 JS_GetLocaleCallbacks(JSContext *cx)
6412 /* This function can be called by a finalizer. */
6413 return cx->localeCallbacks;
6416 /************************************************************************/
6418 JS_PUBLIC_API(JSBool)
6419 JS_IsExceptionPending(JSContext *cx)
6421 /* This function can be called by a finalizer. */
6422 return (JSBool) cx->isExceptionPending();
6425 JS_PUBLIC_API(JSBool)
6426 JS_GetPendingException(JSContext *cx, jsval *vp)
6428 AssertNoGC(cx);
6429 CHECK_REQUEST(cx);
6430 if (!cx->isExceptionPending())
6431 return JS_FALSE;
6432 *vp = cx->getPendingException();
6433 assertSameCompartment(cx, *vp);
6434 return JS_TRUE;
6437 JS_PUBLIC_API(void)
6438 JS_SetPendingException(JSContext *cx, jsval v)
6440 AssertNoGC(cx);
6441 CHECK_REQUEST(cx);
6442 assertSameCompartment(cx, v);
6443 cx->setPendingException(v);
6446 JS_PUBLIC_API(void)
6447 JS_ClearPendingException(JSContext *cx)
6449 AssertNoGC(cx);
6450 cx->clearPendingException();
6453 JS_PUBLIC_API(JSBool)
6454 JS_ReportPendingException(JSContext *cx)
6456 AssertNoGC(cx);
6457 CHECK_REQUEST(cx);
6459 return js_ReportUncaughtException(cx);
6462 struct JSExceptionState {
6463 JSBool throwing;
6464 jsval exception;
6467 JS_PUBLIC_API(JSExceptionState *)
6468 JS_SaveExceptionState(JSContext *cx)
6470 JSExceptionState *state;
6472 AssertNoGC(cx);
6473 CHECK_REQUEST(cx);
6474 state = (JSExceptionState *) cx->malloc_(sizeof(JSExceptionState));
6475 if (state) {
6476 state->throwing = JS_GetPendingException(cx, &state->exception);
6477 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
6478 js_AddRoot(cx, &state->exception, "JSExceptionState.exception");
6480 return state;
6483 JS_PUBLIC_API(void)
6484 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
6486 AssertNoGC(cx);
6487 CHECK_REQUEST(cx);
6488 if (state) {
6489 if (state->throwing)
6490 JS_SetPendingException(cx, state->exception);
6491 else
6492 JS_ClearPendingException(cx);
6493 JS_DropExceptionState(cx, state);
6497 JS_PUBLIC_API(void)
6498 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
6500 AssertNoGC(cx);
6501 CHECK_REQUEST(cx);
6502 if (state) {
6503 if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
6504 assertSameCompartment(cx, state->exception);
6505 JS_RemoveValueRoot(cx, &state->exception);
6507 cx->free_(state);
6511 JS_PUBLIC_API(JSErrorReport *)
6512 JS_ErrorFromException(JSContext *cx, jsval v)
6514 AssertNoGC(cx);
6515 CHECK_REQUEST(cx);
6516 assertSameCompartment(cx, v);
6517 return js_ErrorFromException(cx, v);
6520 JS_PUBLIC_API(JSBool)
6521 JS_ThrowReportedError(JSContext *cx, const char *message,
6522 JSErrorReport *reportp)
6524 AssertNoGC(cx);
6525 return JS_IsRunning(cx) &&
6526 js_ErrorToException(cx, message, reportp, NULL, NULL);
6529 JS_PUBLIC_API(JSBool)
6530 JS_ThrowStopIteration(JSContext *cx)
6532 AssertNoGC(cx);
6533 return js_ThrowStopIteration(cx);
6536 JS_PUBLIC_API(intptr_t)
6537 JS_GetCurrentThread()
6539 #ifdef JS_THREADSAFE
6540 return reinterpret_cast<intptr_t>(PR_GetCurrentThread());
6541 #else
6542 return 0;
6543 #endif
6546 extern JS_PUBLIC_API(void)
6547 JS_ClearRuntimeThread(JSRuntime *rt)
6549 AssertNoGC(rt);
6550 #ifdef JS_THREADSAFE
6551 rt->clearOwnerThread();
6552 #endif
6555 extern JS_PUBLIC_API(void)
6556 JS_SetRuntimeThread(JSRuntime *rt)
6558 AssertNoGC(rt);
6559 #ifdef JS_THREADSAFE
6560 rt->setOwnerThread();
6561 #endif
6564 extern JS_NEVER_INLINE JS_PUBLIC_API(void)
6565 JS_AbortIfWrongThread(JSRuntime *rt)
6567 #ifdef JS_THREADSAFE
6568 if (!rt->onOwnerThread())
6569 MOZ_Assert("rt->onOwnerThread()", __FILE__, __LINE__);
6570 #endif
6573 #ifdef JS_GC_ZEAL
6574 JS_PUBLIC_API(void)
6575 JS_SetGCZeal(JSContext *cx, uint8_t zeal, uint32_t frequency)
6577 const char *env = getenv("JS_GC_ZEAL");
6578 if (env) {
6579 if (0 == strcmp(env, "help")) {
6580 printf("Format: JS_GC_ZEAL=N[,F]\n"
6581 "N indicates \"zealousness\":\n"
6582 " 0: no additional GCs\n"
6583 " 1: additional GCs at common danger points\n"
6584 " 2: GC every F allocations (default: 100)\n"
6585 " 3: GC when the window paints (browser only)\n"
6586 " 4: Verify write barriers between instructions\n"
6587 " 5: Verify write barriers between paints\n");
6589 const char *p = strchr(env, ',');
6590 zeal = atoi(env);
6591 frequency = p ? atoi(p + 1) : JS_DEFAULT_ZEAL_FREQ;
6594 bool schedule = zeal >= js::gc::ZealAllocValue;
6595 cx->runtime->gcZeal_ = zeal;
6596 cx->runtime->gcZealFrequency = frequency;
6597 cx->runtime->gcNextScheduled = schedule ? frequency : 0;
6600 JS_PUBLIC_API(void)
6601 JS_ScheduleGC(JSContext *cx, uint32_t count)
6603 cx->runtime->gcNextScheduled = count;
6605 #endif
6607 /************************************************************************/
6609 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN)
6611 #include "jswin.h"
6614 * Initialization routine for the JS DLL.
6616 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
6618 return TRUE;
6621 #endif
6623 JS_PUBLIC_API(JSBool)
6624 JS_IndexToId(JSContext *cx, uint32_t index, jsid *id)
6626 return IndexToId(cx, index, id);
6629 JS_PUBLIC_API(JSBool)
6630 JS_IsIdentifier(JSContext *cx, JSString *str, JSBool *isIdentifier)
6632 assertSameCompartment(cx, str);
6634 JSLinearString* linearStr = str->ensureLinear(cx);
6635 if (!linearStr)
6636 return false;
6638 *isIdentifier = js::IsIdentifier(linearStr);
6639 return true;
6642 JS_PUBLIC_API(JSBool)
6643 JS_DescribeScriptedCaller(JSContext *cx, JSScript **script, unsigned *lineno)
6645 if (script)
6646 *script = NULL;
6647 if (lineno)
6648 *lineno = 0;
6650 ScriptFrameIter i(cx);
6651 if (i.done())
6652 return JS_FALSE;
6654 if (script)
6655 *script = i.script();
6656 if (lineno)
6657 *lineno = js::PCToLineNumber(i.script(), i.pc());
6658 return JS_TRUE;
6661 #ifdef JS_THREADSAFE
6662 static PRStatus
6663 CallOnce(void *func)
6665 JSInitCallback init = JS_DATA_TO_FUNC_PTR(JSInitCallback, func);
6666 return init() ? PR_SUCCESS : PR_FAILURE;
6668 #endif
6670 JS_PUBLIC_API(JSBool)
6671 JS_CallOnce(JSCallOnceType *once, JSInitCallback func)
6673 #ifdef JS_THREADSAFE
6674 return PR_CallOnceWithArg(once, CallOnce, JS_FUNC_TO_DATA_PTR(void *, func)) == PR_SUCCESS;
6675 #else
6676 if (!*once) {
6677 *once = true;
6678 return func();
6679 } else {
6680 return JS_TRUE;
6682 #endif
6685 namespace JS {
6687 AutoGCRooter::AutoGCRooter(JSContext *cx, ptrdiff_t tag)
6688 : down(cx->runtime->autoGCRooters), tag(tag), stackTop(&cx->runtime->autoGCRooters)
6690 JS_ASSERT(this != *stackTop);
6691 *stackTop = this;
6694 AutoEnumStateRooter::~AutoEnumStateRooter()
6696 if (!stateValue.isNull())
6697 MOZ_ALWAYS_TRUE(obj->enumerate(context, JSENUMERATE_DESTROY, &stateValue, 0));
6700 #ifdef DEBUG
6701 JS_PUBLIC_API(void)
6702 AssertArgumentsAreSane(JSContext *cx, const JS::Value &v)
6704 AssertNoGC(cx);
6705 CHECK_REQUEST(cx);
6706 assertSameCompartment(cx, v);
6708 #endif /* DEBUG */
6710 } // namespace JS
6712 JS_PUBLIC_API(void *)
6713 JS_EncodeScript(JSContext *cx, JSScript *script, uint32_t *lengthp)
6715 XDREncoder encoder(cx);
6716 if (!encoder.codeScript(&script))
6717 return NULL;
6718 return encoder.forgetData(lengthp);
6721 JS_PUBLIC_API(void *)
6722 JS_EncodeInterpretedFunction(JSContext *cx, JSObject *funobj, uint32_t *lengthp)
6724 XDREncoder encoder(cx);
6725 if (!encoder.codeFunction(&funobj))
6726 return NULL;
6727 return encoder.forgetData(lengthp);
6730 JS_PUBLIC_API(JSScript *)
6731 JS_DecodeScript(JSContext *cx, const void *data, uint32_t length,
6732 JSPrincipals *principals, JSPrincipals *originPrincipals)
6734 XDRDecoder decoder(cx, data, length, principals, originPrincipals);
6735 JSScript *script;
6736 if (!decoder.codeScript(&script))
6737 return NULL;
6738 return script;
6741 JS_PUBLIC_API(JSObject *)
6742 JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length,
6743 JSPrincipals *principals, JSPrincipals *originPrincipals)
6745 XDRDecoder decoder(cx, data, length, principals, originPrincipals);
6746 JSObject *funobj;
6747 if (!decoder.codeFunction(&funobj))
6748 return NULL;
6749 return funobj;
6752 JS_PUBLIC_API(JSObject *)
6753 JS_GetScriptedGlobal(JSContext *cx)
6755 ScriptFrameIter i(cx);
6756 if (i.done())
6757 return JS_GetGlobalForScopeChain(cx);
6759 return JS_GetGlobalForFrame(Jsvalify(i.fp()));