Bug 605752: don't crash on OOM inside ExecutablePool, r=dvander, a=beta8+
[mozilla-central.git] / js / src / jsapi.cpp
blobcc7f559535e3a03ff222edda64fff657e6ce1985
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.
44 #include <ctype.h>
45 #include <stdarg.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include "jstypes.h"
49 #include "jsstdint.h"
50 #include "jsarena.h"
51 #include "jsutil.h"
52 #include "jsclist.h"
53 #include "jsdhash.h"
54 #include "jsprf.h"
55 #include "jsapi.h"
56 #include "jsarray.h"
57 #include "jsatom.h"
58 #include "jsbool.h"
59 #include "jsbuiltins.h"
60 #include "jsclone.h"
61 #include "jscntxt.h"
62 #include "jsversion.h"
63 #include "jsdate.h"
64 #include "jsemit.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 "jsnum.h"
73 #include "json.h"
74 #include "jsobj.h"
75 #include "jsopcode.h"
76 #include "jsparse.h"
77 #include "jsproxy.h"
78 #include "jsregexp.h"
79 #include "jsscan.h"
80 #include "jsscope.h"
81 #include "jsscript.h"
82 #include "jsstr.h"
83 #include "jstracer.h"
84 #include "jsdbgapi.h"
85 #include "prmjtime.h"
86 #include "jsstaticcheck.h"
87 #include "jsvector.h"
88 #include "jswrapper.h"
89 #include "jstypedarray.h"
91 #include "jsatominlines.h"
92 #include "jscntxtinlines.h"
93 #include "jsinterpinlines.h"
94 #include "jsobjinlines.h"
95 #include "jsscopeinlines.h"
96 #include "jscntxtinlines.h"
97 #include "jsregexpinlines.h"
98 #include "assembler/wtf/Platform.h"
100 #if ENABLE_YARR_JIT
101 #include "assembler/jit/ExecutableAllocator.h"
102 #include "methodjit/Logging.h"
103 #endif
105 #if JS_HAS_XML_SUPPORT
106 #include "jsxml.h"
107 #endif
109 using namespace js;
110 using namespace js::gc;
112 class AutoVersionAPI
114 JSContext * const cx;
115 JSVersion oldVersion;
116 bool oldVersionWasOverride;
117 uint32 oldOptions;
119 public:
120 explicit AutoVersionAPI(JSContext *cx, JSVersion newVersion)
121 : cx(cx), oldVersion(cx->findVersion()), oldVersionWasOverride(cx->isVersionOverridden()),
122 oldOptions(cx->options) {
123 JS_ASSERT(!VersionExtractFlags(newVersion) ||
124 VersionExtractFlags(newVersion) == VersionFlags::HAS_XML);
125 cx->options = VersionHasXML(newVersion)
126 ? (cx->options | JSOPTION_XML)
127 : (cx->options & ~JSOPTION_XML);
128 cx->maybeOverrideVersion(newVersion);
129 SyncOptionsToVersion(cx);
132 ~AutoVersionAPI() {
133 cx->options = oldOptions;
134 if (oldVersionWasOverride) {
135 JS_ALWAYS_TRUE(cx->maybeOverrideVersion(oldVersion));
136 } else {
137 cx->clearVersionOverride();
138 cx->setDefaultVersion(oldVersion);
140 JS_ASSERT(cx->findVersion() == oldVersion);
144 #ifdef HAVE_VA_LIST_AS_ARRAY
145 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
146 #else
147 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
148 #endif
150 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
151 JS_PUBLIC_DATA(jsid) JS_DEFAULT_XML_NAMESPACE_ID = { size_t(JSID_TYPE_DEFAULT_XML_NAMESPACE) };
152 JS_PUBLIC_DATA(jsid) JSID_VOID = { size_t(JSID_TYPE_VOID) };
153 JS_PUBLIC_DATA(jsid) JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) };
154 #endif
156 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
157 JS_PUBLIC_DATA(jsval) JSVAL_NULL = { BUILD_JSVAL(JSVAL_TAG_NULL, 0) };
158 JS_PUBLIC_DATA(jsval) JSVAL_ZERO = { BUILD_JSVAL(JSVAL_TAG_INT32, 0) };
159 JS_PUBLIC_DATA(jsval) JSVAL_ONE = { BUILD_JSVAL(JSVAL_TAG_INT32, 1) };
160 JS_PUBLIC_DATA(jsval) JSVAL_FALSE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_FALSE) };
161 JS_PUBLIC_DATA(jsval) JSVAL_TRUE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_TRUE) };
162 JS_PUBLIC_DATA(jsval) JSVAL_VOID = { BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0) };
163 #endif
165 /* Make sure that jschar is two bytes unsigned integer */
166 JS_STATIC_ASSERT((jschar)-1 > 0);
167 JS_STATIC_ASSERT(sizeof(jschar) == 2);
169 JS_PUBLIC_API(int64)
170 JS_Now()
172 return PRMJ_Now();
175 JS_PUBLIC_API(jsval)
176 JS_GetNaNValue(JSContext *cx)
178 return Jsvalify(cx->runtime->NaNValue);
181 JS_PUBLIC_API(jsval)
182 JS_GetNegativeInfinityValue(JSContext *cx)
184 return Jsvalify(cx->runtime->negativeInfinityValue);
187 JS_PUBLIC_API(jsval)
188 JS_GetPositiveInfinityValue(JSContext *cx)
190 return Jsvalify(cx->runtime->positiveInfinityValue);
193 JS_PUBLIC_API(jsval)
194 JS_GetEmptyStringValue(JSContext *cx)
196 return STRING_TO_JSVAL(cx->runtime->emptyString);
199 static JSBool
200 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, jsval **vpp, va_list *app)
202 const char *format;
203 JSArgumentFormatMap *map;
205 format = *formatp;
206 for (map = cx->argumentFormatMap; map; map = map->next) {
207 if (!strncmp(format, map->format, map->length)) {
208 *formatp = format + map->length;
209 return map->formatter(cx, format, fromJS, vpp, app);
212 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
213 return JS_FALSE;
216 JS_PUBLIC_API(JSBool)
217 JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format, ...)
219 va_list ap;
220 JSBool ok;
222 va_start(ap, format);
223 ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
224 va_end(ap);
225 return ok;
228 JS_PUBLIC_API(JSBool)
229 JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format, va_list ap)
231 jsval *sp;
232 JSBool required;
233 char c;
234 JSFunction *fun;
235 jsdouble d;
236 JSString *str;
237 JSObject *obj;
239 CHECK_REQUEST(cx);
240 assertSameCompartment(cx, JSValueArray(argv - 2, argc + 2));
241 sp = argv;
242 required = JS_TRUE;
243 while ((c = *format++) != '\0') {
244 if (isspace(c))
245 continue;
246 if (c == '/') {
247 required = JS_FALSE;
248 continue;
250 if (sp == argv + argc) {
251 if (required) {
252 fun = js_ValueToFunction(cx, Valueify(&argv[-2]), 0);
253 if (fun) {
254 char numBuf[12];
255 JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
256 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
257 JSMSG_MORE_ARGS_NEEDED,
258 JS_GetFunctionName(fun), numBuf,
259 (argc == 1) ? "" : "s");
261 return JS_FALSE;
263 break;
265 switch (c) {
266 case 'b':
267 *va_arg(ap, JSBool *) = js_ValueToBoolean(Valueify(*sp));
268 break;
269 case 'c':
270 if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
271 return JS_FALSE;
272 break;
273 case 'i':
274 if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
275 return JS_FALSE;
276 break;
277 case 'u':
278 if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
279 return JS_FALSE;
280 break;
281 case 'j':
282 if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
283 return JS_FALSE;
284 break;
285 case 'd':
286 if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
287 return JS_FALSE;
288 break;
289 case 'I':
290 if (!JS_ValueToNumber(cx, *sp, &d))
291 return JS_FALSE;
292 *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
293 break;
294 case 's':
295 case 'S':
296 case 'W':
297 str = js_ValueToString(cx, Valueify(*sp));
298 if (!str)
299 return JS_FALSE;
300 *sp = STRING_TO_JSVAL(str);
301 if (c == 's') {
302 const char *bytes = js_GetStringBytes(cx, str);
303 if (!bytes)
304 return JS_FALSE;
305 *va_arg(ap, const char **) = bytes;
306 } else if (c == 'W') {
307 const jschar *chars = js_GetStringChars(cx, str);
308 if (!chars)
309 return JS_FALSE;
310 *va_arg(ap, const jschar **) = chars;
311 } else {
312 *va_arg(ap, JSString **) = str;
314 break;
315 case 'o':
316 if (!js_ValueToObjectOrNull(cx, Valueify(*sp), &obj))
317 return JS_FALSE;
318 *sp = OBJECT_TO_JSVAL(obj);
319 *va_arg(ap, JSObject **) = obj;
320 break;
321 case 'f':
322 obj = js_ValueToFunctionObject(cx, Valueify(sp), 0);
323 if (!obj)
324 return JS_FALSE;
325 *sp = OBJECT_TO_JSVAL(obj);
326 *va_arg(ap, JSFunction **) = GET_FUNCTION_PRIVATE(cx, obj);
327 break;
328 case 'v':
329 *va_arg(ap, jsval *) = *sp;
330 break;
331 case '*':
332 break;
333 default:
334 format--;
335 if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
336 JS_ADDRESSOF_VA_LIST(ap))) {
337 return JS_FALSE;
339 /* NB: the formatter already updated sp, so we continue here. */
340 continue;
342 sp++;
344 return JS_TRUE;
347 JS_PUBLIC_API(JSBool)
348 JS_AddArgumentFormatter(JSContext *cx, const char *format, JSArgumentFormatter formatter)
350 size_t length;
351 JSArgumentFormatMap **mpp, *map;
353 length = strlen(format);
354 mpp = &cx->argumentFormatMap;
355 while ((map = *mpp) != NULL) {
356 /* Insert before any shorter string to match before prefixes. */
357 if (map->length < length)
358 break;
359 if (map->length == length && !strcmp(map->format, format))
360 goto out;
361 mpp = &map->next;
363 map = (JSArgumentFormatMap *) cx->malloc(sizeof *map);
364 if (!map)
365 return JS_FALSE;
366 map->format = format;
367 map->length = length;
368 map->next = *mpp;
369 *mpp = map;
370 out:
371 map->formatter = formatter;
372 return JS_TRUE;
375 JS_PUBLIC_API(void)
376 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
378 size_t length;
379 JSArgumentFormatMap **mpp, *map;
381 length = strlen(format);
382 mpp = &cx->argumentFormatMap;
383 while ((map = *mpp) != NULL) {
384 if (map->length == length && !strcmp(map->format, format)) {
385 *mpp = map->next;
386 cx->free(map);
387 return;
389 mpp = &map->next;
393 JS_PUBLIC_API(JSBool)
394 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
396 JSBool ok;
397 JSObject *obj;
398 JSString *str;
399 jsdouble d;
401 CHECK_REQUEST(cx);
402 assertSameCompartment(cx, v);
403 switch (type) {
404 case JSTYPE_VOID:
405 *vp = JSVAL_VOID;
406 ok = JS_TRUE;
407 break;
408 case JSTYPE_OBJECT:
409 ok = js_ValueToObjectOrNull(cx, Valueify(v), &obj);
410 if (ok)
411 *vp = OBJECT_TO_JSVAL(obj);
412 break;
413 case JSTYPE_FUNCTION:
414 *vp = v;
415 obj = js_ValueToFunctionObject(cx, Valueify(vp), JSV2F_SEARCH_STACK);
416 ok = (obj != NULL);
417 break;
418 case JSTYPE_STRING:
419 str = js_ValueToString(cx, Valueify(v));
420 ok = (str != NULL);
421 if (ok)
422 *vp = STRING_TO_JSVAL(str);
423 break;
424 case JSTYPE_NUMBER:
425 ok = JS_ValueToNumber(cx, v, &d);
426 if (ok)
427 *vp = DOUBLE_TO_JSVAL(d);
428 break;
429 case JSTYPE_BOOLEAN:
430 *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(Valueify(v)));
431 return JS_TRUE;
432 default: {
433 char numBuf[12];
434 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
435 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE, numBuf);
436 ok = JS_FALSE;
437 break;
440 return ok;
443 JS_PUBLIC_API(JSBool)
444 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
446 CHECK_REQUEST(cx);
447 assertSameCompartment(cx, v);
448 return js_ValueToObjectOrNull(cx, Valueify(v), objp);
451 JS_PUBLIC_API(JSFunction *)
452 JS_ValueToFunction(JSContext *cx, jsval v)
454 CHECK_REQUEST(cx);
455 assertSameCompartment(cx, v);
456 return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
459 JS_PUBLIC_API(JSFunction *)
460 JS_ValueToConstructor(JSContext *cx, jsval v)
462 CHECK_REQUEST(cx);
463 assertSameCompartment(cx, v);
464 return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
467 JS_PUBLIC_API(JSString *)
468 JS_ValueToString(JSContext *cx, jsval v)
470 CHECK_REQUEST(cx);
471 assertSameCompartment(cx, v);
472 return js_ValueToString(cx, Valueify(v));
475 JS_PUBLIC_API(JSString *)
476 JS_ValueToSource(JSContext *cx, jsval v)
478 CHECK_REQUEST(cx);
479 assertSameCompartment(cx, v);
480 return js_ValueToSource(cx, Valueify(v));
483 JS_PUBLIC_API(JSBool)
484 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
486 CHECK_REQUEST(cx);
487 assertSameCompartment(cx, v);
489 AutoValueRooter tvr(cx, Valueify(v));
490 return ValueToNumber(cx, tvr.value(), dp);
493 JS_PUBLIC_API(JSBool)
494 JS_DoubleIsInt32(jsdouble d, jsint *ip)
496 return JSDOUBLE_IS_INT32(d, (int32_t *)ip);
499 JS_PUBLIC_API(JSBool)
500 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
502 CHECK_REQUEST(cx);
503 assertSameCompartment(cx, v);
505 AutoValueRooter tvr(cx, Valueify(v));
506 return ValueToECMAInt32(cx, tvr.value(), (int32_t *)ip);
509 JS_PUBLIC_API(JSBool)
510 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
512 CHECK_REQUEST(cx);
513 assertSameCompartment(cx, v);
515 AutoValueRooter tvr(cx, Valueify(v));
516 return ValueToECMAUint32(cx, tvr.value(), (uint32_t *)ip);
519 JS_PUBLIC_API(JSBool)
520 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
522 CHECK_REQUEST(cx);
523 assertSameCompartment(cx, v);
525 AutoValueRooter tvr(cx, Valueify(v));
526 return ValueToInt32(cx, tvr.value(), (int32_t *)ip);
529 JS_PUBLIC_API(JSBool)
530 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
532 CHECK_REQUEST(cx);
533 assertSameCompartment(cx, v);
535 AutoValueRooter tvr(cx, Valueify(v));
536 return ValueToUint16(cx, tvr.value(), (uint16_t *)ip);
539 JS_PUBLIC_API(JSBool)
540 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
542 CHECK_REQUEST(cx);
543 assertSameCompartment(cx, v);
544 *bp = js_ValueToBoolean(Valueify(v));
545 return JS_TRUE;
548 JS_PUBLIC_API(JSType)
549 JS_TypeOfValue(JSContext *cx, jsval v)
551 CHECK_REQUEST(cx);
552 assertSameCompartment(cx, v);
553 return TypeOfValue(cx, Valueify(v));
556 JS_PUBLIC_API(const char *)
557 JS_GetTypeName(JSContext *cx, JSType type)
559 if ((uintN)type >= (uintN)JSTYPE_LIMIT)
560 return NULL;
561 return JS_TYPE_STR(type);
564 JS_PUBLIC_API(JSBool)
565 JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2)
567 assertSameCompartment(cx, v1, v2);
568 return StrictlyEqual(cx, Valueify(v1), Valueify(v2));
571 JS_PUBLIC_API(JSBool)
572 JS_SameValue(JSContext *cx, jsval v1, jsval v2)
574 assertSameCompartment(cx, v1, v2);
575 return SameValue(Valueify(v1), Valueify(v2), cx);
578 /************************************************************************/
581 * Has a new runtime ever been created? This flag is used to detect unsafe
582 * changes to js_CStringsAreUTF8 after a runtime has been created, and to
583 * ensure that "first checks" on runtime creation are run only once.
585 #ifdef DEBUG
586 static JSBool js_NewRuntimeWasCalled = JS_FALSE;
587 #endif
589 JSRuntime::JSRuntime()
590 : gcChunkAllocator(&defaultGCChunkAllocator)
592 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
593 JS_INIT_CLIST(&contextList);
594 JS_INIT_CLIST(&trapList);
595 JS_INIT_CLIST(&watchPointList);
598 bool
599 JSRuntime::init(uint32 maxbytes)
601 #ifdef JS_METHODJIT_SPEW
602 JMCheckLogging();
603 #endif
605 #ifdef DEBUG
606 functionMeterFilename = getenv("JS_FUNCTION_STATFILE");
607 if (functionMeterFilename) {
608 if (!methodReadBarrierCountMap.init())
609 return false;
610 if (!unjoinedFunctionCountMap.init())
611 return false;
613 propTreeStatFilename = getenv("JS_PROPTREE_STATFILE");
614 propTreeDumpFilename = getenv("JS_PROPTREE_DUMPFILE");
615 if (meterEmptyShapes()) {
616 if (!emptyShapes.init())
617 return false;
619 #endif
621 if (!(defaultCompartment = new JSCompartment(this)) ||
622 !defaultCompartment->init() ||
623 !compartments.append(defaultCompartment)) {
624 return false;
627 if (!js_InitGC(this, maxbytes) || !js_InitAtomState(this))
628 return false;
630 #if ENABLE_YARR_JIT
631 regExpAllocator = JSC::ExecutableAllocator::create();
632 if (!regExpAllocator)
633 return false;
634 #endif
636 deflatedStringCache = new js::DeflatedStringCache();
637 if (!deflatedStringCache || !deflatedStringCache->init())
638 return false;
640 wrapObjectCallback = js::TransparentObjectWrapper;
642 #ifdef JS_THREADSAFE
643 /* this is asymmetric with JS_ShutDown: */
644 if (!js_SetupLocks(8, 16))
645 return false;
646 rtLock = JS_NEW_LOCK();
647 if (!rtLock)
648 return false;
649 stateChange = JS_NEW_CONDVAR(gcLock);
650 if (!stateChange)
651 return false;
652 debuggerLock = JS_NEW_LOCK();
653 if (!debuggerLock)
654 return false;
655 #endif
657 debugMode = JS_FALSE;
659 return propertyTree.init() && js_InitThreads(this);
662 JSRuntime::~JSRuntime()
664 #ifdef DEBUG
665 /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
666 if (!JS_CLIST_IS_EMPTY(&contextList)) {
667 JSContext *cx, *iter = NULL;
668 uintN cxcount = 0;
669 while ((cx = js_ContextIterator(this, JS_TRUE, &iter)) != NULL) {
670 fprintf(stderr,
671 "JS API usage error: found live context at %p\n",
672 (void *) cx);
673 cxcount++;
675 fprintf(stderr,
676 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
677 cxcount, (cxcount == 1) ? "" : "s");
679 #endif
681 js_FinishThreads(this);
682 js_FreeRuntimeScriptState(this);
683 js_FinishAtomState(this);
686 * Finish the deflated string cache after the last GC and after
687 * calling js_FinishAtomState, which finalizes strings.
689 delete deflatedStringCache;
690 #if ENABLE_YARR_JIT
691 delete regExpAllocator;
692 #endif
693 js_FinishGC(this);
694 #ifdef JS_THREADSAFE
695 if (gcLock)
696 JS_DESTROY_LOCK(gcLock);
697 if (gcDone)
698 JS_DESTROY_CONDVAR(gcDone);
699 if (requestDone)
700 JS_DESTROY_CONDVAR(requestDone);
701 if (rtLock)
702 JS_DESTROY_LOCK(rtLock);
703 if (stateChange)
704 JS_DESTROY_CONDVAR(stateChange);
705 if (debuggerLock)
706 JS_DESTROY_LOCK(debuggerLock);
707 #endif
708 propertyTree.finish();
711 JS_PUBLIC_API(JSRuntime *)
712 JS_NewRuntime(uint32 maxbytes)
714 #ifdef DEBUG
715 if (!js_NewRuntimeWasCalled) {
717 * This code asserts that the numbers associated with the error names
718 * in jsmsg.def are monotonically increasing. It uses values for the
719 * error names enumerated in jscntxt.c. It's not a compile-time check
720 * but it's better than nothing.
722 int errorNumber = 0;
723 #define MSG_DEF(name, number, count, exception, format) \
724 JS_ASSERT(name == errorNumber++);
725 #include "js.msg"
726 #undef MSG_DEF
728 #define MSG_DEF(name, number, count, exception, format) \
729 JS_BEGIN_MACRO \
730 uintN numfmtspecs = 0; \
731 const char *fmt; \
732 for (fmt = format; *fmt != '\0'; fmt++) { \
733 if (*fmt == '{' && isdigit(fmt[1])) \
734 ++numfmtspecs; \
736 JS_ASSERT(count == numfmtspecs); \
737 JS_END_MACRO;
738 #include "js.msg"
739 #undef MSG_DEF
741 js_NewRuntimeWasCalled = JS_TRUE;
743 #endif /* DEBUG */
745 void *mem = js_calloc(sizeof(JSRuntime));
746 if (!mem)
747 return NULL;
749 JSRuntime *rt = new (mem) JSRuntime();
750 if (!rt->init(maxbytes)) {
751 JS_DestroyRuntime(rt);
752 return NULL;
755 return rt;
758 JS_PUBLIC_API(void)
759 JS_DestroyRuntime(JSRuntime *rt)
761 rt->~JSRuntime();
763 js_free(rt);
766 #ifdef JS_REPRMETER
767 namespace reprmeter {
768 extern void js_DumpReprMeter();
770 #endif
772 JS_PUBLIC_API(void)
773 JS_ShutDown(void)
775 #ifdef MOZ_TRACEVIS
776 StopTraceVis();
777 #endif
779 #ifdef JS_OPMETER
780 extern void js_DumpOpMeters();
781 js_DumpOpMeters();
782 #endif
784 #ifdef JS_REPRMETER
785 reprmeter::js_DumpReprMeter();
786 #endif
788 #ifdef JS_THREADSAFE
789 js_CleanupLocks();
790 #endif
791 PRMJ_NowShutdown();
794 JS_PUBLIC_API(void *)
795 JS_GetRuntimePrivate(JSRuntime *rt)
797 return rt->data;
800 JS_PUBLIC_API(void)
801 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
803 rt->data = data;
806 #ifdef JS_THREADSAFE
807 static void
808 StartRequest(JSContext *cx)
810 JSThread *t = cx->thread;
811 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
813 if (t->data.requestDepth) {
814 t->data.requestDepth++;
815 } else {
816 JSRuntime *rt = cx->runtime;
817 AutoLockGC lock(rt);
819 /* Wait until the GC is finished. */
820 if (rt->gcThread != cx->thread) {
821 while (rt->gcThread)
822 JS_AWAIT_GC_DONE(rt);
825 /* Indicate that a request is running. */
826 rt->requestCount++;
827 t->data.requestDepth = 1;
830 * Adjust rt->interruptCounter to reflect any interrupts added while the
831 * thread was suspended.
833 if (t->data.interruptFlags)
834 JS_ATOMIC_INCREMENT(&rt->interruptCounter);
836 if (rt->requestCount == 1 && rt->activityCallback)
837 rt->activityCallback(rt->activityCallbackArg, true);
841 static void
842 StopRequest(JSContext *cx)
844 JSThread *t = cx->thread;
845 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
846 JS_ASSERT(t->data.requestDepth != 0);
847 if (t->data.requestDepth != 1) {
848 t->data.requestDepth--;
849 } else {
850 LeaveTrace(cx); /* for GC safety */
852 t->data.conservativeGC.updateForRequestEnd(t->suspendCount);
854 /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
855 JSRuntime *rt = cx->runtime;
856 AutoLockGC lock(rt);
858 t->data.requestDepth = 0;
861 * Adjust rt->interruptCounter to reflect any interrupts added while the
862 * thread still had active requests.
864 if (t->data.interruptFlags)
865 JS_ATOMIC_DECREMENT(&rt->interruptCounter);
867 /* Give the GC a chance to run if this was the last request running. */
868 JS_ASSERT(rt->requestCount > 0);
869 rt->requestCount--;
870 if (rt->requestCount == 0) {
871 JS_NOTIFY_REQUEST_DONE(rt);
872 if (rt->activityCallback)
873 rt->activityCallback(rt->activityCallbackArg, false);
877 #endif /* JS_THREADSAFE */
879 JS_PUBLIC_API(void)
880 JS_BeginRequest(JSContext *cx)
882 #ifdef JS_THREADSAFE
883 cx->outstandingRequests++;
884 StartRequest(cx);
885 #endif
888 JS_PUBLIC_API(void)
889 JS_EndRequest(JSContext *cx)
891 #ifdef JS_THREADSAFE
892 JS_ASSERT(cx->outstandingRequests != 0);
893 cx->outstandingRequests--;
894 StopRequest(cx);
895 #endif
898 /* Yield to pending GC operations, regardless of request depth */
899 JS_PUBLIC_API(void)
900 JS_YieldRequest(JSContext *cx)
902 #ifdef JS_THREADSAFE
903 CHECK_REQUEST(cx);
904 JS_ResumeRequest(cx, JS_SuspendRequest(cx));
905 #endif
908 JS_PUBLIC_API(jsrefcount)
909 JS_SuspendRequest(JSContext *cx)
911 #ifdef JS_THREADSAFE
912 JSThread *t = cx->thread;
913 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
915 jsrefcount saveDepth = t->data.requestDepth;
916 if (!saveDepth)
917 return 0;
919 t->suspendCount++;
920 t->data.requestDepth = 1;
921 StopRequest(cx);
922 return saveDepth;
923 #else
924 return 0;
925 #endif
928 JS_PUBLIC_API(void)
929 JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
931 #ifdef JS_THREADSAFE
932 JSThread *t = cx->thread;
933 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
934 if (saveDepth == 0)
935 return;
936 JS_ASSERT(saveDepth >= 1);
937 JS_ASSERT(!t->data.requestDepth);
938 JS_ASSERT(t->suspendCount);
939 StartRequest(cx);
940 t->data.requestDepth = saveDepth;
941 t->suspendCount--;
942 #endif
945 JS_PUBLIC_API(void)
946 JS_Lock(JSRuntime *rt)
948 JS_LOCK_RUNTIME(rt);
951 JS_PUBLIC_API(void)
952 JS_Unlock(JSRuntime *rt)
954 JS_UNLOCK_RUNTIME(rt);
957 JS_PUBLIC_API(JSContextCallback)
958 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
960 JSContextCallback old;
962 old = rt->cxCallback;
963 rt->cxCallback = cxCallback;
964 return old;
967 JS_PUBLIC_API(JSContext *)
968 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
970 return js_NewContext(rt, stackChunkSize);
973 JS_PUBLIC_API(void)
974 JS_DestroyContext(JSContext *cx)
976 js_DestroyContext(cx, JSDCM_FORCE_GC);
979 JS_PUBLIC_API(void)
980 JS_DestroyContextNoGC(JSContext *cx)
982 js_DestroyContext(cx, JSDCM_NO_GC);
985 JS_PUBLIC_API(void)
986 JS_DestroyContextMaybeGC(JSContext *cx)
988 js_DestroyContext(cx, JSDCM_MAYBE_GC);
991 JS_PUBLIC_API(void *)
992 JS_GetContextPrivate(JSContext *cx)
994 return cx->data;
997 JS_PUBLIC_API(void)
998 JS_SetContextPrivate(JSContext *cx, void *data)
1000 cx->data = data;
1003 JS_PUBLIC_API(JSRuntime *)
1004 JS_GetRuntime(JSContext *cx)
1006 return cx->runtime;
1009 JS_PUBLIC_API(JSContext *)
1010 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
1012 return js_ContextIterator(rt, JS_TRUE, iterp);
1015 JS_PUBLIC_API(JSVersion)
1016 JS_GetVersion(JSContext *cx)
1018 return VersionNumber(cx->findVersion());
1021 static void
1022 CheckOptionVersionSync(JSContext *cx)
1024 #if DEBUG
1025 uint32 options = cx->options;
1026 JSVersion version = cx->findVersion();
1027 JS_ASSERT(OptionsHasXML(options) == VersionHasXML(version));
1028 JS_ASSERT(OptionsHasAnonFunFix(options) == VersionHasAnonFunFix(version));
1029 #endif
1032 JS_PUBLIC_API(JSVersion)
1033 JS_SetVersion(JSContext *cx, JSVersion newVersion)
1035 JS_ASSERT(VersionIsKnown(newVersion));
1036 JS_ASSERT(!VersionHasFlags(newVersion));
1037 JSVersion newVersionNumber = newVersion;
1039 JSVersion oldVersion = cx->findVersion();
1040 JSVersion oldVersionNumber = VersionNumber(oldVersion);
1041 if (oldVersionNumber == newVersionNumber)
1042 return oldVersionNumber; /* No override actually occurs! */
1044 /* We no longer support 1.4 or below. */
1045 if (newVersionNumber != JSVERSION_DEFAULT && newVersionNumber <= JSVERSION_1_4)
1046 return oldVersionNumber;
1048 VersionCloneFlags(oldVersion, &newVersion);
1049 cx->maybeOverrideVersion(newVersion);
1050 CheckOptionVersionSync(cx);
1051 return oldVersionNumber;
1054 static struct v2smap {
1055 JSVersion version;
1056 const char *string;
1057 } v2smap[] = {
1058 {JSVERSION_1_0, "1.0"},
1059 {JSVERSION_1_1, "1.1"},
1060 {JSVERSION_1_2, "1.2"},
1061 {JSVERSION_1_3, "1.3"},
1062 {JSVERSION_1_4, "1.4"},
1063 {JSVERSION_ECMA_3, "ECMAv3"},
1064 {JSVERSION_1_5, "1.5"},
1065 {JSVERSION_1_6, "1.6"},
1066 {JSVERSION_1_7, "1.7"},
1067 {JSVERSION_1_8, "1.8"},
1068 {JSVERSION_ECMA_5, "ECMAv5"},
1069 {JSVERSION_DEFAULT, js_default_str},
1070 {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
1073 JS_PUBLIC_API(const char *)
1074 JS_VersionToString(JSVersion version)
1076 int i;
1078 for (i = 0; v2smap[i].string; i++)
1079 if (v2smap[i].version == version)
1080 return v2smap[i].string;
1081 return "unknown";
1084 JS_PUBLIC_API(JSVersion)
1085 JS_StringToVersion(const char *string)
1087 int i;
1089 for (i = 0; v2smap[i].string; i++)
1090 if (strcmp(v2smap[i].string, string) == 0)
1091 return v2smap[i].version;
1092 return JSVERSION_UNKNOWN;
1095 JS_PUBLIC_API(uint32)
1096 JS_GetOptions(JSContext *cx)
1099 * Can't check option/version synchronization here.
1100 * We may have been synchronized with a script version that was formerly on
1101 * the stack, but has now been popped.
1103 return cx->options;
1106 JS_PUBLIC_API(uint32)
1107 JS_SetOptions(JSContext *cx, uint32 options)
1109 AutoLockGC lock(cx->runtime);
1110 uint32 oldopts = cx->options;
1111 cx->options = options;
1112 SyncOptionsToVersion(cx);
1113 cx->updateJITEnabled();
1114 CheckOptionVersionSync(cx);
1115 return oldopts;
1118 JS_PUBLIC_API(uint32)
1119 JS_ToggleOptions(JSContext *cx, uint32 options)
1121 AutoLockGC lock(cx->runtime);
1122 CheckOptionVersionSync(cx);
1123 uint32 oldopts = cx->options;
1124 cx->options ^= options;
1125 (void) SyncOptionsToVersion(cx);
1126 cx->updateJITEnabled();
1127 CheckOptionVersionSync(cx);
1128 return oldopts;
1131 JS_PUBLIC_API(const char *)
1132 JS_GetImplementationVersion(void)
1134 return "JavaScript-C 1.8.0 pre-release 1 2007-10-03";
1137 JS_PUBLIC_API(JSCompartmentCallback)
1138 JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback)
1140 JSCompartmentCallback old = rt->compartmentCallback;
1141 rt->compartmentCallback = callback;
1142 return old;
1145 JS_PUBLIC_API(JSWrapObjectCallback)
1146 JS_SetWrapObjectCallbacks(JSRuntime *rt,
1147 JSWrapObjectCallback callback,
1148 JSPreWrapCallback precallback)
1150 JSWrapObjectCallback old = rt->wrapObjectCallback;
1151 rt->wrapObjectCallback = callback;
1152 rt->preWrapObjectCallback = precallback;
1153 return old;
1156 JS_PUBLIC_API(JSCrossCompartmentCall *)
1157 JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
1159 CHECK_REQUEST(cx);
1161 JS_ASSERT(target);
1162 AutoCompartment *call = new AutoCompartment(cx, target);
1163 if (!call)
1164 return NULL;
1165 if (!call->enter()) {
1166 delete call;
1167 return NULL;
1169 return reinterpret_cast<JSCrossCompartmentCall *>(call);
1172 JS_PUBLIC_API(void)
1173 JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
1175 AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
1176 CHECK_REQUEST(realcall->context);
1177 realcall->leave();
1178 delete realcall;
1181 bool
1182 JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target)
1184 JS_ASSERT(!call);
1185 if (cx->compartment == target->getCompartment()) {
1186 call = reinterpret_cast<JSCrossCompartmentCall*>(1);
1187 return true;
1189 call = JS_EnterCrossCompartmentCall(cx, target);
1190 return call != NULL;
1193 void
1194 JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target)
1196 (void) enter(cx, target);
1199 JS_PUBLIC_API(void *)
1200 JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data)
1202 CHECK_REQUEST(cx);
1203 void *old = compartment->data;
1204 compartment->data = data;
1205 return old;
1208 JS_PUBLIC_API(void *)
1209 JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment)
1211 CHECK_REQUEST(cx);
1212 return compartment->data;
1215 JS_PUBLIC_API(JSBool)
1216 JS_WrapObject(JSContext *cx, JSObject **objp)
1218 CHECK_REQUEST(cx);
1219 return cx->compartment->wrap(cx, objp);
1222 JS_PUBLIC_API(JSBool)
1223 JS_WrapValue(JSContext *cx, jsval *vp)
1225 CHECK_REQUEST(cx);
1226 return cx->compartment->wrap(cx, Valueify(vp));
1229 JS_PUBLIC_API(JSObject *)
1230 JS_TransplantWrapper(JSContext *cx, JSObject *wrapper, JSObject *target)
1232 JS_ASSERT(wrapper->isWrapper());
1235 * This function is called when a window is navigating. In that case, we
1236 * need to "move" the window from wrapper's compartment to target's
1237 * compartment.
1239 JSCompartment *destination = target->getCompartment();
1240 if (wrapper->getCompartment() == destination) {
1241 // If the wrapper is in the same compartment as the destination, then
1242 // we know that we won't find wrapper in the destination's cross
1243 // compartment map and that the same object will continue to work.
1244 if (!wrapper->swap(cx, target))
1245 return NULL;
1246 return wrapper;
1249 JSObject *obj;
1250 WrapperMap &map = destination->crossCompartmentWrappers;
1251 Value wrapperv = ObjectValue(*wrapper);
1253 // There might already be a wrapper for the window in the new compartment.
1254 if (WrapperMap::Ptr p = map.lookup(wrapperv)) {
1255 // If there is, make it the primary outer window proxy around the
1256 // inner (accomplished by swapping target's innards with the old,
1257 // possibly security wrapper, innards).
1258 obj = &p->value.toObject();
1259 map.remove(p);
1260 if (!obj->swap(cx, target))
1261 return NULL;
1262 } else {
1263 // Otherwise, this is going to be our outer window proxy in the new
1264 // compartment.
1265 obj = target;
1268 // Now, iterate through other scopes looking for references to the old
1269 // outer window. They need to be updated to point at the new outer window.
1270 // They also might transition between different types of security wrappers
1271 // based on whether the new compartment is same origin with them.
1272 Value targetv = ObjectValue(*obj);
1273 WrapperVector &vector = cx->runtime->compartments;
1274 AutoValueVector toTransplant(cx);
1275 toTransplant.reserve(vector.length());
1277 for (JSCompartment **p = vector.begin(), **end = vector.end(); p != end; ++p) {
1278 WrapperMap &pmap = (*p)->crossCompartmentWrappers;
1279 if (WrapperMap::Ptr wp = pmap.lookup(wrapperv)) {
1280 // We found a wrapper. Remember and root it.
1281 toTransplant.append(wp->value);
1285 for (Value *begin = toTransplant.begin(), *end = toTransplant.end(); begin != end; ++begin) {
1286 JSObject *wobj = &begin->toObject();
1287 JSCompartment *wcompartment = wobj->compartment();
1288 WrapperMap &pmap = wcompartment->crossCompartmentWrappers;
1289 JS_ASSERT(pmap.lookup(wrapperv));
1290 pmap.remove(wrapperv);
1292 // First, we wrap it in the new compartment. This will return a
1293 // new wrapper.
1294 AutoCompartment ac(cx, wobj);
1295 JSObject *tobj = obj;
1296 if (!ac.enter() || !wcompartment->wrap(cx, &tobj))
1297 return NULL;
1299 // Now, because we need to maintain object identity, we do a brain
1300 // transplant on the old object. At the same time, we update the
1301 // entry in the compartment's wrapper map to point to the old
1302 // wrapper.
1303 JS_ASSERT(tobj != wobj);
1304 if (!wobj->swap(cx, tobj))
1305 return NULL;
1306 pmap.put(targetv, ObjectValue(*wobj));
1309 // Lastly, update the old outer window proxy to point to the new one.
1311 AutoCompartment ac(cx, wrapper);
1312 JSObject *tobj = obj;
1313 if (!ac.enter() || !JS_WrapObject(cx, &tobj))
1314 return NULL;
1315 if (!wrapper->swap(cx, tobj))
1316 return NULL;
1317 wrapper->getCompartment()->crossCompartmentWrappers.put(targetv, wrapperv);
1320 return obj;
1323 JS_PUBLIC_API(JSObject *)
1324 JS_GetGlobalObject(JSContext *cx)
1326 return cx->globalObject;
1329 JS_PUBLIC_API(void)
1330 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1332 CHECK_REQUEST(cx);
1334 cx->globalObject = obj;
1335 if (!cx->hasfp())
1336 cx->resetCompartment();
1339 class AutoResolvingEntry {
1340 public:
1341 AutoResolvingEntry() : entry(NULL) {}
1344 * Returns false on error. But N.B. if obj[id] was already being resolved,
1345 * this is a no-op, and we silently treat that as success.
1347 bool start(JSContext *cx, JSObject *obj, jsid id, uint32 flag) {
1348 JS_ASSERT(!entry);
1349 this->cx = cx;
1350 key.obj = obj;
1351 key.id = id;
1352 this->flag = flag;
1353 bool ok = !!js_StartResolving(cx, &key, flag, &entry);
1354 JS_ASSERT_IF(!ok, !entry);
1355 return ok;
1358 ~AutoResolvingEntry() {
1359 if (entry)
1360 js_StopResolving(cx, &key, flag, NULL, 0);
1363 private:
1364 JSContext *cx;
1365 JSResolvingKey key;
1366 uint32 flag;
1367 JSResolvingEntry *entry;
1370 JSObject *
1371 js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1373 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
1374 JSObject *fun_proto, *obj_proto;
1376 /* If cx has no global object, use obj so prototypes can be found. */
1377 if (!cx->globalObject)
1378 JS_SetGlobalObject(cx, obj);
1380 /* Record Function and Object in cx->resolvingTable. */
1381 AutoResolvingEntry e1, e2;
1382 JSAtom **classAtoms = cx->runtime->atomState.classAtoms;
1383 if (!e1.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Function]), JSRESFLAG_LOOKUP) ||
1384 !e2.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Object]), JSRESFLAG_LOOKUP)) {
1385 return NULL;
1388 /* Initialize the function class first so constructors can be made. */
1389 if (!js_GetClassPrototype(cx, obj, JSProto_Function, &fun_proto))
1390 return NULL;
1391 if (!fun_proto) {
1392 fun_proto = js_InitFunctionClass(cx, obj);
1393 if (!fun_proto)
1394 return NULL;
1395 } else {
1396 JSObject *ctor;
1398 ctor = JS_GetConstructor(cx, fun_proto);
1399 if (!ctor)
1400 return NULL;
1401 obj->defineProperty(cx, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
1402 ObjectValue(*ctor), 0, 0, 0);
1405 /* Initialize the object class next so Object.prototype works. */
1406 if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto))
1407 return NULL;
1408 if (!obj_proto)
1409 obj_proto = js_InitObjectClass(cx, obj);
1410 if (!obj_proto)
1411 return NULL;
1413 /* Function.prototype and the global object delegate to Object.prototype. */
1414 fun_proto->setProto(obj_proto);
1415 if (!obj->getProto())
1416 obj->setProto(obj_proto);
1418 return fun_proto;
1421 JS_PUBLIC_API(JSBool)
1422 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1424 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
1425 CHECK_REQUEST(cx);
1428 * JS_SetGlobalObject might or might not change cx's compartment, so call
1429 * it before assertSameCompartment. (The API contract is that *after* this,
1430 * cx and obj must be in the same compartment.)
1432 if (!cx->globalObject)
1433 JS_SetGlobalObject(cx, obj);
1434 assertSameCompartment(cx, obj);
1436 /* Define a top-level property 'undefined' with the undefined value. */
1437 JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1438 if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1439 PropertyStub, PropertyStub,
1440 JSPROP_PERMANENT | JSPROP_READONLY)) {
1441 return JS_FALSE;
1444 /* Function and Object require cooperative bootstrapping magic. */
1445 if (!js_InitFunctionAndObjectClasses(cx, obj))
1446 return JS_FALSE;
1448 /* Initialize the rest of the standard objects and functions. */
1449 return js_InitArrayClass(cx, obj) &&
1450 js_InitBooleanClass(cx, obj) &&
1451 js_InitExceptionClasses(cx, obj) &&
1452 js_InitMathClass(cx, obj) &&
1453 js_InitNumberClass(cx, obj) &&
1454 js_InitJSONClass(cx, obj) &&
1455 js_InitRegExpClass(cx, obj) &&
1456 js_InitStringClass(cx, obj) &&
1457 js_InitTypedArrayClasses(cx, obj) &&
1458 #if JS_HAS_XML_SUPPORT
1459 js_InitXMLClasses(cx, obj) &&
1460 #endif
1461 #if JS_HAS_GENERATORS
1462 js_InitIteratorClasses(cx, obj) &&
1463 #endif
1464 js_InitDateClass(cx, obj) &&
1465 js_InitProxyClass(cx, obj);
1468 #define CLASP(name) (&js_##name##Class)
1469 #define TYPED_ARRAY_CLASP(type) (&TypedArray::fastClasses[TypedArray::type])
1470 #define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
1471 #define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
1472 #define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
1473 #define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
1475 typedef struct JSStdName {
1476 JSObjectOp init;
1477 size_t atomOffset; /* offset of atom pointer in JSAtomState */
1478 const char *name; /* null if atom is pre-pinned, else name */
1479 Class *clasp;
1480 } JSStdName;
1482 static JSAtom *
1483 StdNameToAtom(JSContext *cx, JSStdName *stdn)
1485 size_t offset;
1486 JSAtom *atom;
1487 const char *name;
1489 offset = stdn->atomOffset;
1490 atom = OFFSET_TO_ATOM(cx->runtime, offset);
1491 if (!atom) {
1492 name = stdn->name;
1493 if (name) {
1494 atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1495 OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1498 return atom;
1502 * Table of class initializers and their atom offsets in rt->atomState.
1503 * If you add a "standard" class, remember to update this table.
1505 static JSStdName standard_class_atoms[] = {
1506 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Function)},
1507 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Object)},
1508 {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)},
1509 {js_InitBooleanClass, EAGER_ATOM_AND_CLASP(Boolean)},
1510 {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)},
1511 {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)},
1512 {js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)},
1513 {js_InitStringClass, EAGER_ATOM_AND_CLASP(String)},
1514 {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)},
1515 {js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)},
1516 #if JS_HAS_XML_SUPPORT
1517 {js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)},
1518 {js_InitNamespaceClass, EAGER_ATOM_AND_CLASP(Namespace)},
1519 {js_InitQNameClass, EAGER_ATOM_AND_CLASP(QName)},
1520 #endif
1521 #if JS_HAS_GENERATORS
1522 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
1523 #endif
1524 {js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
1525 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
1526 {NULL, 0, NULL, NULL}
1530 * Table of top-level function and constant names and their init functions.
1531 * If you add a "standard" global function or property, remember to update
1532 * this table.
1534 static JSStdName standard_class_names[] = {
1535 {js_InitObjectClass, EAGER_ATOM(eval), CLASP(Object)},
1537 /* Global properties and functions defined by the Number class. */
1538 {js_InitNumberClass, LAZY_ATOM(NaN), CLASP(Number)},
1539 {js_InitNumberClass, LAZY_ATOM(Infinity), CLASP(Number)},
1540 {js_InitNumberClass, LAZY_ATOM(isNaN), CLASP(Number)},
1541 {js_InitNumberClass, LAZY_ATOM(isFinite), CLASP(Number)},
1542 {js_InitNumberClass, LAZY_ATOM(parseFloat), CLASP(Number)},
1543 {js_InitNumberClass, LAZY_ATOM(parseInt), CLASP(Number)},
1545 /* String global functions. */
1546 {js_InitStringClass, LAZY_ATOM(escape), CLASP(String)},
1547 {js_InitStringClass, LAZY_ATOM(unescape), CLASP(String)},
1548 {js_InitStringClass, LAZY_ATOM(decodeURI), CLASP(String)},
1549 {js_InitStringClass, LAZY_ATOM(encodeURI), CLASP(String)},
1550 {js_InitStringClass, LAZY_ATOM(decodeURIComponent), CLASP(String)},
1551 {js_InitStringClass, LAZY_ATOM(encodeURIComponent), CLASP(String)},
1552 #if JS_HAS_UNEVAL
1553 {js_InitStringClass, LAZY_ATOM(uneval), CLASP(String)},
1554 #endif
1556 /* Exception constructors. */
1557 {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)},
1558 {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
1559 {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
1560 {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
1561 {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
1562 {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
1563 {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
1564 {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)},
1566 #if JS_HAS_XML_SUPPORT
1567 {js_InitAnyNameClass, EAGER_ATOM_AND_CLASP(AnyName)},
1568 {js_InitAttributeNameClass, EAGER_ATOM_AND_CLASP(AttributeName)},
1569 {js_InitXMLClass, LAZY_ATOM(XMLList), CLASP(XML)},
1570 {js_InitXMLClass, LAZY_ATOM(isXMLName), CLASP(XML)},
1571 #endif
1573 #if JS_HAS_GENERATORS
1574 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)},
1575 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Generator)},
1576 #endif
1578 /* Typed Arrays */
1579 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
1580 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int8Array), TYPED_ARRAY_CLASP(TYPE_INT8)},
1581 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8Array), TYPED_ARRAY_CLASP(TYPE_UINT8)},
1582 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int16Array), TYPED_ARRAY_CLASP(TYPE_INT16)},
1583 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint16Array), TYPED_ARRAY_CLASP(TYPE_UINT16)},
1584 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int32Array), TYPED_ARRAY_CLASP(TYPE_INT32)},
1585 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint32Array), TYPED_ARRAY_CLASP(TYPE_UINT32)},
1586 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float32Array), TYPED_ARRAY_CLASP(TYPE_FLOAT32)},
1587 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
1588 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8ClampedArray),
1589 TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
1591 {js_InitProxyClass, EAGER_ATOM_AND_CLASP(Proxy)},
1593 {NULL, 0, NULL, NULL}
1596 static JSStdName object_prototype_names[] = {
1597 /* Object.prototype properties (global delegates to Object.prototype). */
1598 {js_InitObjectClass, EAGER_ATOM(proto), CLASP(Object)},
1599 #if JS_HAS_TOSOURCE
1600 {js_InitObjectClass, EAGER_ATOM(toSource), CLASP(Object)},
1601 #endif
1602 {js_InitObjectClass, EAGER_ATOM(toString), CLASP(Object)},
1603 {js_InitObjectClass, EAGER_ATOM(toLocaleString), CLASP(Object)},
1604 {js_InitObjectClass, EAGER_ATOM(valueOf), CLASP(Object)},
1605 #if JS_HAS_OBJ_WATCHPOINT
1606 {js_InitObjectClass, LAZY_ATOM(watch), CLASP(Object)},
1607 {js_InitObjectClass, LAZY_ATOM(unwatch), CLASP(Object)},
1608 #endif
1609 {js_InitObjectClass, LAZY_ATOM(hasOwnProperty), CLASP(Object)},
1610 {js_InitObjectClass, LAZY_ATOM(isPrototypeOf), CLASP(Object)},
1611 {js_InitObjectClass, LAZY_ATOM(propertyIsEnumerable), CLASP(Object)},
1612 #if OLD_GETTER_SETTER_METHODS
1613 {js_InitObjectClass, LAZY_ATOM(defineGetter), CLASP(Object)},
1614 {js_InitObjectClass, LAZY_ATOM(defineSetter), CLASP(Object)},
1615 {js_InitObjectClass, LAZY_ATOM(lookupGetter), CLASP(Object)},
1616 {js_InitObjectClass, LAZY_ATOM(lookupSetter), CLASP(Object)},
1617 #endif
1619 {NULL, 0, NULL, NULL}
1622 JS_PUBLIC_API(JSBool)
1623 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
1625 JSString *idstr;
1626 JSRuntime *rt;
1627 JSAtom *atom;
1628 JSStdName *stdnm;
1629 uintN i;
1631 CHECK_REQUEST(cx);
1632 assertSameCompartment(cx, obj, id);
1633 *resolved = JS_FALSE;
1635 rt = cx->runtime;
1636 JS_ASSERT(rt->state != JSRTS_DOWN);
1637 if (rt->state == JSRTS_LANDING || !JSID_IS_ATOM(id))
1638 return JS_TRUE;
1640 idstr = JSID_TO_STRING(id);
1642 /* Check whether we're resolving 'undefined', and define it if so. */
1643 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1644 if (idstr == ATOM_TO_STRING(atom)) {
1645 *resolved = JS_TRUE;
1646 return obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1647 PropertyStub, PropertyStub,
1648 JSPROP_PERMANENT | JSPROP_READONLY);
1651 /* Try for class constructors/prototypes named by well-known atoms. */
1652 stdnm = NULL;
1653 for (i = 0; standard_class_atoms[i].init; i++) {
1654 JS_ASSERT(standard_class_atoms[i].clasp);
1655 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1656 if (idstr == ATOM_TO_STRING(atom)) {
1657 stdnm = &standard_class_atoms[i];
1658 break;
1662 if (!stdnm) {
1663 /* Try less frequently used top-level functions and constants. */
1664 for (i = 0; standard_class_names[i].init; i++) {
1665 JS_ASSERT(standard_class_names[i].clasp);
1666 atom = StdNameToAtom(cx, &standard_class_names[i]);
1667 if (!atom)
1668 return JS_FALSE;
1669 if (idstr == ATOM_TO_STRING(atom)) {
1670 stdnm = &standard_class_names[i];
1671 break;
1675 if (!stdnm && !obj->getProto()) {
1677 * Try even less frequently used names delegated from the global
1678 * object to Object.prototype, but only if the Object class hasn't
1679 * yet been initialized.
1681 for (i = 0; object_prototype_names[i].init; i++) {
1682 JS_ASSERT(object_prototype_names[i].clasp);
1683 atom = StdNameToAtom(cx, &object_prototype_names[i]);
1684 if (!atom)
1685 return JS_FALSE;
1686 if (idstr == ATOM_TO_STRING(atom)) {
1687 stdnm = &object_prototype_names[i];
1688 break;
1694 if (stdnm) {
1696 * If this standard class is anonymous, then we don't want to resolve
1697 * by name.
1699 JS_ASSERT(obj->getClass()->flags & JSCLASS_IS_GLOBAL);
1700 if (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)
1701 return JS_TRUE;
1703 JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(stdnm->clasp);
1704 if (obj->getReservedSlot(key).isObject())
1705 return JS_TRUE;
1707 if (!stdnm->init(cx, obj))
1708 return JS_FALSE;
1709 *resolved = JS_TRUE;
1711 return JS_TRUE;
1714 JS_PUBLIC_API(JSBool)
1715 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1717 JSRuntime *rt;
1718 JSAtom *atom;
1719 uintN i;
1721 CHECK_REQUEST(cx);
1722 assertSameCompartment(cx, obj);
1723 rt = cx->runtime;
1725 /* Check whether we need to bind 'undefined' and define it if so. */
1726 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1727 if (!obj->nativeContains(ATOM_TO_JSID(atom)) &&
1728 !obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1729 PropertyStub, PropertyStub,
1730 JSPROP_PERMANENT | JSPROP_READONLY)) {
1731 return JS_FALSE;
1734 /* Initialize any classes that have not been resolved yet. */
1735 for (i = 0; standard_class_atoms[i].init; i++) {
1736 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1737 if (!obj->nativeContains(ATOM_TO_JSID(atom)) &&
1738 !standard_class_atoms[i].init(cx, obj)) {
1739 return JS_FALSE;
1743 return JS_TRUE;
1746 namespace js {
1748 JSIdArray *
1749 NewIdArray(JSContext *cx, jsint length)
1751 JSIdArray *ida;
1753 ida = (JSIdArray *)
1754 cx->calloc(offsetof(JSIdArray, vector) + length * sizeof(jsval));
1755 if (ida)
1756 ida->length = length;
1757 return ida;
1763 * Unlike realloc(3), this function frees ida on failure.
1765 static JSIdArray *
1766 SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
1768 JSIdArray *rida;
1770 rida = (JSIdArray *)
1771 JS_realloc(cx, ida,
1772 offsetof(JSIdArray, vector) + length * sizeof(jsval));
1773 if (!rida) {
1774 JS_DestroyIdArray(cx, ida);
1775 } else {
1776 rida->length = length;
1778 return rida;
1781 static JSIdArray *
1782 AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1784 jsint i, length;
1786 i = *ip;
1787 length = ida->length;
1788 if (i >= length) {
1789 ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
1790 if (!ida)
1791 return NULL;
1792 JS_ASSERT(i < ida->length);
1794 ida->vector[i] = ATOM_TO_JSID(atom);
1795 *ip = i + 1;
1796 return ida;
1799 static JSIdArray *
1800 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
1801 jsint *ip, JSBool *foundp)
1803 *foundp = obj->nativeContains(ATOM_TO_JSID(atom));
1804 if (*foundp)
1805 ida = AddAtomToArray(cx, atom, ida, ip);
1806 return ida;
1809 JS_PUBLIC_API(JSIdArray *)
1810 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, JSIdArray *ida)
1812 JSRuntime *rt;
1813 jsint i, j, k;
1814 JSAtom *atom;
1815 JSBool found;
1816 JSObjectOp init;
1818 CHECK_REQUEST(cx);
1819 assertSameCompartment(cx, obj, ida);
1820 rt = cx->runtime;
1821 if (ida) {
1822 i = ida->length;
1823 } else {
1824 ida = NewIdArray(cx, 8);
1825 if (!ida)
1826 return NULL;
1827 i = 0;
1830 /* Check whether 'undefined' has been resolved and enumerate it if so. */
1831 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1832 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1833 if (!ida)
1834 return NULL;
1836 /* Enumerate only classes that *have* been resolved. */
1837 for (j = 0; standard_class_atoms[j].init; j++) {
1838 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
1839 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1840 if (!ida)
1841 return NULL;
1843 if (found) {
1844 init = standard_class_atoms[j].init;
1846 for (k = 0; standard_class_names[k].init; k++) {
1847 if (standard_class_names[k].init == init) {
1848 atom = StdNameToAtom(cx, &standard_class_names[k]);
1849 ida = AddAtomToArray(cx, atom, ida, &i);
1850 if (!ida)
1851 return NULL;
1855 if (init == js_InitObjectClass) {
1856 for (k = 0; object_prototype_names[k].init; k++) {
1857 atom = StdNameToAtom(cx, &object_prototype_names[k]);
1858 ida = AddAtomToArray(cx, atom, ida, &i);
1859 if (!ida)
1860 return NULL;
1866 /* Trim to exact length. */
1867 return SetIdArrayLength(cx, ida, i);
1870 #undef CLASP
1871 #undef EAGER_ATOM
1872 #undef EAGER_CLASS_ATOM
1873 #undef EAGER_ATOM_CLASP
1874 #undef LAZY_ATOM
1876 JS_PUBLIC_API(JSBool)
1877 JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp)
1879 CHECK_REQUEST(cx);
1880 assertSameCompartment(cx, obj);
1881 return js_GetClassObject(cx, obj, key, objp);
1884 JS_PUBLIC_API(JSObject *)
1885 JS_GetScopeChain(JSContext *cx)
1887 CHECK_REQUEST(cx);
1888 return GetScopeChain(cx);
1891 JS_PUBLIC_API(JSObject *)
1892 JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
1894 assertSameCompartment(cx, obj);
1895 return obj->getGlobal();
1898 JS_PUBLIC_API(JSObject *)
1899 JS_GetGlobalForScopeChain(JSContext *cx)
1901 CHECK_REQUEST(cx);
1902 return GetGlobalForScopeChain(cx);
1905 JS_PUBLIC_API(jsval)
1906 JS_ComputeThis(JSContext *cx, jsval *vp)
1908 assertSameCompartment(cx, JSValueArray(vp, 2));
1909 if (!ComputeThisFromVp(cx, Valueify(vp)))
1910 return JSVAL_NULL;
1911 return vp[1];
1914 JS_PUBLIC_API(void *)
1915 JS_malloc(JSContext *cx, size_t nbytes)
1917 return cx->malloc(nbytes);
1920 JS_PUBLIC_API(void *)
1921 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1923 return cx->realloc(p, nbytes);
1926 JS_PUBLIC_API(void)
1927 JS_free(JSContext *cx, void *p)
1929 return cx->free(p);
1932 JS_PUBLIC_API(void)
1933 JS_updateMallocCounter(JSContext *cx, size_t nbytes)
1935 return cx->runtime->updateMallocCounter(nbytes);
1938 JS_PUBLIC_API(char *)
1939 JS_strdup(JSContext *cx, const char *s)
1941 size_t n;
1942 void *p;
1944 n = strlen(s) + 1;
1945 p = cx->malloc(n);
1946 if (!p)
1947 return NULL;
1948 return (char *)memcpy(p, s, n);
1951 JS_PUBLIC_API(JSBool)
1952 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
1954 d = JS_CANONICALIZE_NAN(d);
1955 Valueify(rval)->setNumber(d);
1956 return JS_TRUE;
1959 #undef JS_AddRoot
1961 JS_PUBLIC_API(JSBool)
1962 JS_AddValueRoot(JSContext *cx, jsval *vp)
1964 CHECK_REQUEST(cx);
1965 return js_AddRoot(cx, Valueify(vp), NULL);
1968 JS_PUBLIC_API(JSBool)
1969 JS_AddStringRoot(JSContext *cx, JSString **rp)
1971 CHECK_REQUEST(cx);
1972 return js_AddGCThingRoot(cx, (void **)rp, NULL);
1975 JS_PUBLIC_API(JSBool)
1976 JS_AddObjectRoot(JSContext *cx, JSObject **rp)
1978 CHECK_REQUEST(cx);
1979 return js_AddGCThingRoot(cx, (void **)rp, NULL);
1982 JS_PUBLIC_API(JSBool)
1983 JS_AddGCThingRoot(JSContext *cx, void **rp)
1985 CHECK_REQUEST(cx);
1986 return js_AddGCThingRoot(cx, (void **)rp, NULL);
1989 JS_PUBLIC_API(JSBool)
1990 JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name)
1992 CHECK_REQUEST(cx);
1993 return js_AddRoot(cx, Valueify(vp), name);
1996 JS_PUBLIC_API(JSBool)
1997 JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name)
1999 CHECK_REQUEST(cx);
2000 return js_AddGCThingRoot(cx, (void **)rp, name);
2003 JS_PUBLIC_API(JSBool)
2004 JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name)
2006 CHECK_REQUEST(cx);
2007 return js_AddGCThingRoot(cx, (void **)rp, name);
2010 JS_PUBLIC_API(JSBool)
2011 JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name)
2013 CHECK_REQUEST(cx);
2014 return js_AddGCThingRoot(cx, (void **)rp, name);
2017 JS_PUBLIC_API(JSBool)
2018 JS_RemoveValueRoot(JSContext *cx, jsval *vp)
2020 CHECK_REQUEST(cx);
2021 return js_RemoveRoot(cx->runtime, (void *)vp);
2024 JS_PUBLIC_API(JSBool)
2025 JS_RemoveStringRoot(JSContext *cx, JSString **rp)
2027 CHECK_REQUEST(cx);
2028 return js_RemoveRoot(cx->runtime, (void *)rp);
2031 JS_PUBLIC_API(JSBool)
2032 JS_RemoveObjectRoot(JSContext *cx, JSObject **rp)
2034 CHECK_REQUEST(cx);
2035 return js_RemoveRoot(cx->runtime, (void *)rp);
2038 JS_PUBLIC_API(JSBool)
2039 JS_RemoveGCThingRoot(JSContext *cx, void **rp)
2041 CHECK_REQUEST(cx);
2042 return js_RemoveRoot(cx->runtime, (void *)rp);
2045 #ifdef DEBUG
2047 JS_PUBLIC_API(void)
2048 JS_DumpNamedRoots(JSRuntime *rt,
2049 void (*dump)(const char *name, void *rp, JSGCRootType type, void *data),
2050 void *data)
2052 js_DumpNamedRoots(rt, dump, data);
2055 #endif /* DEBUG */
2057 JS_PUBLIC_API(uint32)
2058 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
2060 return js_MapGCRoots(rt, map, data);
2063 JS_PUBLIC_API(JSBool)
2064 JS_LockGCThing(JSContext *cx, void *thing)
2066 JSBool ok;
2068 CHECK_REQUEST(cx);
2069 ok = js_LockGCThingRT(cx->runtime, thing);
2070 if (!ok)
2071 JS_ReportOutOfMemory(cx);
2072 return ok;
2075 JS_PUBLIC_API(JSBool)
2076 JS_LockGCThingRT(JSRuntime *rt, void *thing)
2078 return js_LockGCThingRT(rt, thing);
2081 JS_PUBLIC_API(JSBool)
2082 JS_UnlockGCThing(JSContext *cx, void *thing)
2084 CHECK_REQUEST(cx);
2085 js_UnlockGCThingRT(cx->runtime, thing);
2086 return true;
2089 JS_PUBLIC_API(JSBool)
2090 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
2092 js_UnlockGCThingRT(rt, thing);
2093 return true;
2096 JS_PUBLIC_API(void)
2097 JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
2099 rt->gcExtraRootsTraceOp = traceOp;
2100 rt->gcExtraRootsData = data;
2103 JS_PUBLIC_API(void)
2104 JS_TraceRuntime(JSTracer *trc)
2106 TraceRuntime(trc);
2109 JS_PUBLIC_API(void)
2110 JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
2112 JS_ASSERT(thing);
2113 MarkKind(trc, thing, kind);
2116 #ifdef DEBUG
2118 #ifdef HAVE_XPCONNECT
2119 #include "dump_xpc.h"
2120 #endif
2122 JS_PUBLIC_API(void)
2123 JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, uint32 kind,
2124 JSBool details)
2126 const char *name;
2127 size_t n;
2129 if (bufsize == 0)
2130 return;
2132 switch (kind) {
2133 case JSTRACE_OBJECT:
2135 JSObject *obj = (JSObject *)thing;
2136 Class *clasp = obj->getClass();
2138 name = clasp->name;
2139 #ifdef HAVE_XPCONNECT
2140 if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
2141 void *privateThing = obj->getPrivate();
2142 if (privateThing) {
2143 const char *xpcClassName = GetXPCObjectClassName(privateThing);
2144 if (xpcClassName)
2145 name = xpcClassName;
2148 #endif
2149 break;
2152 case JSTRACE_STRING:
2153 name = ((JSString *)thing)->isDependent()
2154 ? "substring"
2155 : "string";
2156 break;
2158 #if JS_HAS_XML_SUPPORT
2159 case JSTRACE_XML:
2160 name = "xml";
2161 break;
2162 #endif
2163 default:
2164 JS_ASSERT(0);
2165 return;
2166 break;
2169 n = strlen(name);
2170 if (n > bufsize - 1)
2171 n = bufsize - 1;
2172 memcpy(buf, name, n + 1);
2173 buf += n;
2174 bufsize -= n;
2176 if (details && bufsize > 2) {
2177 *buf++ = ' ';
2178 bufsize--;
2180 switch (kind) {
2181 case JSTRACE_OBJECT:
2183 JSObject *obj = (JSObject *)thing;
2184 Class *clasp = obj->getClass();
2185 if (clasp == &js_FunctionClass) {
2186 JSFunction *fun = GET_FUNCTION_PRIVATE(trc->context, obj);
2187 if (!fun) {
2188 JS_snprintf(buf, bufsize, "<newborn>");
2189 } else if (FUN_OBJECT(fun) != obj) {
2190 JS_snprintf(buf, bufsize, "%p", fun);
2191 } else {
2192 if (fun->atom)
2193 js_PutEscapedString(buf, bufsize, ATOM_TO_STRING(fun->atom), 0);
2195 } else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
2196 JS_snprintf(buf, bufsize, "%p", obj->getPrivate());
2197 } else {
2198 JS_snprintf(buf, bufsize, "<no private>");
2200 break;
2203 case JSTRACE_STRING:
2204 js_PutEscapedString(buf, bufsize, (JSString *)thing, 0);
2205 break;
2207 #if JS_HAS_XML_SUPPORT
2208 case JSTRACE_XML:
2210 extern const char *js_xml_class_str[];
2211 JSXML *xml = (JSXML *)thing;
2213 JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]);
2214 break;
2216 #endif
2217 default:
2218 JS_ASSERT(0);
2219 break;
2222 buf[bufsize - 1] = '\0';
2225 typedef struct JSHeapDumpNode JSHeapDumpNode;
2227 struct JSHeapDumpNode {
2228 void *thing;
2229 uint32 kind;
2230 JSHeapDumpNode *next; /* next sibling */
2231 JSHeapDumpNode *parent; /* node with the thing that refer to thing
2232 from this node */
2233 char edgeName[1]; /* name of the edge from parent->thing
2234 into thing */
2237 typedef struct JSDumpingTracer {
2238 JSTracer base;
2239 JSDHashTable visited;
2240 JSBool ok;
2241 void *startThing;
2242 void *thingToFind;
2243 void *thingToIgnore;
2244 JSHeapDumpNode *parentNode;
2245 JSHeapDumpNode **lastNodep;
2246 char buffer[200];
2247 } JSDumpingTracer;
2249 static void
2250 DumpNotify(JSTracer *trc, void *thing, uint32 kind)
2252 JSDumpingTracer *dtrc;
2253 JSContext *cx;
2254 JSDHashEntryStub *entry;
2255 JSHeapDumpNode *node;
2256 const char *edgeName;
2257 size_t edgeNameSize;
2259 JS_ASSERT(trc->callback == DumpNotify);
2260 dtrc = (JSDumpingTracer *)trc;
2262 if (!dtrc->ok || thing == dtrc->thingToIgnore)
2263 return;
2265 cx = trc->context;
2268 * Check if we have already seen thing unless it is thingToFind to include
2269 * it to the graph each time we reach it and print all live things that
2270 * refer to thingToFind.
2272 * This does not print all possible paths leading to thingToFind since
2273 * when a thing A refers directly or indirectly to thingToFind and A is
2274 * present several times in the graph, we will print only the first path
2275 * leading to A and thingToFind, other ways to reach A will be ignored.
2277 if (dtrc->thingToFind != thing) {
2279 * The startThing check allows to avoid putting startThing into the
2280 * hash table before tracing startThing in JS_DumpHeap.
2282 if (thing == dtrc->startThing)
2283 return;
2284 entry = (JSDHashEntryStub *)
2285 JS_DHashTableOperate(&dtrc->visited, thing, JS_DHASH_ADD);
2286 if (!entry) {
2287 JS_ReportOutOfMemory(cx);
2288 dtrc->ok = JS_FALSE;
2289 return;
2291 if (entry->key)
2292 return;
2293 entry->key = thing;
2296 if (dtrc->base.debugPrinter) {
2297 dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer));
2298 edgeName = dtrc->buffer;
2299 } else if (dtrc->base.debugPrintIndex != (size_t)-1) {
2300 JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]",
2301 (const char *)dtrc->base.debugPrintArg,
2302 dtrc->base.debugPrintIndex);
2303 edgeName = dtrc->buffer;
2304 } else {
2305 edgeName = (const char*)dtrc->base.debugPrintArg;
2308 edgeNameSize = strlen(edgeName) + 1;
2309 node = (JSHeapDumpNode *)
2310 cx->malloc(offsetof(JSHeapDumpNode, edgeName) + edgeNameSize);
2311 if (!node) {
2312 dtrc->ok = JS_FALSE;
2313 return;
2316 node->thing = thing;
2317 node->kind = kind;
2318 node->next = NULL;
2319 node->parent = dtrc->parentNode;
2320 memcpy(node->edgeName, edgeName, edgeNameSize);
2322 JS_ASSERT(!*dtrc->lastNodep);
2323 *dtrc->lastNodep = node;
2324 dtrc->lastNodep = &node->next;
2327 /* Dump node and the chain that leads to thing it contains. */
2328 static JSBool
2329 DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
2331 JSHeapDumpNode *prev, *following;
2332 size_t chainLimit;
2333 JSBool ok;
2334 enum { MAX_PARENTS_TO_PRINT = 10 };
2336 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2337 &dtrc->base, node->thing, node->kind, JS_TRUE);
2338 if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
2339 return JS_FALSE;
2342 * We need to print the parent chain in the reverse order. To do it in
2343 * O(N) time where N is the chain length we first reverse the chain while
2344 * searching for the top and then print each node while restoring the
2345 * chain order.
2347 chainLimit = MAX_PARENTS_TO_PRINT;
2348 prev = NULL;
2349 for (;;) {
2350 following = node->parent;
2351 node->parent = prev;
2352 prev = node;
2353 node = following;
2354 if (!node)
2355 break;
2356 if (chainLimit == 0) {
2357 if (fputs("...", fp) < 0)
2358 return JS_FALSE;
2359 break;
2361 --chainLimit;
2364 node = prev;
2365 prev = following;
2366 ok = JS_TRUE;
2367 do {
2368 /* Loop must continue even when !ok to restore the parent chain. */
2369 if (ok) {
2370 if (!prev) {
2371 /* Print edge from some runtime root or startThing. */
2372 if (fputs(node->edgeName, fp) < 0)
2373 ok = JS_FALSE;
2374 } else {
2375 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2376 &dtrc->base, prev->thing, prev->kind,
2377 JS_FALSE);
2378 if (fprintf(fp, "(%p %s).%s",
2379 prev->thing, dtrc->buffer, node->edgeName) < 0) {
2380 ok = JS_FALSE;
2384 following = node->parent;
2385 node->parent = prev;
2386 prev = node;
2387 node = following;
2388 } while (node);
2390 return ok && putc('\n', fp) >= 0;
2393 JS_PUBLIC_API(JSBool)
2394 JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind,
2395 void *thingToFind, size_t maxDepth, void *thingToIgnore)
2397 JSDumpingTracer dtrc;
2398 JSHeapDumpNode *node, *children, *next, *parent;
2399 size_t depth;
2400 JSBool thingToFindWasTraced;
2402 if (maxDepth == 0)
2403 return JS_TRUE;
2405 JS_TRACER_INIT(&dtrc.base, cx, DumpNotify);
2406 if (!JS_DHashTableInit(&dtrc.visited, JS_DHashGetStubOps(),
2407 NULL, sizeof(JSDHashEntryStub),
2408 JS_DHASH_DEFAULT_CAPACITY(100))) {
2409 JS_ReportOutOfMemory(cx);
2410 return JS_FALSE;
2412 dtrc.ok = JS_TRUE;
2413 dtrc.startThing = startThing;
2414 dtrc.thingToFind = thingToFind;
2415 dtrc.thingToIgnore = thingToIgnore;
2416 dtrc.parentNode = NULL;
2417 node = NULL;
2418 dtrc.lastNodep = &node;
2419 if (!startThing) {
2420 JS_ASSERT(startKind == 0);
2421 TraceRuntime(&dtrc.base);
2422 } else {
2423 JS_TraceChildren(&dtrc.base, startThing, startKind);
2426 depth = 1;
2427 if (!node)
2428 goto dump_out;
2430 thingToFindWasTraced = thingToFind && thingToFind == startThing;
2431 for (;;) {
2433 * Loop must continue even when !dtrc.ok to free all nodes allocated
2434 * so far.
2436 if (dtrc.ok) {
2437 if (thingToFind == NULL || thingToFind == node->thing)
2438 dtrc.ok = DumpNode(&dtrc, fp, node);
2440 /* Descend into children. */
2441 if (dtrc.ok &&
2442 depth < maxDepth &&
2443 (thingToFind != node->thing || !thingToFindWasTraced)) {
2444 dtrc.parentNode = node;
2445 children = NULL;
2446 dtrc.lastNodep = &children;
2447 JS_TraceChildren(&dtrc.base, node->thing, node->kind);
2448 if (thingToFind == node->thing)
2449 thingToFindWasTraced = JS_TRUE;
2450 if (children != NULL) {
2451 ++depth;
2452 node = children;
2453 continue;
2458 /* Move to next or parents next and free the node. */
2459 for (;;) {
2460 next = node->next;
2461 parent = node->parent;
2462 cx->free(node);
2463 node = next;
2464 if (node)
2465 break;
2466 if (!parent)
2467 goto dump_out;
2468 JS_ASSERT(depth > 1);
2469 --depth;
2470 node = parent;
2474 dump_out:
2475 JS_ASSERT(depth == 1);
2476 JS_DHashTableFinish(&dtrc.visited);
2477 return dtrc.ok;
2480 #endif /* DEBUG */
2482 JS_PUBLIC_API(void)
2483 JS_MarkGCThing(JSContext *cx, jsval v, const char *name, void *arg)
2485 JSTracer *trc;
2487 trc = (JSTracer *)arg;
2488 if (!trc)
2489 trc = cx->runtime->gcMarkingTracer;
2490 else
2491 JS_ASSERT(trc == cx->runtime->gcMarkingTracer);
2493 #ifdef JS_THREADSAFE
2494 JS_ASSERT(cx->runtime->gcThread == trc->context->thread);
2495 #endif
2496 MarkValue(trc, Valueify(v), name ? name : "unknown");
2499 extern JS_PUBLIC_API(JSBool)
2500 JS_IsGCMarkingTracer(JSTracer *trc)
2502 return IS_GC_MARKING_TRACER(trc);
2505 JS_PUBLIC_API(void)
2506 JS_GC(JSContext *cx)
2508 LeaveTrace(cx);
2510 /* Don't nuke active arenas if executing or compiling. */
2511 if (cx->tempPool.current == &cx->tempPool.first)
2512 JS_FinishArenaPool(&cx->tempPool);
2513 js_GC(cx, GC_NORMAL);
2516 JS_PUBLIC_API(void)
2517 JS_MaybeGC(JSContext *cx)
2519 JSRuntime *rt;
2520 uint32 bytes, lastBytes;
2522 rt = cx->runtime;
2524 #ifdef JS_GC_ZEAL
2525 if (rt->gcZeal > 0) {
2526 JS_GC(cx);
2527 return;
2529 #endif
2531 bytes = rt->gcBytes;
2532 lastBytes = rt->gcLastBytes;
2535 * We run the GC if we used all available free GC cells and had to
2536 * allocate extra 1/3 of GC arenas since the last run of GC, or if
2537 * we have malloc'd more bytes through JS_malloc than we were told
2538 * to allocate by JS_NewRuntime.
2540 * The reason for
2541 * bytes > 4/3 lastBytes
2542 * condition is the following. Bug 312238 changed bytes and lastBytes
2543 * to mean the total amount of memory that the GC uses now and right
2544 * after the last GC.
2546 * Before the bug the variables meant the size of allocated GC things
2547 * now and right after the last GC. That size did not include the
2548 * memory taken by free GC cells and the condition was
2549 * bytes > 3/2 lastBytes.
2550 * That is, we run the GC if we have half again as many bytes of
2551 * GC-things as the last time we GC'd. To be compatible we need to
2552 * express that condition through the new meaning of bytes and
2553 * lastBytes.
2555 * We write the original condition as
2556 * B*(1-F) > 3/2 Bl*(1-Fl)
2557 * where B is the total memory size allocated by GC and F is the free
2558 * cell density currently and Sl and Fl are the size and the density
2559 * right after GC. The density by definition is memory taken by free
2560 * cells divided by total amount of memory. In other words, B and Bl
2561 * are bytes and lastBytes with the new meaning and B*(1-F) and
2562 * Bl*(1-Fl) are bytes and lastBytes with the original meaning.
2564 * Our task is to exclude F and Fl from the last statement. According
2565 * to the stats from bug 331966 comment 23, Fl is about 10-25% for a
2566 * typical run of the browser. It means that the original condition
2567 * implied that we did not run GC unless we exhausted the pool of
2568 * free cells. Indeed if we still have free cells, then B == Bl since
2569 * we did not yet allocated any new arenas and the condition means
2570 * 1 - F > 3/2 (1-Fl) or 3/2Fl > 1/2 + F
2571 * That implies 3/2 Fl > 1/2 or Fl > 1/3. That cannot be fulfilled
2572 * for the state described by the stats. So we can write the original
2573 * condition as:
2574 * F == 0 && B > 3/2 Bl(1-Fl)
2575 * Again using the stats we see that Fl is about 11% when the browser
2576 * starts up and when we are far from hitting rt->gcMaxBytes. With
2577 * this F we have
2578 * F == 0 && B > 3/2 Bl(1-0.11)
2579 * or approximately F == 0 && B > 4/3 Bl.
2581 if ((bytes > 8192 && bytes > lastBytes + lastBytes / 3) ||
2582 rt->isGCMallocLimitReached()) {
2583 JS_GC(cx);
2587 JS_PUBLIC_API(JSGCCallback)
2588 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
2590 CHECK_REQUEST(cx);
2591 return JS_SetGCCallbackRT(cx->runtime, cb);
2594 JS_PUBLIC_API(JSGCCallback)
2595 JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
2597 JSGCCallback oldcb;
2599 oldcb = rt->gcCallback;
2600 rt->gcCallback = cb;
2601 return oldcb;
2604 JS_PUBLIC_API(JSBool)
2605 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
2607 JS_ASSERT(thing);
2608 JS_ASSERT(!cx->runtime->gcMarkingTracer);
2609 return IsAboutToBeFinalized(thing);
2612 JS_PUBLIC_API(void)
2613 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
2615 switch (key) {
2616 case JSGC_MAX_BYTES:
2617 rt->gcMaxBytes = value;
2618 break;
2619 case JSGC_MAX_MALLOC_BYTES:
2620 rt->setGCMaxMallocBytes(value);
2621 break;
2622 case JSGC_STACKPOOL_LIFESPAN:
2623 rt->gcEmptyArenaPoolLifespan = value;
2624 break;
2625 default:
2626 JS_ASSERT(key == JSGC_TRIGGER_FACTOR);
2627 JS_ASSERT(value >= 100);
2628 rt->setGCTriggerFactor(value);
2629 return;
2633 JS_PUBLIC_API(uint32)
2634 JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
2636 switch (key) {
2637 case JSGC_MAX_BYTES:
2638 return rt->gcMaxBytes;
2639 case JSGC_MAX_MALLOC_BYTES:
2640 return rt->gcMaxMallocBytes;
2641 case JSGC_STACKPOOL_LIFESPAN:
2642 return rt->gcEmptyArenaPoolLifespan;
2643 case JSGC_TRIGGER_FACTOR:
2644 return rt->gcTriggerFactor;
2645 case JSGC_BYTES:
2646 return rt->gcBytes;
2647 default:
2648 JS_ASSERT(key == JSGC_NUMBER);
2649 return rt->gcNumber;
2653 JS_PUBLIC_API(void)
2654 JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32 value)
2656 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2657 #ifdef JS_TRACER
2658 SetMaxCodeCacheBytes(cx, value);
2659 #endif
2662 JS_PUBLIC_API(uint32)
2663 JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key)
2665 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2666 #ifdef JS_TRACER
2667 return JS_THREAD_DATA(cx)->traceMonitor.maxCodeCacheBytes;
2668 #else
2669 return 0;
2670 #endif
2673 JS_PUBLIC_API(void)
2674 JS_FlushCaches(JSContext *cx)
2676 #ifdef JS_TRACER
2677 FlushJITCache(cx);
2678 #endif
2681 JS_PUBLIC_API(intN)
2682 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
2684 return js_ChangeExternalStringFinalizer(NULL, finalizer);
2687 JS_PUBLIC_API(intN)
2688 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
2690 return js_ChangeExternalStringFinalizer(finalizer, NULL);
2693 JS_PUBLIC_API(JSString *)
2694 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
2696 CHECK_REQUEST(cx);
2697 JS_ASSERT(uintN(type) < JS_EXTERNAL_STRING_LIMIT);
2699 JSString *str = js_NewGCExternalString(cx, uintN(type));
2700 if (!str)
2701 return NULL;
2702 str->initFlat(chars, length);
2703 cx->runtime->updateMallocCounter((length + 1) * sizeof(jschar));
2704 return str;
2707 JS_PUBLIC_API(intN)
2708 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
2711 * No need to test this in js_GetExternalStringGCType, which asserts its
2712 * inverse instead of wasting cycles on testing a condition we can ensure
2713 * by auditing in-VM calls to the js_... helper.
2715 if (JSString::isStatic(str))
2716 return -1;
2718 return js_GetExternalStringGCType(str);
2721 JS_PUBLIC_API(void)
2722 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
2724 #if JS_STACK_GROWTH_DIRECTION > 0
2725 if (limitAddr == 0)
2726 limitAddr = jsuword(-1);
2727 #endif
2728 cx->stackLimit = limitAddr;
2731 JS_PUBLIC_API(void)
2732 JS_SetNativeStackQuota(JSContext *cx, size_t stackSize)
2734 #ifdef JS_THREADSAFE
2735 JS_ASSERT(cx->thread);
2736 #endif
2738 #if JS_STACK_GROWTH_DIRECTION > 0
2739 if (stackSize == 0) {
2740 cx->stackLimit = jsuword(-1);
2741 } else {
2742 jsuword stackBase = reinterpret_cast<jsuword>(JS_THREAD_DATA(cx)->nativeStackBase);
2743 JS_ASSERT(stackBase <= size_t(-1) - stackSize);
2744 cx->stackLimit = stackBase + stackSize - 1;
2746 #else
2747 if (stackSize == 0) {
2748 cx->stackLimit = 0;
2749 } else {
2750 jsuword stackBase = reinterpret_cast<jsuword>(JS_THREAD_DATA(cx)->nativeStackBase);
2751 JS_ASSERT(stackBase >= stackSize);
2752 cx->stackLimit = stackBase - (stackSize - 1);
2754 #endif
2757 JS_PUBLIC_API(void)
2758 JS_SetScriptStackQuota(JSContext *cx, size_t quota)
2760 cx->scriptStackQuota = quota;
2763 /************************************************************************/
2765 JS_PUBLIC_API(void)
2766 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
2768 cx->free(ida);
2771 JS_PUBLIC_API(JSBool)
2772 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
2774 CHECK_REQUEST(cx);
2775 assertSameCompartment(cx, v);
2776 return ValueToId(cx, Valueify(v), idp);
2779 JS_PUBLIC_API(JSBool)
2780 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
2782 CHECK_REQUEST(cx);
2783 *vp = IdToJsval(id);
2784 assertSameCompartment(cx, *vp);
2785 return JS_TRUE;
2788 JS_PUBLIC_API(JSBool)
2789 JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
2791 return JS_TRUE;
2794 JS_PUBLIC_API(JSBool)
2795 JS_EnumerateStub(JSContext *cx, JSObject *obj)
2797 return JS_TRUE;
2800 JS_PUBLIC_API(JSBool)
2801 JS_ResolveStub(JSContext *cx, JSObject *obj, jsid id)
2803 return JS_TRUE;
2806 JS_PUBLIC_API(JSBool)
2807 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
2809 JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION);
2810 return js_TryValueOf(cx, obj, type, Valueify(vp));
2813 JS_PUBLIC_API(void)
2814 JS_FinalizeStub(JSContext *cx, JSObject *obj)
2817 JS_PUBLIC_API(JSObject *)
2818 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
2819 JSClass *clasp, JSNative constructor, uintN nargs,
2820 JSPropertySpec *ps, JSFunctionSpec *fs,
2821 JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
2823 CHECK_REQUEST(cx);
2824 assertSameCompartment(cx, obj, parent_proto);
2825 return js_InitClass(cx, obj, parent_proto, Valueify(clasp),
2826 Valueify(constructor), nargs,
2827 ps, fs, static_ps, static_fs);
2830 #ifdef JS_THREADSAFE
2831 JS_PUBLIC_API(JSClass *)
2832 JS_GetClass(JSContext *cx, JSObject *obj)
2834 return Jsvalify(obj->getClass());
2836 #else
2837 JS_PUBLIC_API(JSClass *)
2838 JS_GetClass(JSObject *obj)
2840 return Jsvalify(obj->getClass());
2842 #endif
2844 JS_PUBLIC_API(JSBool)
2845 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2847 CHECK_REQUEST(cx);
2848 assertSameCompartment(cx, obj);
2849 return InstanceOf(cx, obj, Valueify(clasp), Valueify(argv));
2852 JS_PUBLIC_API(JSBool)
2853 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
2855 assertSameCompartment(cx, obj, v);
2856 return HasInstance(cx, obj, Valueify(&v), bp);
2859 JS_PUBLIC_API(void *)
2860 JS_GetPrivate(JSContext *cx, JSObject *obj)
2862 return obj->getPrivate();
2865 JS_PUBLIC_API(JSBool)
2866 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2868 obj->setPrivate(data);
2869 return true;
2872 JS_PUBLIC_API(void *)
2873 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2875 if (!InstanceOf(cx, obj, Valueify(clasp), Valueify(argv)))
2876 return NULL;
2877 return obj->getPrivate();
2880 JS_PUBLIC_API(JSObject *)
2881 JS_GetPrototype(JSContext *cx, JSObject *obj)
2883 JSObject *proto;
2885 CHECK_REQUEST(cx);
2886 assertSameCompartment(cx, obj);
2887 proto = obj->getProto();
2889 /* Beware ref to dead object (we may be called from obj's finalizer). */
2890 return proto && proto->map ? proto : NULL;
2893 JS_PUBLIC_API(JSBool)
2894 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
2896 CHECK_REQUEST(cx);
2897 assertSameCompartment(cx, obj, proto);
2898 return SetProto(cx, obj, proto, JS_FALSE);
2901 JS_PUBLIC_API(JSObject *)
2902 JS_GetParent(JSContext *cx, JSObject *obj)
2904 assertSameCompartment(cx, obj);
2905 JSObject *parent = obj->getParent();
2907 /* Beware ref to dead object (we may be called from obj's finalizer). */
2908 return parent && parent->map ? parent : NULL;
2911 JS_PUBLIC_API(JSBool)
2912 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
2914 CHECK_REQUEST(cx);
2915 JS_ASSERT(parent || !obj->getParent());
2916 assertSameCompartment(cx, obj, parent);
2917 obj->setParent(parent);
2918 return true;
2921 JS_PUBLIC_API(JSObject *)
2922 JS_GetConstructor(JSContext *cx, JSObject *proto)
2924 Value cval;
2926 CHECK_REQUEST(cx);
2927 assertSameCompartment(cx, proto);
2929 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
2931 if (!proto->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), &cval))
2932 return NULL;
2934 JSObject *funobj;
2935 if (!IsFunctionObject(cval, &funobj)) {
2936 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
2937 proto->getClass()->name);
2938 return NULL;
2940 return &cval.toObject();
2943 JS_PUBLIC_API(JSBool)
2944 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
2946 assertSameCompartment(cx, obj);
2947 *idp = OBJECT_TO_JSID(obj);
2948 return JS_TRUE;
2951 JS_PUBLIC_API(JSObject *)
2952 JS_NewGlobalObject(JSContext *cx, JSClass *clasp)
2954 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
2955 CHECK_REQUEST(cx);
2956 JS_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
2957 JSObject *obj = NewNonFunction<WithProto::Given>(cx, Valueify(clasp), NULL, NULL);
2958 if (!obj)
2959 return NULL;
2961 /* Construct a regexp statics object for this global object. */
2962 JSObject *res = regexp_statics_construct(cx, obj);
2963 if (!res ||
2964 !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_REGEXP_STATICS,
2965 ObjectValue(*res))) {
2966 return NULL;
2969 return obj;
2972 JS_PUBLIC_API(JSObject *)
2973 JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals)
2975 CHECK_REQUEST(cx);
2976 JSCompartment *compartment = NewCompartment(cx, principals);
2977 if (!compartment)
2978 return NULL;
2980 JSCompartment *saved = cx->compartment;
2981 cx->compartment = compartment;
2982 JSObject *obj = JS_NewGlobalObject(cx, clasp);
2983 cx->compartment = saved;
2985 return obj;
2988 JS_PUBLIC_API(JSObject *)
2989 JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
2991 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
2992 CHECK_REQUEST(cx);
2993 assertSameCompartment(cx, proto, parent);
2995 Class *clasp = Valueify(jsclasp);
2996 if (!clasp)
2997 clasp = &js_ObjectClass; /* default class is Object */
2999 JS_ASSERT(clasp != &js_FunctionClass);
3000 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
3002 JSObject *obj = NewNonFunction<WithProto::Class>(cx, clasp, proto, parent);
3004 JS_ASSERT_IF(obj, obj->getParent());
3005 return obj;
3008 JS_PUBLIC_API(JSObject *)
3009 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
3011 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
3012 CHECK_REQUEST(cx);
3013 assertSameCompartment(cx, proto, parent);
3015 Class *clasp = Valueify(jsclasp);
3016 if (!clasp)
3017 clasp = &js_ObjectClass; /* default class is Object */
3019 JS_ASSERT(clasp != &js_FunctionClass);
3020 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
3022 return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
3025 JS_PUBLIC_API(JSObject *)
3026 JS_NewObjectForConstructor(JSContext *cx, const jsval *vp)
3028 CHECK_REQUEST(cx);
3029 assertSameCompartment(cx, *vp);
3031 return js_CreateThis(cx, JSVAL_TO_OBJECT(*vp));
3034 JS_PUBLIC_API(JSBool)
3035 JS_IsExtensible(JSObject *obj)
3037 return obj->isExtensible();
3040 JS_PUBLIC_API(JSBool)
3041 JS_FreezeObject(JSContext *cx, JSObject *obj)
3043 CHECK_REQUEST(cx);
3044 assertSameCompartment(cx, obj);
3046 return obj->freeze(cx);
3049 JS_PUBLIC_API(JSBool)
3050 JS_DeepFreezeObject(JSContext *cx, JSObject *obj)
3052 CHECK_REQUEST(cx);
3053 assertSameCompartment(cx, obj);
3055 /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */
3056 if (obj->isExtensible())
3057 return true;
3059 if (!obj->freeze(cx))
3060 return false;
3062 /* Walk slots in obj and if any value is a non-null object, seal it. */
3063 for (uint32 i = 0, n = obj->slotSpan(); i < n; ++i) {
3064 const Value &v = obj->getSlot(i);
3065 if (v.isPrimitive())
3066 continue;
3067 if (!JS_DeepFreezeObject(cx, &v.toObject()))
3068 return false;
3071 return true;
3074 JS_PUBLIC_API(JSObject *)
3075 JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
3077 CHECK_REQUEST(cx);
3078 assertSameCompartment(cx, proto, parent);
3079 Class *clasp = Valueify(jsclasp);
3080 if (!clasp)
3081 clasp = &js_ObjectClass; /* default class is Object */
3082 return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
3085 JS_PUBLIC_API(JSObject *)
3086 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *proto,
3087 JSObject *parent, uintN argc, jsval *argv)
3089 CHECK_REQUEST(cx);
3090 assertSameCompartment(cx, proto, parent, JSValueArray(argv, argc));
3091 Class *clasp = Valueify(jsclasp);
3092 if (!clasp)
3093 clasp = &js_ObjectClass; /* default class is Object */
3094 return js_ConstructObject(cx, clasp, proto, parent, argc, Valueify(argv));
3097 static JSBool
3098 LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3099 JSObject **objp, JSProperty **propp)
3101 CHECK_REQUEST(cx);
3102 assertSameCompartment(cx, obj, id);
3104 JSAutoResolveFlags rf(cx, flags);
3105 id = js_CheckForStringIndex(id);
3106 return obj->lookupProperty(cx, id, objp, propp);
3109 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
3111 static JSBool
3112 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, jsid id,
3113 JSProperty *prop, Value *vp)
3115 if (!prop) {
3116 /* XXX bad API: no way to tell "not defined" from "void value" */
3117 vp->setUndefined();
3118 return JS_TRUE;
3121 if (obj2->isNative()) {
3122 Shape *shape = (Shape *) prop;
3124 if (shape->isMethod()) {
3125 AutoShapeRooter root(cx, shape);
3126 vp->setObject(shape->methodObject());
3127 return obj2->methodReadBarrier(cx, *shape, vp);
3130 /* Peek at the native property's slot value, without doing a Get. */
3131 if (obj2->containsSlot(shape->slot)) {
3132 *vp = obj2->nativeGetSlot(shape->slot);
3133 return true;
3135 } else {
3136 if (obj2->isDenseArray())
3137 return js_GetDenseArrayElementValue(cx, obj2, id, vp);
3138 if (obj2->isProxy()) {
3139 AutoPropertyDescriptorRooter desc(cx);
3140 if (!JSProxy::getPropertyDescriptor(cx, obj2, id, false, &desc))
3141 return false;
3142 if (!(desc.attrs & JSPROP_SHARED)) {
3143 *vp = desc.value;
3144 return true;
3149 /* XXX bad API: no way to return "defined but value unknown" */
3150 vp->setBoolean(true);
3151 return true;
3154 JS_PUBLIC_API(JSBool)
3155 JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3157 JSObject *obj2;
3158 JSProperty *prop;
3159 return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) &&
3160 LookupResult(cx, obj, obj2, id, prop, Valueify(vp));
3163 JS_PUBLIC_API(JSBool)
3164 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3166 return JS_LookupPropertyById(cx, obj, INT_TO_JSID(index), vp);
3169 JS_PUBLIC_API(JSBool)
3170 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3172 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3173 return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3176 JS_PUBLIC_API(JSBool)
3177 JS_LookupUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3179 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3180 return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3183 JS_PUBLIC_API(JSBool)
3184 JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3185 JSObject **objp, jsval *vp)
3187 JSBool ok;
3188 JSProperty *prop;
3190 CHECK_REQUEST(cx);
3191 assertSameCompartment(cx, obj, id);
3192 ok = obj->isNative()
3193 ? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0
3194 : obj->lookupProperty(cx, id, objp, &prop);
3195 return ok && LookupResult(cx, obj, *objp, id, prop, Valueify(vp));
3198 JS_PUBLIC_API(JSBool)
3199 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, uintN flags, jsval *vp)
3201 JSObject *obj2;
3202 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3203 return atom && JS_LookupPropertyWithFlagsById(cx, obj, ATOM_TO_JSID(atom), flags, &obj2, vp);
3206 JS_PUBLIC_API(JSBool)
3207 JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3209 JSObject *obj2;
3210 JSProperty *prop;
3211 JSBool ok = LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3212 &obj2, &prop);
3213 *foundp = (prop != NULL);
3214 return ok;
3217 JS_PUBLIC_API(JSBool)
3218 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3220 return JS_HasPropertyById(cx, obj, INT_TO_JSID(index), foundp);
3223 JS_PUBLIC_API(JSBool)
3224 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3226 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3227 return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3230 JS_PUBLIC_API(JSBool)
3231 JS_HasUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, JSBool *foundp)
3233 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3234 return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3237 JS_PUBLIC_API(JSBool)
3238 JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3240 CHECK_REQUEST(cx);
3241 assertSameCompartment(cx, obj, id);
3243 if (!obj->isNative()) {
3244 JSObject *obj2;
3245 JSProperty *prop;
3247 if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3248 &obj2, &prop)) {
3249 return JS_FALSE;
3251 *foundp = (obj == obj2);
3252 return JS_TRUE;
3255 *foundp = obj->nativeContains(id);
3256 return JS_TRUE;
3259 JS_PUBLIC_API(JSBool)
3260 JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3262 return JS_AlreadyHasOwnPropertyById(cx, obj, INT_TO_JSID(index), foundp);
3265 JS_PUBLIC_API(JSBool)
3266 JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3268 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3269 return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3272 JS_PUBLIC_API(JSBool)
3273 JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3274 JSBool *foundp)
3276 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3277 return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3280 static JSBool
3281 DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value,
3282 PropertyOp getter, PropertyOp setter, uintN attrs,
3283 uintN flags, intN tinyid)
3285 CHECK_REQUEST(cx);
3286 assertSameCompartment(cx, obj, id, value,
3287 (attrs & JSPROP_GETTER)
3288 ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
3289 : NULL,
3290 (attrs & JSPROP_SETTER)
3291 ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
3292 : NULL);
3294 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
3295 if (flags != 0 && obj->isNative()) {
3296 return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter,
3297 attrs, flags, tinyid, NULL);
3299 return obj->defineProperty(cx, id, value, getter, setter, attrs);
3302 JS_PUBLIC_API(JSBool)
3303 JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
3304 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3306 return DefinePropertyById(cx, obj, id, Valueify(value), Valueify(getter),
3307 Valueify(setter), attrs, 0, 0);
3310 JS_PUBLIC_API(JSBool)
3311 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
3312 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3314 return DefinePropertyById(cx, obj, INT_TO_JSID(index), Valueify(value),
3315 Valueify(getter), Valueify(setter), attrs, 0, 0);
3318 static JSBool
3319 DefineProperty(JSContext *cx, JSObject *obj, const char *name, const Value &value,
3320 PropertyOp getter, PropertyOp setter, uintN attrs,
3321 uintN flags, intN tinyid)
3323 jsid id;
3324 JSAtom *atom;
3326 if (attrs & JSPROP_INDEX) {
3327 id = INT_TO_JSID(intptr_t(name));
3328 atom = NULL;
3329 attrs &= ~JSPROP_INDEX;
3330 } else {
3331 atom = js_Atomize(cx, name, strlen(name), 0);
3332 if (!atom)
3333 return JS_FALSE;
3334 id = ATOM_TO_JSID(atom);
3336 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid);
3339 JS_PUBLIC_API(JSBool)
3340 JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
3341 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3343 return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter),
3344 Valueify(setter), attrs, 0, 0);
3347 JS_PUBLIC_API(JSBool)
3348 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, int8 tinyid,
3349 jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3351 return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter),
3352 Valueify(setter), attrs, Shape::HAS_SHORTID, tinyid);
3355 static JSBool
3356 DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3357 const Value &value, PropertyOp getter, PropertyOp setter, uintN attrs,
3358 uintN flags, intN tinyid)
3360 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3361 return atom && DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs,
3362 flags, tinyid);
3365 JS_PUBLIC_API(JSBool)
3366 JS_DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3367 jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3369 return DefineUCProperty(cx, obj, name, namelen, Valueify(value),
3370 Valueify(getter), Valueify(setter), attrs, 0, 0);
3373 JS_PUBLIC_API(JSBool)
3374 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3375 int8 tinyid, jsval value, JSPropertyOp getter, JSPropertyOp setter,
3376 uintN attrs)
3378 return DefineUCProperty(cx, obj, name, namelen, Valueify(value), Valueify(getter),
3379 Valueify(setter), attrs, Shape::HAS_SHORTID, tinyid);
3382 JS_PUBLIC_API(JSBool)
3383 JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp)
3385 CHECK_REQUEST(cx);
3386 assertSameCompartment(cx, obj, id, descriptor);
3387 return js_DefineOwnProperty(cx, obj, id, Valueify(descriptor), bp);
3390 JS_PUBLIC_API(JSObject *)
3391 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp,
3392 JSObject *proto, uintN attrs)
3394 CHECK_REQUEST(cx);
3395 assertSameCompartment(cx, obj, proto);
3397 Class *clasp = Valueify(jsclasp);
3398 if (!clasp)
3399 clasp = &js_ObjectClass; /* default class is Object */
3401 JSObject *nobj = NewObject<WithProto::Class>(cx, clasp, proto, obj);
3402 if (!nobj)
3403 return NULL;
3405 if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
3406 return NULL;
3408 return nobj;
3411 JS_PUBLIC_API(JSBool)
3412 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
3414 JSBool ok;
3415 uintN attrs;
3417 CHECK_REQUEST(cx);
3418 for (ok = JS_TRUE; cds->name; cds++) {
3419 Value value = DoubleValue(cds->dval);
3420 attrs = cds->flags;
3421 if (!attrs)
3422 attrs = JSPROP_READONLY | JSPROP_PERMANENT;
3423 ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
3424 if (!ok)
3425 break;
3427 return ok;
3430 JS_PUBLIC_API(JSBool)
3431 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
3433 JSBool ok;
3435 for (ok = true; ps->name; ps++) {
3436 ok = DefineProperty(cx, obj, ps->name, UndefinedValue(),
3437 Valueify(ps->getter), Valueify(ps->setter),
3438 ps->flags, Shape::HAS_SHORTID, ps->tinyid);
3439 if (!ok)
3440 break;
3442 return ok;
3445 JS_PUBLIC_API(JSBool)
3446 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *alias)
3448 JSObject *obj2;
3449 JSProperty *prop;
3450 JSBool ok;
3451 Shape *shape;
3453 CHECK_REQUEST(cx);
3454 assertSameCompartment(cx, obj);
3456 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3457 if (!atom)
3458 return JS_FALSE;
3459 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
3460 return JS_FALSE;
3461 if (!prop) {
3462 js_ReportIsNotDefined(cx, name);
3463 return JS_FALSE;
3465 if (obj2 != obj || !obj->isNative()) {
3466 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3467 alias, name, obj2->getClass()->name);
3468 return JS_FALSE;
3470 atom = js_Atomize(cx, alias, strlen(alias), 0);
3471 if (!atom) {
3472 ok = JS_FALSE;
3473 } else {
3474 shape = (Shape *)prop;
3475 ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
3476 shape->getter(), shape->setter(), shape->slot,
3477 shape->attributes(), shape->getFlags() | Shape::ALIAS,
3478 shape->shortid)
3479 != NULL);
3481 return ok;
3484 JS_PUBLIC_API(JSBool)
3485 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
3487 JSObject *obj2;
3488 JSProperty *prop;
3489 Shape *shape;
3491 CHECK_REQUEST(cx);
3492 assertSameCompartment(cx, obj);
3494 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3495 if (!atom)
3496 return JS_FALSE;
3497 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
3498 return JS_FALSE;
3499 if (!prop) {
3500 js_ReportIsNotDefined(cx, name);
3501 return JS_FALSE;
3503 if (obj2 != obj || !obj->isNative()) {
3504 char numBuf[12];
3505 JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
3506 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3507 numBuf, name, obj2->getClass()->name);
3508 return JS_FALSE;
3510 shape = (Shape *)prop;
3511 return js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
3512 shape->getter(), shape->setter(), shape->slot,
3513 shape->attributes(), shape->getFlags() | Shape::ALIAS,
3514 shape->shortid)
3515 != NULL;
3518 static JSBool
3519 GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3520 JSBool own, PropertyDescriptor *desc)
3522 JSObject *obj2;
3523 JSProperty *prop;
3525 if (!LookupPropertyById(cx, obj, id, flags, &obj2, &prop))
3526 return JS_FALSE;
3528 if (!prop || (own && obj != obj2)) {
3529 desc->obj = NULL;
3530 desc->attrs = 0;
3531 desc->getter = NULL;
3532 desc->setter = NULL;
3533 desc->value.setUndefined();
3534 return JS_TRUE;
3537 desc->obj = obj2;
3538 if (obj2->isNative()) {
3539 Shape *shape = (Shape *) prop;
3540 desc->attrs = shape->attributes();
3542 if (shape->isMethod()) {
3543 desc->getter = desc->setter = PropertyStub;
3544 desc->value.setObject(shape->methodObject());
3545 } else {
3546 desc->getter = shape->getter();
3547 desc->setter = shape->setter();
3548 if (obj2->containsSlot(shape->slot))
3549 desc->value = obj2->nativeGetSlot(shape->slot);
3550 else
3551 desc->value.setUndefined();
3553 } else {
3554 if (obj2->isProxy()) {
3555 JSAutoResolveFlags rf(cx, flags);
3556 return own
3557 ? JSProxy::getOwnPropertyDescriptor(cx, obj2, id, false, desc)
3558 : JSProxy::getPropertyDescriptor(cx, obj2, id, false, desc);
3560 if (!obj2->getAttributes(cx, id, &desc->attrs))
3561 return false;
3562 desc->getter = NULL;
3563 desc->setter = NULL;
3564 desc->value.setUndefined();
3566 return true;
3569 JS_PUBLIC_API(JSBool)
3570 JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3571 JSPropertyDescriptor *desc)
3573 return GetPropertyDescriptorById(cx, obj, id, flags, JS_FALSE, Valueify(desc));
3576 JS_PUBLIC_API(JSBool)
3577 JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *obj, jsid id,
3578 uintN *attrsp, JSBool *foundp,
3579 JSPropertyOp *getterp, JSPropertyOp *setterp)
3581 PropertyDescriptor desc;
3582 if (!GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, JS_FALSE, &desc))
3583 return false;
3585 *attrsp = desc.attrs;
3586 *foundp = (desc.obj != NULL);
3587 if (getterp)
3588 *getterp = Jsvalify(desc.getter);
3589 if (setterp)
3590 *setterp = Jsvalify(desc.setter);
3591 return true;
3594 JS_PUBLIC_API(JSBool)
3595 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3596 uintN *attrsp, JSBool *foundp)
3598 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3599 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3600 attrsp, foundp, NULL, NULL);
3603 JS_PUBLIC_API(JSBool)
3604 JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3605 uintN *attrsp, JSBool *foundp)
3607 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3608 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3609 attrsp, foundp, NULL, NULL);
3612 JS_PUBLIC_API(JSBool)
3613 JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, const char *name,
3614 uintN *attrsp, JSBool *foundp,
3615 JSPropertyOp *getterp, JSPropertyOp *setterp)
3617 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3618 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3619 attrsp, foundp, getterp, setterp);
3622 JS_PUBLIC_API(JSBool)
3623 JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
3624 const jschar *name, size_t namelen,
3625 uintN *attrsp, JSBool *foundp,
3626 JSPropertyOp *getterp, JSPropertyOp *setterp)
3628 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3629 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3630 attrsp, foundp, getterp, setterp);
3633 JS_PUBLIC_API(JSBool)
3634 JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3636 CHECK_REQUEST(cx);
3637 return js_GetOwnPropertyDescriptor(cx, obj, id, Valueify(vp));
3640 static JSBool
3641 SetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, uintN attrs, JSBool *foundp)
3643 JSObject *obj2;
3644 JSProperty *prop;
3646 if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
3647 return false;
3648 if (!prop || obj != obj2) {
3649 *foundp = false;
3650 return true;
3652 JSBool ok = obj->isNative()
3653 ? js_SetNativeAttributes(cx, obj, (Shape *) prop, attrs)
3654 : obj->setAttributes(cx, id, &attrs);
3655 if (ok)
3656 *foundp = true;
3657 return ok;
3660 JS_PUBLIC_API(JSBool)
3661 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3662 uintN attrs, JSBool *foundp)
3664 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3665 return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
3668 JS_PUBLIC_API(JSBool)
3669 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3670 uintN attrs, JSBool *foundp)
3672 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3673 return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
3676 JS_PUBLIC_API(JSBool)
3677 JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3679 CHECK_REQUEST(cx);
3680 assertSameCompartment(cx, obj, id);
3681 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3682 return obj->getProperty(cx, id, Valueify(vp));
3685 JS_PUBLIC_API(JSBool)
3686 JS_GetPropertyByIdDefault(JSContext *cx, JSObject *obj, jsid id, jsval def, jsval *vp)
3688 return GetPropertyDefault(cx, obj, id, Valueify(def), Valueify(vp));
3691 JS_PUBLIC_API(JSBool)
3692 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3694 return JS_GetPropertyById(cx, obj, INT_TO_JSID(index), vp);
3697 JS_PUBLIC_API(JSBool)
3698 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3700 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3701 return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3704 JS_PUBLIC_API(JSBool)
3705 JS_GetPropertyDefault(JSContext *cx, JSObject *obj, const char *name, jsval def, jsval *vp)
3707 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3708 return atom && JS_GetPropertyByIdDefault(cx, obj, ATOM_TO_JSID(atom), def, vp);
3711 JS_PUBLIC_API(JSBool)
3712 JS_GetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3714 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3715 return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3718 JS_PUBLIC_API(JSBool)
3719 JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval *vp)
3721 CHECK_REQUEST(cx);
3722 assertSameCompartment(cx, obj, id);
3723 if (!js_GetMethod(cx, obj, id, JSGET_METHOD_BARRIER, Valueify(vp)))
3724 return JS_FALSE;
3725 if (objp)
3726 *objp = obj;
3727 return JS_TRUE;
3730 JS_PUBLIC_API(JSBool)
3731 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, jsval *vp)
3733 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3734 return atom && JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), objp, vp);
3737 JS_PUBLIC_API(JSBool)
3738 JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3740 CHECK_REQUEST(cx);
3741 assertSameCompartment(cx, obj, id);
3742 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
3743 return obj->setProperty(cx, id, Valueify(vp), false);
3746 JS_PUBLIC_API(JSBool)
3747 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3749 return JS_SetPropertyById(cx, obj, INT_TO_JSID(index), vp);
3752 JS_PUBLIC_API(JSBool)
3753 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3755 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3756 return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3759 JS_PUBLIC_API(JSBool)
3760 JS_SetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3762 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3763 return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3766 JS_PUBLIC_API(JSBool)
3767 JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
3769 CHECK_REQUEST(cx);
3770 assertSameCompartment(cx, obj, id);
3771 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3772 return obj->deleteProperty(cx, id, Valueify(rval), false);
3775 JS_PUBLIC_API(JSBool)
3776 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
3778 return JS_DeletePropertyById2(cx, obj, INT_TO_JSID(index), rval);
3781 JS_PUBLIC_API(JSBool)
3782 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name, jsval *rval)
3784 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3785 return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
3788 JS_PUBLIC_API(JSBool)
3789 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *rval)
3791 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3792 return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
3795 JS_PUBLIC_API(JSBool)
3796 JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id)
3798 jsval junk;
3799 return JS_DeletePropertyById2(cx, obj, id, &junk);
3802 JS_PUBLIC_API(JSBool)
3803 JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
3805 jsval junk;
3806 return JS_DeleteElement2(cx, obj, index, &junk);
3809 JS_PUBLIC_API(JSBool)
3810 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
3812 jsval junk;
3813 return JS_DeleteProperty2(cx, obj, name, &junk);
3816 JS_PUBLIC_API(void)
3817 JS_ClearScope(JSContext *cx, JSObject *obj)
3819 CHECK_REQUEST(cx);
3820 assertSameCompartment(cx, obj);
3822 JSFinalizeOp clearOp = obj->getOps()->clear;
3823 if (clearOp)
3824 clearOp(cx, obj);
3826 if (obj->isNative())
3827 js_ClearNative(cx, obj);
3829 /* Clear cached class objects on the global object. */
3830 if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) {
3831 int key;
3833 for (key = JSProto_Null; key < JSProto_LIMIT * 3; key++)
3834 JS_SetReservedSlot(cx, obj, key, JSVAL_VOID);
3837 js_InitRandom(cx);
3840 JS_PUBLIC_API(JSIdArray *)
3841 JS_Enumerate(JSContext *cx, JSObject *obj)
3843 CHECK_REQUEST(cx);
3844 assertSameCompartment(cx, obj);
3846 AutoIdVector props(cx);
3847 JSIdArray *ida;
3848 if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida))
3849 return false;
3850 for (size_t n = 0; n < size_t(ida->length); ++n)
3851 JS_ASSERT(js_CheckForStringIndex(ida->vector[n]) == ida->vector[n]);
3852 return ida;
3856 * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
3857 * prop_iterator_class somehow...
3858 * + preserve the obj->enumerate API while optimizing the native object case
3859 * + native case here uses a Shape *, but that iterates in reverse!
3860 * + so we make non-native match, by reverse-iterating after JS_Enumerating
3862 const uint32 JSSLOT_ITER_INDEX = 0;
3864 static void
3865 prop_iter_finalize(JSContext *cx, JSObject *obj)
3867 void *pdata = obj->getPrivate();
3868 if (!pdata)
3869 return;
3871 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) {
3872 /* Non-native case: destroy the ida enumerated when obj was created. */
3873 JSIdArray *ida = (JSIdArray *) pdata;
3874 JS_DestroyIdArray(cx, ida);
3878 static void
3879 prop_iter_trace(JSTracer *trc, JSObject *obj)
3881 void *pdata = obj->getPrivate();
3882 if (!pdata)
3883 return;
3885 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
3886 /* Native case: just mark the next property to visit. */
3887 ((Shape *) pdata)->trace(trc);
3888 } else {
3889 /* Non-native case: mark each id in the JSIdArray private. */
3890 JSIdArray *ida = (JSIdArray *) pdata;
3891 MarkIdRange(trc, ida->length, ida->vector, "prop iter");
3895 static Class prop_iter_class = {
3896 "PropertyIterator",
3897 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
3898 JSCLASS_MARK_IS_TRACE,
3899 PropertyStub, /* addProperty */
3900 PropertyStub, /* delProperty */
3901 PropertyStub, /* getProperty */
3902 PropertyStub, /* setProperty */
3903 EnumerateStub,
3904 ResolveStub,
3905 ConvertStub,
3906 prop_iter_finalize,
3907 NULL, /* reserved0 */
3908 NULL, /* checkAccess */
3909 NULL, /* call */
3910 NULL, /* construct */
3911 NULL, /* xdrObject */
3912 NULL, /* hasInstance */
3913 JS_CLASS_TRACE(prop_iter_trace)
3916 JS_PUBLIC_API(JSObject *)
3917 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
3919 JSObject *iterobj;
3920 const void *pdata;
3921 jsint index;
3922 JSIdArray *ida;
3924 CHECK_REQUEST(cx);
3925 assertSameCompartment(cx, obj);
3926 iterobj = NewNonFunction<WithProto::Class>(cx, &prop_iter_class, NULL, obj);
3927 if (!iterobj)
3928 return NULL;
3930 if (obj->isNative()) {
3931 /* Native case: start with the last property in obj. */
3932 pdata = obj->lastProperty();
3933 index = -1;
3934 } else {
3936 * Non-native case: enumerate a JSIdArray and keep it via private.
3938 * Note: we have to make sure that we root obj around the call to
3939 * JS_Enumerate to protect against multiple allocations under it.
3941 AutoObjectRooter tvr(cx, iterobj);
3942 ida = JS_Enumerate(cx, obj);
3943 if (!ida)
3944 return NULL;
3945 pdata = ida;
3946 index = ida->length;
3949 /* iterobj cannot escape to other threads here. */
3950 iterobj->setPrivate(const_cast<void *>(pdata));
3951 iterobj->getSlotRef(JSSLOT_ITER_INDEX).setInt32(index);
3952 return iterobj;
3955 JS_PUBLIC_API(JSBool)
3956 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
3958 jsint i;
3959 JSObject *obj;
3960 const Shape *shape;
3961 JSIdArray *ida;
3963 CHECK_REQUEST(cx);
3964 assertSameCompartment(cx, iterobj);
3965 i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
3966 if (i < 0) {
3967 /* Native case: private data is a property tree node pointer. */
3968 obj = iterobj->getParent();
3969 JS_ASSERT(obj->isNative());
3970 shape = (Shape *) iterobj->getPrivate();
3973 * If the next property mapped by obj in the property tree ancestor
3974 * line is not enumerable, or it's an alias, skip it and keep on trying
3975 * to find an enumerable property that is still in obj.
3977 while (shape->previous() && (!shape->enumerable() || shape->isAlias()))
3978 shape = shape->previous();
3980 if (!shape->previous()) {
3981 JS_ASSERT(JSID_IS_EMPTY(shape->id));
3982 *idp = JSID_VOID;
3983 } else {
3984 iterobj->setPrivate(const_cast<Shape *>(shape->previous()));
3985 *idp = shape->id;
3987 } else {
3988 /* Non-native case: use the ida enumerated when iterobj was created. */
3989 ida = (JSIdArray *) iterobj->getPrivate();
3990 JS_ASSERT(i <= ida->length);
3991 STATIC_ASSUME(i <= ida->length);
3992 if (i == 0) {
3993 *idp = JSID_VOID;
3994 } else {
3995 *idp = ida->vector[--i];
3996 iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i));
3999 return JS_TRUE;
4002 JS_PUBLIC_API(JSBool)
4003 JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
4005 CHECK_REQUEST(cx);
4006 assertSameCompartment(cx, obj);
4007 return js_GetReservedSlot(cx, obj, index, Valueify(vp));
4010 JS_PUBLIC_API(JSBool)
4011 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
4013 CHECK_REQUEST(cx);
4014 assertSameCompartment(cx, obj, v);
4015 return js_SetReservedSlot(cx, obj, index, Valueify(v));
4018 JS_PUBLIC_API(JSObject *)
4019 JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
4021 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4022 CHECK_REQUEST(cx);
4023 /* NB: jsuint cast does ToUint32. */
4024 assertSameCompartment(cx, JSValueArray(vector, vector ? (jsuint)length : 0));
4025 return js_NewArrayObject(cx, (jsuint)length, Valueify(vector));
4028 JS_PUBLIC_API(JSBool)
4029 JS_IsArrayObject(JSContext *cx, JSObject *obj)
4031 assertSameCompartment(cx, obj);
4032 return obj->isArray() ||
4033 (obj->isWrapper() && JSWrapper::wrappedObject(obj)->isArray());
4036 JS_PUBLIC_API(JSBool)
4037 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
4039 CHECK_REQUEST(cx);
4040 assertSameCompartment(cx, obj);
4041 return js_GetLengthProperty(cx, obj, lengthp);
4044 JS_PUBLIC_API(JSBool)
4045 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
4047 CHECK_REQUEST(cx);
4048 assertSameCompartment(cx, obj);
4049 return js_SetLengthProperty(cx, obj, length);
4052 JS_PUBLIC_API(JSBool)
4053 JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
4055 CHECK_REQUEST(cx);
4056 assertSameCompartment(cx, obj);
4057 return js_HasLengthProperty(cx, obj, lengthp);
4060 JS_PUBLIC_API(JSBool)
4061 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
4062 jsval *vp, uintN *attrsp)
4064 CHECK_REQUEST(cx);
4065 assertSameCompartment(cx, obj, id);
4066 return CheckAccess(cx, obj, id, mode, Valueify(vp), attrsp);
4069 #ifdef JS_THREADSAFE
4070 JS_PUBLIC_API(jsrefcount)
4071 JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
4073 return JS_ATOMIC_INCREMENT(&principals->refcount);
4076 JS_PUBLIC_API(jsrefcount)
4077 JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
4079 jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
4080 if (rc == 0)
4081 principals->destroy(cx, principals);
4082 return rc;
4084 #endif
4086 JS_PUBLIC_API(JSSecurityCallbacks *)
4087 JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks)
4089 JSSecurityCallbacks *oldcallbacks;
4091 oldcallbacks = rt->securityCallbacks;
4092 rt->securityCallbacks = callbacks;
4093 return oldcallbacks;
4096 JS_PUBLIC_API(JSSecurityCallbacks *)
4097 JS_GetRuntimeSecurityCallbacks(JSRuntime *rt)
4099 return rt->securityCallbacks;
4102 JS_PUBLIC_API(JSSecurityCallbacks *)
4103 JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks)
4105 JSSecurityCallbacks *oldcallbacks;
4107 oldcallbacks = cx->securityCallbacks;
4108 cx->securityCallbacks = callbacks;
4109 return oldcallbacks;
4112 JS_PUBLIC_API(JSSecurityCallbacks *)
4113 JS_GetSecurityCallbacks(JSContext *cx)
4115 return cx->securityCallbacks
4116 ? cx->securityCallbacks
4117 : cx->runtime->securityCallbacks;
4120 JS_PUBLIC_API(JSFunction *)
4121 JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
4122 JSObject *parent, const char *name)
4124 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4125 JSAtom *atom;
4127 CHECK_REQUEST(cx);
4128 assertSameCompartment(cx, parent);
4130 if (!name) {
4131 atom = NULL;
4132 } else {
4133 atom = js_Atomize(cx, name, strlen(name), 0);
4134 if (!atom)
4135 return NULL;
4137 return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, atom);
4140 JS_PUBLIC_API(JSObject *)
4141 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
4143 CHECK_REQUEST(cx);
4144 assertSameCompartment(cx, parent); // XXX no funobj for now
4145 if (!parent) {
4146 if (cx->hasfp())
4147 parent = GetScopeChain(cx, cx->fp());
4148 if (!parent)
4149 parent = cx->globalObject;
4150 JS_ASSERT(parent);
4153 if (funobj->getClass() != &js_FunctionClass) {
4155 * We cannot clone this object, so fail (we used to return funobj, bad
4156 * idea, but we changed incompatibly to teach any abusers a lesson!).
4158 Value v = ObjectValue(*funobj);
4159 js_ReportIsNotFunction(cx, &v, 0);
4160 return NULL;
4163 JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
4164 if (!FUN_FLAT_CLOSURE(fun))
4165 return CloneFunctionObject(cx, fun, parent);
4168 * A flat closure carries its own environment, so why clone it? In case
4169 * someone wants to mutate its fixed slots or add ad-hoc properties. API
4170 * compatibility suggests we not return funobj and let callers mutate the
4171 * returned object at will.
4173 * But it's worse than that: API compatibility according to the test for
4174 * bug 300079 requires we get "upvars" from parent and its ancestors! So
4175 * we do that (grudgingly!). The scope chain ancestors are searched as if
4176 * they were activations, respecting the skip field in each upvar's cookie
4177 * but looking up the property by name instead of frame slot.
4179 JSObject *clone = js_AllocFlatClosure(cx, fun, parent);
4180 if (!clone)
4181 return NULL;
4183 JSUpvarArray *uva = fun->u.i.script->upvars();
4184 uint32 i = uva->length;
4185 JS_ASSERT(i != 0);
4187 for (Shape::Range r(fun->lastUpvar()); i-- != 0; r.popFront()) {
4188 JSObject *obj = parent;
4189 int skip = uva->vector[i].level();
4190 while (--skip > 0) {
4191 if (!obj) {
4192 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4193 JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
4194 return NULL;
4196 obj = obj->getParent();
4199 if (!obj->getProperty(cx, r.front().id, clone->getFlatClosureUpvars() + i))
4200 return NULL;
4203 return clone;
4206 JS_PUBLIC_API(JSObject *)
4207 JS_GetFunctionObject(JSFunction *fun)
4209 return FUN_OBJECT(fun);
4212 JS_PUBLIC_API(const char *)
4213 JS_GetFunctionName(JSFunction *fun)
4215 return fun->atom
4216 ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
4217 : js_anonymous_str;
4220 JS_PUBLIC_API(JSString *)
4221 JS_GetFunctionId(JSFunction *fun)
4223 return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
4226 JS_PUBLIC_API(uintN)
4227 JS_GetFunctionFlags(JSFunction *fun)
4229 return fun->flags;
4232 JS_PUBLIC_API(uint16)
4233 JS_GetFunctionArity(JSFunction *fun)
4235 return fun->nargs;
4238 JS_PUBLIC_API(JSBool)
4239 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
4241 return obj->getClass() == &js_FunctionClass;
4244 static JSBool
4245 js_generic_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp)
4247 JSFunctionSpec *fs;
4248 JSObject *tmp;
4249 Native native;
4251 fs = (JSFunctionSpec *) vp->toObject().getReservedSlot(0).toPrivate();
4252 JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
4254 if (argc < 1) {
4255 js_ReportMissingArg(cx, *vp, 0);
4256 return JS_FALSE;
4259 if (vp[2].isPrimitive()) {
4261 * Make sure that this is an object or null, as required by the generic
4262 * functions.
4264 if (!js_ValueToObjectOrNull(cx, vp[2], &tmp))
4265 return JS_FALSE;
4266 vp[2].setObjectOrNull(tmp);
4270 * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
4271 * which is almost always the class constructor object, e.g. Array. Then
4272 * call the corresponding prototype native method with our first argument
4273 * passed as |this|.
4275 memmove(vp + 1, vp + 2, argc * sizeof(jsval));
4278 * Follow Function.prototype.apply and .call by using the global object as
4279 * the 'this' param if no args.
4281 if (!ComputeThisFromArgv(cx, vp + 2))
4282 return JS_FALSE;
4284 /* Clear the last parameter in case too few arguments were passed. */
4285 vp[2 + --argc].setUndefined();
4287 native =
4288 #ifdef JS_TRACER
4289 (fs->flags & JSFUN_TRCINFO)
4290 ? JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native
4292 #endif
4293 Valueify(fs->call);
4294 return native(cx, argc, vp);
4297 JS_PUBLIC_API(JSBool)
4298 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
4300 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4301 uintN flags;
4302 JSObject *ctor;
4303 JSFunction *fun;
4305 CHECK_REQUEST(cx);
4306 assertSameCompartment(cx, obj);
4307 ctor = NULL;
4308 for (; fs->name; fs++) {
4309 flags = fs->flags;
4312 * Define a generic arity N+1 static method for the arity N prototype
4313 * method if flags contains JSFUN_GENERIC_NATIVE.
4315 if (flags & JSFUN_GENERIC_NATIVE) {
4316 if (!ctor) {
4317 ctor = JS_GetConstructor(cx, obj);
4318 if (!ctor)
4319 return JS_FALSE;
4322 flags &= ~JSFUN_GENERIC_NATIVE;
4323 fun = JS_DefineFunction(cx, ctor, fs->name,
4324 Jsvalify(js_generic_native_method_dispatcher),
4325 fs->nargs + 1,
4326 flags & ~JSFUN_TRCINFO);
4327 if (!fun)
4328 return JS_FALSE;
4331 * As jsapi.h notes, fs must point to storage that lives as long
4332 * as fun->object lives.
4334 Value priv = PrivateValue(fs);
4335 if (!js_SetReservedSlot(cx, FUN_OBJECT(fun), 0, priv))
4336 return JS_FALSE;
4339 fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
4340 if (!fun)
4341 return JS_FALSE;
4343 return JS_TRUE;
4346 JS_PUBLIC_API(JSFunction *)
4347 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
4348 uintN nargs, uintN attrs)
4350 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4351 CHECK_REQUEST(cx);
4352 assertSameCompartment(cx, obj);
4353 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
4354 return atom ? js_DefineFunction(cx, obj, atom, Valueify(call), nargs, attrs) : NULL;
4357 JS_PUBLIC_API(JSFunction *)
4358 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
4359 const jschar *name, size_t namelen, JSNative call,
4360 uintN nargs, uintN attrs)
4362 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4363 CHECK_REQUEST(cx);
4364 assertSameCompartment(cx, obj);
4365 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
4366 return atom ? js_DefineFunction(cx, obj, atom, Valueify(call), nargs, attrs) : NULL;
4369 inline static void
4370 LAST_FRAME_EXCEPTION_CHECK(JSContext *cx, bool result)
4372 if (!result && !(cx->options & JSOPTION_DONT_REPORT_UNCAUGHT))
4373 js_ReportUncaughtException(cx);
4376 inline static void
4377 LAST_FRAME_CHECKS(JSContext *cx, bool result)
4379 if (!JS_IsRunning(cx)) {
4380 LAST_FRAME_EXCEPTION_CHECK(cx, result);
4384 inline static uint32
4385 JS_OPTIONS_TO_TCFLAGS(JSContext *cx)
4387 return ((cx->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) |
4388 ((cx->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0);
4391 extern JS_PUBLIC_API(JSScript *)
4392 JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4393 JSPrincipals *principals,
4394 const jschar *chars, size_t length,
4395 const char *filename, uintN lineno,
4396 JSVersion version)
4398 AutoVersionAPI avi(cx, version);
4399 return JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno);
4402 JS_PUBLIC_API(JSScript *)
4403 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4404 const jschar *chars, size_t length,
4405 const char *filename, uintN lineno)
4407 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4408 CHECK_REQUEST(cx);
4409 assertSameCompartment(cx, obj, principals);
4411 uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4412 JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
4413 chars, length, NULL, filename, lineno);
4414 if (script && !js_NewScriptObject(cx, script)) {
4415 js_DestroyScript(cx, script);
4416 script = NULL;
4418 LAST_FRAME_CHECKS(cx, script);
4419 return script;
4422 JS_PUBLIC_API(JSScript *)
4423 JS_CompileUCScript(JSContext *cx, JSObject *obj, const jschar *chars, size_t length,
4424 const char *filename, uintN lineno)
4426 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4427 return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno);
4430 JS_PUBLIC_API(JSScript *)
4431 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
4432 JSPrincipals *principals,
4433 const char *bytes, size_t length,
4434 const char *filename, uintN lineno)
4436 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4437 CHECK_REQUEST(cx);
4439 jschar *chars = js_InflateString(cx, bytes, &length);
4440 if (!chars)
4441 return NULL;
4442 JSScript *script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno);
4443 cx->free(chars);
4444 return script;
4447 JS_PUBLIC_API(JSScript *)
4448 JS_CompileScript(JSContext *cx, JSObject *obj, const char *bytes, size_t length,
4449 const char *filename, uintN lineno)
4451 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4452 return JS_CompileScriptForPrincipals(cx, obj, NULL, bytes, length, filename, lineno);
4455 JS_PUBLIC_API(JSBool)
4456 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, const char *bytes, size_t length)
4458 jschar *chars;
4459 JSBool result;
4460 JSExceptionState *exnState;
4461 JSErrorReporter older;
4463 CHECK_REQUEST(cx);
4464 assertSameCompartment(cx, obj);
4465 chars = js_InflateString(cx, bytes, &length);
4466 if (!chars)
4467 return JS_TRUE;
4470 * Return true on any out-of-memory error, so our caller doesn't try to
4471 * collect more buffered source.
4473 result = JS_TRUE;
4474 exnState = JS_SaveExceptionState(cx);
4476 Parser parser(cx);
4477 if (parser.init(chars, length, NULL, NULL, 1)) {
4478 older = JS_SetErrorReporter(cx, NULL);
4479 if (!parser.parse(obj) &&
4480 parser.tokenStream.isUnexpectedEOF()) {
4482 * We ran into an error. If it was because we ran out of
4483 * source, we return false so our caller knows to try to
4484 * collect more buffered source.
4486 result = JS_FALSE;
4488 JS_SetErrorReporter(cx, older);
4491 cx->free(chars);
4492 JS_RestoreExceptionState(cx, exnState);
4493 return result;
4496 JS_PUBLIC_API(JSScript *)
4497 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
4499 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4500 FILE *fp;
4501 uint32 tcflags;
4502 JSScript *script;
4504 CHECK_REQUEST(cx);
4505 assertSameCompartment(cx, obj);
4506 if (!filename || strcmp(filename, "-") == 0) {
4507 fp = stdin;
4508 } else {
4509 fp = fopen(filename, "r");
4510 if (!fp) {
4511 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
4512 filename, "No such file or directory");
4513 return NULL;
4517 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4518 script = Compiler::compileScript(cx, obj, NULL, NULL, tcflags,
4519 NULL, 0, fp, filename, 1);
4520 if (fp != stdin)
4521 fclose(fp);
4522 if (script && !js_NewScriptObject(cx, script)) {
4523 js_DestroyScript(cx, script);
4524 script = NULL;
4526 LAST_FRAME_CHECKS(cx, script);
4527 return script;
4530 JS_PUBLIC_API(JSScript *)
4531 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *filename, FILE *file,
4532 JSPrincipals *principals)
4534 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4535 uint32 tcflags;
4536 JSScript *script;
4538 CHECK_REQUEST(cx);
4539 assertSameCompartment(cx, obj, principals);
4540 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4541 script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
4542 NULL, 0, file, filename, 1);
4543 if (script && !js_NewScriptObject(cx, script)) {
4544 js_DestroyScript(cx, script);
4545 script = NULL;
4547 LAST_FRAME_CHECKS(cx, script);
4548 return script;
4551 JS_PUBLIC_API(JSScript *)
4552 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *file)
4554 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4555 return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
4558 JS_PUBLIC_API(JSObject *)
4559 JS_NewScriptObject(JSContext *cx, JSScript *script)
4561 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4562 CHECK_REQUEST(cx);
4563 assertSameCompartment(cx, script);
4564 if (!script)
4565 return NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
4568 * This function should only ever be applied to JSScripts that had
4569 * script objects allocated for them when they were created, as
4570 * described in the comment for JSScript::u.object.
4572 JS_ASSERT(script->u.object);
4573 JS_ASSERT(script != JSScript::emptyScript());
4574 return script->u.object;
4577 JS_PUBLIC_API(JSObject *)
4578 JS_GetScriptObject(JSScript *script)
4581 * This function should only ever be applied to JSScripts that had
4582 * script objects allocated for them when they were created, as
4583 * described in the comment for JSScript::u.object.
4585 JS_ASSERT(script->u.object);
4586 return script->u.object;
4589 JS_PUBLIC_API(void)
4590 JS_DestroyScript(JSContext *cx, JSScript *script)
4592 CHECK_REQUEST(cx);
4595 * Originally, JSScript lifetimes were managed explicitly, and this function
4596 * was used to free a JSScript. Now, this function does nothing, and the
4597 * garbage collector manages JSScripts; you must root the JSScript's script
4598 * object (obtained via JS_GetScriptObject) to keep it alive.
4600 * However, since the script objects have taken over this responsibility, it
4601 * follows that every script passed here must have a script object.
4603 JS_ASSERT(script->u.object);
4606 JS_PUBLIC_API(JSFunction *)
4607 JS_CompileUCFunctionForPrincipalsVersion(JSContext *cx, JSObject *obj,
4608 JSPrincipals *principals, const char *name,
4609 uintN nargs, const char **argnames,
4610 const jschar *chars, size_t length,
4611 const char *filename, uintN lineno,
4612 JSVersion version)
4614 AutoVersionAPI avi(cx, version);
4615 return JS_CompileUCFunctionForPrincipals(cx, obj, principals, name, nargs, argnames, chars,
4616 length, filename, lineno);
4619 JS_PUBLIC_API(JSFunction *)
4620 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
4621 JSPrincipals *principals, const char *name,
4622 uintN nargs, const char **argnames,
4623 const jschar *chars, size_t length,
4624 const char *filename, uintN lineno)
4626 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4627 JSFunction *fun;
4628 JSAtom *funAtom, *argAtom;
4629 uintN i;
4631 CHECK_REQUEST(cx);
4632 assertSameCompartment(cx, obj, principals);
4633 if (!name) {
4634 funAtom = NULL;
4635 } else {
4636 funAtom = js_Atomize(cx, name, strlen(name), 0);
4637 if (!funAtom) {
4638 fun = NULL;
4639 goto out2;
4642 fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
4643 if (!fun)
4644 goto out2;
4647 AutoObjectRooter tvr(cx, FUN_OBJECT(fun));
4648 MUST_FLOW_THROUGH("out");
4650 for (i = 0; i < nargs; i++) {
4651 argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
4652 if (!argAtom) {
4653 fun = NULL;
4654 goto out2;
4656 if (!fun->addLocal(cx, argAtom, JSLOCAL_ARG)) {
4657 fun = NULL;
4658 goto out2;
4662 if (!Compiler::compileFunctionBody(cx, fun, principals,
4663 chars, length, filename, lineno)) {
4664 fun = NULL;
4665 goto out2;
4668 if (obj && funAtom &&
4669 !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), ObjectValue(*fun),
4670 NULL, NULL, JSPROP_ENUMERATE)) {
4671 fun = NULL;
4674 #ifdef JS_SCOPE_DEPTH_METER
4675 if (fun && obj) {
4676 JSObject *pobj = obj;
4677 uintN depth = 1;
4679 while ((pobj = pobj->getParent()) != NULL)
4680 ++depth;
4681 JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
4683 #endif
4686 out2:
4687 LAST_FRAME_CHECKS(cx, fun);
4688 return fun;
4691 JS_PUBLIC_API(JSFunction *)
4692 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
4693 uintN nargs, const char **argnames,
4694 const jschar *chars, size_t length,
4695 const char *filename, uintN lineno)
4697 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4698 return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames,
4699 chars, length, filename, lineno);
4702 JS_PUBLIC_API(JSFunction *)
4703 JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
4704 JSPrincipals *principals, const char *name,
4705 uintN nargs, const char **argnames,
4706 const char *bytes, size_t length,
4707 const char *filename, uintN lineno)
4709 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4710 jschar *chars = js_InflateString(cx, bytes, &length);
4711 if (!chars)
4712 return NULL;
4713 JSFunction *fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
4714 nargs, argnames, chars, length,
4715 filename, lineno);
4716 cx->free(chars);
4717 return fun;
4720 JS_PUBLIC_API(JSFunction *)
4721 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
4722 uintN nargs, const char **argnames,
4723 const char *bytes, size_t length,
4724 const char *filename, uintN lineno)
4726 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4727 return JS_CompileFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames, bytes, length,
4728 filename, lineno);
4731 JS_PUBLIC_API(JSString *)
4732 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, uintN indent)
4734 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4735 JSPrinter *jp;
4736 JSString *str;
4738 CHECK_REQUEST(cx);
4739 #ifdef DEBUG
4740 if (cx->compartment != script->compartment)
4741 CompartmentChecker::fail(cx->compartment, script->compartment);
4742 #endif
4743 jp = js_NewPrinter(cx, name, NULL,
4744 indent & ~JS_DONT_PRETTY_PRINT,
4745 !(indent & JS_DONT_PRETTY_PRINT),
4746 false, false);
4747 if (!jp)
4748 return NULL;
4749 if (js_DecompileScript(jp, script))
4750 str = js_GetPrinterOutput(jp);
4751 else
4752 str = NULL;
4753 js_DestroyPrinter(jp);
4754 return str;
4757 JS_PUBLIC_API(JSString *)
4758 JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
4760 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4761 CHECK_REQUEST(cx);
4762 assertSameCompartment(cx, fun);
4763 return js_DecompileToString(cx, "JS_DecompileFunction", fun,
4764 indent & ~JS_DONT_PRETTY_PRINT,
4765 !(indent & JS_DONT_PRETTY_PRINT),
4766 false, false, js_DecompileFunction);
4769 JS_PUBLIC_API(JSString *)
4770 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
4772 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4773 CHECK_REQUEST(cx);
4774 assertSameCompartment(cx, fun);
4775 return js_DecompileToString(cx, "JS_DecompileFunctionBody", fun,
4776 indent & ~JS_DONT_PRETTY_PRINT,
4777 !(indent & JS_DONT_PRETTY_PRINT),
4778 false, false, js_DecompileFunctionBody);
4781 JS_PUBLIC_API(JSBool)
4782 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
4784 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4785 JSBool ok;
4787 CHECK_REQUEST(cx);
4788 assertSameCompartment(cx, obj, script);
4789 /* This should receive only scripts handed out via the JSAPI. */
4790 JS_ASSERT(script == JSScript::emptyScript() || script->u.object);
4791 ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
4792 LAST_FRAME_CHECKS(cx, ok);
4793 return ok;
4796 JS_PUBLIC_API(JSBool)
4797 JS_EvaluateUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4798 JSPrincipals *principals,
4799 const jschar *chars, uintN length,
4800 const char *filename, uintN lineno,
4801 jsval *rval, JSVersion version)
4803 AutoVersionAPI avi(cx, version);
4804 return JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno,
4805 rval);
4808 JS_PUBLIC_API(JSBool)
4809 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
4810 JSPrincipals *principals,
4811 const jschar *chars, uintN length,
4812 const char *filename, uintN lineno,
4813 jsval *rval)
4815 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4816 JSScript *script;
4817 JSBool ok;
4819 CHECK_REQUEST(cx);
4820 script = Compiler::compileScript(cx, obj, NULL, principals,
4821 !rval
4822 ? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
4823 : TCF_COMPILE_N_GO,
4824 chars, length, NULL, filename, lineno);
4825 if (!script) {
4826 LAST_FRAME_CHECKS(cx, script);
4827 return JS_FALSE;
4829 ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
4830 LAST_FRAME_CHECKS(cx, ok);
4831 js_DestroyScript(cx, script);
4832 return ok;
4835 JS_PUBLIC_API(JSBool)
4836 JS_EvaluateUCScript(JSContext *cx, JSObject *obj, const jschar *chars, uintN length,
4837 const char *filename, uintN lineno, jsval *rval)
4839 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4840 return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno, rval);
4843 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
4844 JS_PUBLIC_API(JSBool)
4845 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4846 const char *bytes, uintN nbytes,
4847 const char *filename, uintN lineno, jsval *rval)
4849 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4850 size_t length = nbytes;
4851 jschar *chars = js_InflateString(cx, bytes, &length);
4852 if (!chars)
4853 return JS_FALSE;
4854 JSBool ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
4855 filename, lineno, rval);
4856 cx->free(chars);
4857 return ok;
4860 JS_PUBLIC_API(JSBool)
4861 JS_EvaluateScript(JSContext *cx, JSObject *obj, const char *bytes, uintN nbytes,
4862 const char *filename, uintN lineno, jsval *rval)
4864 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4865 return JS_EvaluateScriptForPrincipals(cx, obj, NULL, bytes, nbytes, filename, lineno, rval);
4868 JS_PUBLIC_API(JSBool)
4869 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, jsval *argv,
4870 jsval *rval)
4872 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4873 JSBool ok;
4875 CHECK_REQUEST(cx);
4876 assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc));
4877 ok = ExternalInvoke(cx, obj, ObjectValue(*fun), argc, Valueify(argv), Valueify(rval));
4878 LAST_FRAME_CHECKS(cx, ok);
4879 return ok;
4882 JS_PUBLIC_API(JSBool)
4883 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, jsval *argv,
4884 jsval *rval)
4886 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4887 CHECK_REQUEST(cx);
4888 assertSameCompartment(cx, obj, JSValueArray(argv, argc));
4890 AutoValueRooter tvr(cx);
4891 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
4892 JSBool ok = atom &&
4893 js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, tvr.addr()) &&
4894 ExternalInvoke(cx, obj, tvr.value(), argc, Valueify(argv), Valueify(rval));
4895 LAST_FRAME_CHECKS(cx, ok);
4896 return ok;
4899 JS_PUBLIC_API(JSBool)
4900 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, jsval *argv,
4901 jsval *rval)
4903 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4904 JSBool ok;
4906 CHECK_REQUEST(cx);
4907 assertSameCompartment(cx, obj, fval, JSValueArray(argv, argc));
4908 ok = ExternalInvoke(cx, obj, Valueify(fval), argc, Valueify(argv), Valueify(rval));
4909 LAST_FRAME_CHECKS(cx, ok);
4910 return ok;
4913 namespace JS {
4915 JS_PUBLIC_API(bool)
4916 Call(JSContext *cx, jsval thisv, jsval fval, uintN argc, jsval *argv, jsval *rval)
4918 JSBool ok;
4920 CHECK_REQUEST(cx);
4921 assertSameCompartment(cx, thisv, fval, JSValueArray(argv, argc));
4922 ok = ExternalInvoke(cx, Valueify(thisv), Valueify(fval), argc, Valueify(argv), Valueify(rval));
4923 LAST_FRAME_CHECKS(cx, ok);
4924 return ok;
4927 } // namespace JS
4929 JS_PUBLIC_API(JSObject *)
4930 JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv)
4932 CHECK_REQUEST(cx);
4933 assertSameCompartment(cx, ctor, JSValueArray(argv, argc));
4935 // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
4936 // is not a simple variation of JSOP_CALL. We have to determine what class
4937 // of object to create, create it, and clamp the return value to an object,
4938 // among other details. js_InvokeConstructor does the hard work.
4939 InvokeArgsGuard args;
4940 if (!cx->stack().pushInvokeArgs(cx, argc, &args))
4941 return NULL;
4943 args.callee().setObject(*ctor);
4944 args.thisv().setNull();
4945 memcpy(args.argv(), argv, argc * sizeof(jsval));
4947 bool ok = InvokeConstructor(cx, args);
4948 JSObject *obj = (ok && args.rval().isObject())
4949 ? &args.rval().toObject()
4950 : NULL;
4952 LAST_FRAME_CHECKS(cx, ok);
4953 return obj;
4956 JS_PUBLIC_API(JSOperationCallback)
4957 JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback)
4959 #ifdef JS_THREADSAFE
4960 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
4961 #endif
4962 JSOperationCallback old = cx->operationCallback;
4963 cx->operationCallback = callback;
4964 return old;
4967 JS_PUBLIC_API(JSOperationCallback)
4968 JS_GetOperationCallback(JSContext *cx)
4970 return cx->operationCallback;
4973 JS_PUBLIC_API(void)
4974 JS_TriggerOperationCallback(JSContext *cx)
4976 #ifdef JS_THREADSAFE
4977 AutoLockGC lock(cx->runtime);
4978 #endif
4979 TriggerOperationCallback(cx);
4982 JS_PUBLIC_API(void)
4983 JS_TriggerAllOperationCallbacks(JSRuntime *rt)
4985 #ifdef JS_THREADSAFE
4986 AutoLockGC lock(rt);
4987 #endif
4988 TriggerAllOperationCallbacks(rt);
4991 JS_PUBLIC_API(JSBool)
4992 JS_IsRunning(JSContext *cx)
4995 * The use of cx->fp below is safe. Rationale: Here we don't care if the
4996 * interpreter state is stale. We just want to know if there *is* any
4997 * interpreter state.
4999 VOUCH_DOES_NOT_REQUIRE_STACK();
5001 #ifdef JS_TRACER
5002 JS_ASSERT_IF(JS_TRACE_MONITOR(cx).tracecx == cx, cx->hasfp());
5003 #endif
5004 JSStackFrame *fp = cx->maybefp();
5005 while (fp && fp->isDummyFrame())
5006 fp = fp->prev();
5007 return fp != NULL;
5010 JS_PUBLIC_API(JSStackFrame *)
5011 JS_SaveFrameChain(JSContext *cx)
5013 CHECK_REQUEST(cx);
5014 JSStackFrame *fp = js_GetTopStackFrame(cx);
5015 if (!fp)
5016 return NULL;
5017 cx->saveActiveSegment();
5018 return fp;
5021 JS_PUBLIC_API(void)
5022 JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
5024 CHECK_REQUEST(cx);
5025 JS_ASSERT_NOT_ON_TRACE(cx);
5026 JS_ASSERT(!cx->hasfp());
5027 if (!fp)
5028 return;
5029 cx->restoreSegment();
5030 cx->resetCompartment();
5033 /************************************************************************/
5035 JS_PUBLIC_API(JSString *)
5036 JS_NewString(JSContext *cx, char *bytes, size_t nbytes)
5038 size_t length = nbytes;
5039 jschar *chars;
5040 JSString *str;
5042 CHECK_REQUEST(cx);
5044 /* Make a UTF-16 vector from the 8-bit char codes in bytes. */
5045 chars = js_InflateString(cx, bytes, &length);
5046 if (!chars)
5047 return NULL;
5049 /* Free chars (but not bytes, which caller frees on error) if we fail. */
5050 str = js_NewString(cx, chars, length);
5051 if (!str) {
5052 cx->free(chars);
5053 return NULL;
5056 /* Hand off bytes to the deflated string cache, if possible. */
5057 if (!cx->runtime->deflatedStringCache->setBytes(cx, str, bytes))
5058 cx->free(bytes);
5059 return str;
5062 JS_PUBLIC_API(JSString *)
5063 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
5065 jschar *js;
5066 JSString *str;
5068 CHECK_REQUEST(cx);
5069 js = js_InflateString(cx, s, &n);
5070 if (!js)
5071 return NULL;
5072 str = js_NewString(cx, js, n);
5073 if (!str)
5074 cx->free(js);
5075 return str;
5078 JS_PUBLIC_API(JSString *)
5079 JS_NewStringCopyZ(JSContext *cx, const char *s)
5081 size_t n;
5082 jschar *js;
5083 JSString *str;
5085 CHECK_REQUEST(cx);
5086 if (!s)
5087 return cx->runtime->emptyString;
5088 n = strlen(s);
5089 js = js_InflateString(cx, s, &n);
5090 if (!js)
5091 return NULL;
5092 str = js_NewString(cx, js, n);
5093 if (!str)
5094 cx->free(js);
5095 return str;
5098 JS_PUBLIC_API(JSBool)
5099 JS_StringHasBeenInterned(JSString *str)
5101 return str->isAtomized();
5104 JS_PUBLIC_API(JSString *)
5105 JS_InternString(JSContext *cx, const char *s)
5107 JSAtom *atom;
5109 CHECK_REQUEST(cx);
5110 atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
5111 if (!atom)
5112 return NULL;
5113 return ATOM_TO_STRING(atom);
5116 JS_PUBLIC_API(JSString *)
5117 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
5119 CHECK_REQUEST(cx);
5120 return js_NewString(cx, chars, length);
5123 JS_PUBLIC_API(JSString *)
5124 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
5126 CHECK_REQUEST(cx);
5127 return js_NewStringCopyN(cx, s, n);
5130 JS_PUBLIC_API(JSString *)
5131 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
5133 CHECK_REQUEST(cx);
5134 if (!s)
5135 return cx->runtime->emptyString;
5136 return js_NewStringCopyZ(cx, s);
5139 JS_PUBLIC_API(JSString *)
5140 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
5142 JSAtom *atom;
5144 CHECK_REQUEST(cx);
5145 atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
5146 if (!atom)
5147 return NULL;
5148 return ATOM_TO_STRING(atom);
5151 JS_PUBLIC_API(JSString *)
5152 JS_InternUCString(JSContext *cx, const jschar *s)
5154 return JS_InternUCStringN(cx, s, js_strlen(s));
5157 JS_PUBLIC_API(char *)
5158 JS_GetStringBytes(JSString *str)
5160 const char *bytes;
5162 bytes = js_GetStringBytes(NULL, str);
5163 return (char *)(bytes ? bytes : "");
5166 JS_PUBLIC_API(jschar *)
5167 JS_GetStringChars(JSString *str)
5169 size_t n, size;
5170 jschar *s;
5172 str->ensureNotRope();
5175 * API botch (again, shades of JS_GetStringBytes): we have no cx to report
5176 * out-of-memory when undepending strings, so we replace JSString::undepend
5177 * with explicit malloc call and ignore its errors.
5179 * If we fail to convert a dependent string into an independent one, our
5180 * caller will not be guaranteed a \u0000 terminator as a backstop. This
5181 * may break some clients who already misbehave on embedded NULs.
5183 * The gain of dependent strings, which cure quadratic and cubic growth
5184 * rate bugs in string concatenation, is worth this slight loss in API
5185 * compatibility.
5187 if (str->isDependent()) {
5188 n = str->dependentLength();
5189 size = (n + 1) * sizeof(jschar);
5190 s = (jschar *) js_malloc(size);
5191 if (s) {
5192 memcpy(s, str->dependentChars(), n * sizeof *s);
5193 s[n] = 0;
5194 str->initFlat(s, n);
5195 } else {
5196 s = str->dependentChars();
5198 } else {
5199 str->flatClearMutable();
5200 s = str->flatChars();
5202 return s;
5205 JS_PUBLIC_API(size_t)
5206 JS_GetStringLength(JSString *str)
5208 return str->length();
5211 JS_PUBLIC_API(const char *)
5212 JS_GetStringBytesZ(JSContext *cx, JSString *str)
5214 assertSameCompartment(cx, str);
5215 return js_GetStringBytes(cx, str);
5218 JS_PUBLIC_API(const jschar *)
5219 JS_GetStringCharsZ(JSContext *cx, JSString *str)
5221 assertSameCompartment(cx, str);
5222 return str->undepend(cx);
5225 JS_PUBLIC_API(intN)
5226 JS_CompareStrings(JSString *str1, JSString *str2)
5228 return js_CompareStrings(str1, str2);
5231 JS_PUBLIC_API(JSString *)
5232 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
5234 CHECK_REQUEST(cx);
5235 return js_NewString(cx, chars, length);
5238 JS_PUBLIC_API(JSString *)
5239 JS_NewDependentString(JSContext *cx, JSString *str, size_t start, size_t length)
5241 CHECK_REQUEST(cx);
5242 return js_NewDependentString(cx, str, start, length);
5245 JS_PUBLIC_API(JSString *)
5246 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
5248 CHECK_REQUEST(cx);
5249 return js_ConcatStrings(cx, left, right);
5252 JS_PUBLIC_API(const jschar *)
5253 JS_UndependString(JSContext *cx, JSString *str)
5255 CHECK_REQUEST(cx);
5256 return str->undepend(cx);
5259 JS_PUBLIC_API(JSBool)
5260 JS_MakeStringImmutable(JSContext *cx, JSString *str)
5262 CHECK_REQUEST(cx);
5263 return js_MakeStringImmutable(cx, str);
5266 JS_PUBLIC_API(JSBool)
5267 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, size_t *dstlenp)
5269 size_t n;
5271 if (!dst) {
5272 n = js_GetDeflatedStringLength(cx, src, srclen);
5273 if (n == (size_t)-1) {
5274 *dstlenp = 0;
5275 return JS_FALSE;
5277 *dstlenp = n;
5278 return JS_TRUE;
5281 return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5284 JS_PUBLIC_API(JSBool)
5285 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp)
5287 return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5290 JS_PUBLIC_API(char *)
5291 JS_EncodeString(JSContext *cx, JSString *str)
5293 return js_DeflateString(cx, str->chars(), str->length());
5296 JS_PUBLIC_API(JSBool)
5297 JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
5298 JSONWriteCallback callback, void *data)
5300 CHECK_REQUEST(cx);
5301 assertSameCompartment(cx, replacer, space);
5302 JSCharBuffer cb(cx);
5303 if (!js_Stringify(cx, Valueify(vp), replacer, Valueify(space), cb))
5304 return false;
5305 return callback(cb.begin(), cb.length(), data);
5308 JS_PUBLIC_API(JSBool)
5309 JS_TryJSON(JSContext *cx, jsval *vp)
5311 CHECK_REQUEST(cx);
5312 assertSameCompartment(cx, *vp);
5313 return js_TryJSON(cx, Valueify(vp));
5316 JS_PUBLIC_API(JSONParser *)
5317 JS_BeginJSONParse(JSContext *cx, jsval *vp)
5319 CHECK_REQUEST(cx);
5320 return js_BeginJSONParse(cx, Valueify(vp));
5323 JS_PUBLIC_API(JSBool)
5324 JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len)
5326 CHECK_REQUEST(cx);
5327 return js_ConsumeJSONText(cx, jp, data, len);
5330 JS_PUBLIC_API(JSBool)
5331 JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver)
5333 CHECK_REQUEST(cx);
5334 assertSameCompartment(cx, reviver);
5335 return js_FinishJSONParse(cx, jp, Valueify(reviver));
5338 JS_PUBLIC_API(JSBool)
5339 JS_ReadStructuredClone(JSContext *cx, const uint64 *buf, size_t nbytes, jsval *vp)
5341 return ReadStructuredClone(cx, buf, nbytes, Valueify(vp));
5344 JS_PUBLIC_API(JSBool)
5345 JS_WriteStructuredClone(JSContext *cx, jsval v, uint64 **bufp, size_t *nbytesp)
5347 return WriteStructuredClone(cx, Valueify(v), (uint64_t **) bufp, nbytesp);
5350 JS_PUBLIC_API(JSBool)
5351 JS_StructuredClone(JSContext *cx, jsval v, jsval *vp)
5353 JSAutoStructuredCloneBuffer buf(cx);
5354 return buf.write(v) && buf.read(vp);
5357 JS_PUBLIC_API(void)
5358 JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks)
5360 rt->structuredCloneCallbacks = callbacks;
5363 JS_PUBLIC_API(JSBool)
5364 JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32 *p1, uint32 *p2)
5366 return r->input().readPair((uint32_t *) p1, (uint32_t *) p2);
5369 JS_PUBLIC_API(JSBool)
5370 JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len)
5372 return r->input().readBytes(p, len);
5375 JS_PUBLIC_API(JSBool)
5376 JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32 tag, uint32 data)
5378 return w->output().writePair(tag, data);
5381 JS_PUBLIC_API(JSBool)
5382 JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len)
5384 return w->output().writeBytes(p, len);
5388 * The following determines whether C Strings are to be treated as UTF-8
5389 * or ISO-8859-1. For correct operation, it must be set prior to the
5390 * first call to JS_NewRuntime.
5392 #ifndef JS_C_STRINGS_ARE_UTF8
5393 JSBool js_CStringsAreUTF8 = JS_FALSE;
5394 #endif
5396 JS_PUBLIC_API(JSBool)
5397 JS_CStringsAreUTF8()
5399 return js_CStringsAreUTF8;
5402 JS_PUBLIC_API(void)
5403 JS_SetCStringsAreUTF8()
5405 JS_ASSERT(!js_NewRuntimeWasCalled);
5407 #ifndef JS_C_STRINGS_ARE_UTF8
5408 js_CStringsAreUTF8 = JS_TRUE;
5409 #endif
5412 /************************************************************************/
5414 JS_PUBLIC_API(void)
5415 JS_ReportError(JSContext *cx, const char *format, ...)
5417 va_list ap;
5419 va_start(ap, format);
5420 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
5421 va_end(ap);
5424 JS_PUBLIC_API(void)
5425 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
5426 void *userRef, const uintN errorNumber, ...)
5428 va_list ap;
5430 va_start(ap, errorNumber);
5431 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5432 errorNumber, JS_TRUE, ap);
5433 va_end(ap);
5436 JS_PUBLIC_API(void)
5437 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
5438 void *userRef, const uintN errorNumber, ...)
5440 va_list ap;
5442 va_start(ap, errorNumber);
5443 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5444 errorNumber, JS_FALSE, ap);
5445 va_end(ap);
5448 JS_PUBLIC_API(JSBool)
5449 JS_ReportWarning(JSContext *cx, const char *format, ...)
5451 va_list ap;
5452 JSBool ok;
5454 va_start(ap, format);
5455 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
5456 va_end(ap);
5457 return ok;
5460 JS_PUBLIC_API(JSBool)
5461 JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
5462 JSErrorCallback errorCallback, void *userRef,
5463 const uintN errorNumber, ...)
5465 va_list ap;
5466 JSBool ok;
5468 va_start(ap, errorNumber);
5469 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5470 errorNumber, JS_TRUE, ap);
5471 va_end(ap);
5472 return ok;
5475 JS_PUBLIC_API(JSBool)
5476 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
5477 JSErrorCallback errorCallback, void *userRef,
5478 const uintN errorNumber, ...)
5480 va_list ap;
5481 JSBool ok;
5483 va_start(ap, errorNumber);
5484 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5485 errorNumber, JS_FALSE, ap);
5486 va_end(ap);
5487 return ok;
5490 JS_PUBLIC_API(void)
5491 JS_ReportOutOfMemory(JSContext *cx)
5493 js_ReportOutOfMemory(cx);
5496 JS_PUBLIC_API(void)
5497 JS_ReportAllocationOverflow(JSContext *cx)
5499 js_ReportAllocationOverflow(cx);
5502 JS_PUBLIC_API(JSErrorReporter)
5503 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
5505 JSErrorReporter older;
5507 older = cx->errorReporter;
5508 cx->errorReporter = er;
5509 return older;
5512 /************************************************************************/
5515 * Regular Expressions.
5517 JS_PUBLIC_API(JSObject *)
5518 JS_NewRegExpObject(JSContext *cx, JSObject *obj, char *bytes, size_t length, uintN flags)
5520 CHECK_REQUEST(cx);
5521 jschar *chars = js_InflateString(cx, bytes, &length);
5522 if (!chars)
5523 return NULL;
5524 RegExpStatics *res = RegExpStatics::extractFrom(obj);
5525 JSObject *reobj = RegExp::createObject(cx, res, chars, length, flags);
5526 cx->free(chars);
5527 return reobj;
5530 JS_PUBLIC_API(JSObject *)
5531 JS_NewUCRegExpObject(JSContext *cx, JSObject *obj, jschar *chars, size_t length, uintN flags)
5533 CHECK_REQUEST(cx);
5534 RegExpStatics *res = RegExpStatics::extractFrom(obj);
5535 return RegExp::createObject(cx, res, chars, length, flags);
5538 JS_PUBLIC_API(void)
5539 JS_SetRegExpInput(JSContext *cx, JSObject *obj, JSString *input, JSBool multiline)
5541 CHECK_REQUEST(cx);
5542 assertSameCompartment(cx, input);
5544 RegExpStatics::extractFrom(obj)->reset(input, !!multiline);
5547 JS_PUBLIC_API(void)
5548 JS_ClearRegExpStatics(JSContext *cx, JSObject *obj)
5550 CHECK_REQUEST(cx);
5551 JS_ASSERT(obj);
5553 RegExpStatics::extractFrom(obj)->clear();
5556 JS_PUBLIC_API(JSBool)
5557 JS_ExecuteRegExp(JSContext *cx, JSObject *obj, JSObject *reobj, jschar *chars, size_t length,
5558 size_t *indexp, JSBool test, jsval *rval)
5560 CHECK_REQUEST(cx);
5562 RegExp *re = RegExp::extractFrom(reobj);
5563 if (!re)
5564 return false;
5566 JSString *str = js_NewStringCopyN(cx, chars, length);
5567 if (!str)
5568 return false;
5570 return re->execute(cx, RegExpStatics::extractFrom(obj), str, indexp, test, Valueify(rval));
5573 JS_PUBLIC_API(JSObject *)
5574 JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, uintN flags)
5576 CHECK_REQUEST(cx);
5577 jschar *chars = js_InflateString(cx, bytes, &length);
5578 if (!chars)
5579 return NULL;
5580 JSObject *obj = RegExp::createObjectNoStatics(cx, chars, length, flags);
5581 cx->free(chars);
5582 return obj;
5585 JS_PUBLIC_API(JSObject *)
5586 JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, uintN flags)
5588 CHECK_REQUEST(cx);
5589 return RegExp::createObjectNoStatics(cx, chars, length, flags);
5592 JS_PUBLIC_API(JSBool)
5593 JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *obj, jschar *chars, size_t length,
5594 size_t *indexp, JSBool test, jsval *rval)
5596 CHECK_REQUEST(cx);
5598 RegExp *re = RegExp::extractFrom(obj);
5599 if (!re)
5600 return false;
5602 JSString *str = js_NewStringCopyN(cx, chars, length);
5603 if (!str)
5604 return false;
5606 return re->executeNoStatics(cx, str, indexp, test, Valueify(rval));
5609 /************************************************************************/
5611 JS_PUBLIC_API(void)
5612 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
5614 cx->localeCallbacks = callbacks;
5617 JS_PUBLIC_API(JSLocaleCallbacks *)
5618 JS_GetLocaleCallbacks(JSContext *cx)
5620 return cx->localeCallbacks;
5623 /************************************************************************/
5625 JS_PUBLIC_API(JSBool)
5626 JS_IsExceptionPending(JSContext *cx)
5628 return (JSBool) cx->throwing;
5631 JS_PUBLIC_API(JSBool)
5632 JS_GetPendingException(JSContext *cx, jsval *vp)
5634 CHECK_REQUEST(cx);
5635 if (!cx->throwing)
5636 return JS_FALSE;
5637 Valueify(*vp) = cx->exception;
5638 return JS_TRUE;
5641 JS_PUBLIC_API(void)
5642 JS_SetPendingException(JSContext *cx, jsval v)
5644 CHECK_REQUEST(cx);
5645 assertSameCompartment(cx, v);
5646 SetPendingException(cx, Valueify(v));
5649 JS_PUBLIC_API(void)
5650 JS_ClearPendingException(JSContext *cx)
5652 cx->throwing = JS_FALSE;
5653 cx->exception.setUndefined();
5656 JS_PUBLIC_API(JSBool)
5657 JS_ReportPendingException(JSContext *cx)
5659 JSBool ok;
5660 JSPackedBool save;
5662 CHECK_REQUEST(cx);
5665 * Set cx->generatingError to suppress the standard error-to-exception
5666 * conversion done by all {js,JS}_Report* functions except for OOM. The
5667 * cx->generatingError flag was added to suppress recursive divergence
5668 * under js_ErrorToException, but it serves for our purposes here too.
5670 save = cx->generatingError;
5671 cx->generatingError = JS_TRUE;
5672 ok = js_ReportUncaughtException(cx);
5673 cx->generatingError = save;
5674 return ok;
5677 struct JSExceptionState {
5678 JSBool throwing;
5679 jsval exception;
5682 JS_PUBLIC_API(JSExceptionState *)
5683 JS_SaveExceptionState(JSContext *cx)
5685 JSExceptionState *state;
5687 CHECK_REQUEST(cx);
5688 state = (JSExceptionState *) cx->malloc(sizeof(JSExceptionState));
5689 if (state) {
5690 state->throwing = JS_GetPendingException(cx, &state->exception);
5691 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
5692 js_AddRoot(cx, Valueify(&state->exception), "JSExceptionState.exception");
5694 return state;
5697 JS_PUBLIC_API(void)
5698 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
5700 CHECK_REQUEST(cx);
5701 if (state) {
5702 if (state->throwing)
5703 JS_SetPendingException(cx, state->exception);
5704 else
5705 JS_ClearPendingException(cx);
5706 JS_DropExceptionState(cx, state);
5710 JS_PUBLIC_API(void)
5711 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
5713 CHECK_REQUEST(cx);
5714 if (state) {
5715 if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
5716 assertSameCompartment(cx, state->exception);
5717 JS_RemoveValueRoot(cx, &state->exception);
5719 cx->free(state);
5723 JS_PUBLIC_API(JSErrorReport *)
5724 JS_ErrorFromException(JSContext *cx, jsval v)
5726 CHECK_REQUEST(cx);
5727 assertSameCompartment(cx, v);
5728 return js_ErrorFromException(cx, v);
5731 JS_PUBLIC_API(JSBool)
5732 JS_ThrowReportedError(JSContext *cx, const char *message,
5733 JSErrorReport *reportp)
5735 return JS_IsRunning(cx) &&
5736 js_ErrorToException(cx, message, reportp, NULL, NULL);
5739 JS_PUBLIC_API(JSBool)
5740 JS_ThrowStopIteration(JSContext *cx)
5742 return js_ThrowStopIteration(cx);
5746 * Get the owning thread id of a context. Returns 0 if the context is not
5747 * owned by any thread.
5749 JS_PUBLIC_API(jsword)
5750 JS_GetContextThread(JSContext *cx)
5752 #ifdef JS_THREADSAFE
5753 return reinterpret_cast<jsword>(JS_THREAD_ID(cx));
5754 #else
5755 return 0;
5756 #endif
5760 * Set the current thread as the owning thread of a context. Returns the
5761 * old owning thread id, or -1 if the operation failed.
5763 JS_PUBLIC_API(jsword)
5764 JS_SetContextThread(JSContext *cx)
5766 #ifdef JS_THREADSAFE
5767 JS_ASSERT(!cx->outstandingRequests);
5768 if (cx->thread) {
5769 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
5770 return reinterpret_cast<jsword>(cx->thread->id);
5773 if (!js_InitContextThread(cx)) {
5774 js_ReportOutOfMemory(cx);
5775 return -1;
5778 /* Here the GC lock is still held after js_InitContextThread took it. */
5779 JS_UNLOCK_GC(cx->runtime);
5780 #endif
5781 return 0;
5784 JS_PUBLIC_API(jsword)
5785 JS_ClearContextThread(JSContext *cx)
5787 #ifdef JS_THREADSAFE
5789 * cx must have exited all requests it entered and, if cx is associated
5790 * with a thread, this must be called only from that thread. If not, this
5791 * is a harmless no-op.
5793 JS_ASSERT(cx->outstandingRequests == 0);
5794 JSThread *t = cx->thread;
5795 if (!t)
5796 return 0;
5797 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
5800 * We must not race with a GC that accesses cx->thread for all threads,
5801 * see bug 476934.
5803 JSRuntime *rt = cx->runtime;
5804 AutoLockGC lock(rt);
5805 js_WaitForGC(rt);
5806 js_ClearContextThread(cx);
5807 JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth);
5810 * We can access t->id as long as the GC lock is held and we cannot race
5811 * with the GC that may delete t.
5813 return reinterpret_cast<jsword>(t->id);
5814 #else
5815 return 0;
5816 #endif
5819 #ifdef MOZ_TRACE_JSCALLS
5820 JS_PUBLIC_API(void)
5821 JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb)
5823 cx->functionCallback = fcb;
5826 JS_PUBLIC_API(JSFunctionCallback)
5827 JS_GetFunctionCallback(JSContext *cx)
5829 return cx->functionCallback;
5831 #endif
5833 #ifdef JS_GC_ZEAL
5834 JS_PUBLIC_API(void)
5835 JS_SetGCZeal(JSContext *cx, uint8 zeal)
5837 cx->runtime->gcZeal = zeal;
5839 #endif
5841 /************************************************************************/
5843 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN) && !defined (WINCE)
5845 #include "jswin.h"
5848 * Initialization routine for the JS DLL.
5850 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
5852 return TRUE;
5855 #endif