Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / js / src / jsapi.cpp
blob8e81c59842ed14465666c0358ed8c9d716b03828
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 <sys/stat.h>
49 #include "jstypes.h"
50 #include "jsstdint.h"
51 #include "jsarena.h"
52 #include "jsutil.h"
53 #include "jsclist.h"
54 #include "jsdhash.h"
55 #include "jsprf.h"
56 #include "jsapi.h"
57 #include "jsarray.h"
58 #include "jsatom.h"
59 #include "jsbool.h"
60 #include "jsbuiltins.h"
61 #include "jsclone.h"
62 #include "jscntxt.h"
63 #include "jsversion.h"
64 #include "jsdate.h"
65 #include "jsemit.h"
66 #include "jsexn.h"
67 #include "jsfun.h"
68 #include "jsgc.h"
69 #include "jsinterp.h"
70 #include "jsiter.h"
71 #include "jslock.h"
72 #include "jsmath.h"
73 #include "jsnum.h"
74 #include "json.h"
75 #include "jsobj.h"
76 #include "jsopcode.h"
77 #include "jsparse.h"
78 #include "jsproxy.h"
79 #include "jsregexp.h"
80 #include "jsscan.h"
81 #include "jsscope.h"
82 #include "jsscript.h"
83 #include "jsstr.h"
84 #include "jstracer.h"
85 #include "jsdbgapi.h"
86 #include "prmjtime.h"
87 #include "jsstaticcheck.h"
88 #include "jsvector.h"
89 #include "jswrapper.h"
90 #include "jstypedarray.h"
92 #include "jsatominlines.h"
93 #include "jscntxtinlines.h"
94 #include "jsinterpinlines.h"
95 #include "jsobjinlines.h"
96 #include "jsscopeinlines.h"
97 #include "jscntxtinlines.h"
98 #include "jsregexpinlines.h"
99 #include "jsscriptinlines.h"
100 #include "jsstrinlines.h"
101 #include "assembler/wtf/Platform.h"
103 #if ENABLE_YARR_JIT
104 #include "assembler/jit/ExecutableAllocator.h"
105 #include "methodjit/Logging.h"
106 #endif
108 #if JS_HAS_XML_SUPPORT
109 #include "jsxml.h"
110 #endif
112 using namespace js;
113 using namespace js::gc;
115 static JSClass dummy_class = {
116 "jdummy",
117 JSCLASS_GLOBAL_FLAGS,
118 JS_PropertyStub, JS_PropertyStub,
119 JS_PropertyStub, JS_StrictPropertyStub,
120 JS_EnumerateStub, JS_ResolveStub,
121 JS_ConvertStub, NULL,
122 JSCLASS_NO_OPTIONAL_MEMBERS
126 * This class is a version-establising barrier at the head of a VM entry or
127 * re-entry. It ensures that:
129 * - |newVersion| is the starting (default) version used for the context.
130 * - The starting version state is not an override.
131 * - Overrides in the VM session are not propagated to the caller.
133 class AutoVersionAPI
135 JSContext * const cx;
136 JSVersion oldDefaultVersion;
137 bool oldHasVersionOverride;
138 JSVersion oldVersionOverride;
139 #ifdef DEBUG
140 uintN oldCompileOptions;
141 #endif
142 JSVersion newVersion;
144 public:
145 explicit AutoVersionAPI(JSContext *cx, JSVersion newVersion)
146 : cx(cx),
147 oldDefaultVersion(cx->getDefaultVersion()),
148 oldHasVersionOverride(cx->isVersionOverridden()),
149 oldVersionOverride(oldHasVersionOverride ? cx->findVersion() : JSVERSION_UNKNOWN)
150 #ifdef DEBUG
151 , oldCompileOptions(cx->getCompileOptions())
152 #endif
155 * Note: ANONFUNFIX in newVersion is ignored for backwards
156 * compatibility, must be set via JS_SetOptions. (Because of this, we
157 * inherit the current ANONFUNFIX setting from the options.
159 VersionSetAnonFunFix(&newVersion, OptionsHasAnonFunFix(cx->getCompileOptions()));
160 this->newVersion = newVersion;
161 cx->clearVersionOverride();
162 cx->setDefaultVersion(newVersion);
165 ~AutoVersionAPI() {
166 cx->setDefaultVersion(oldDefaultVersion);
167 if (oldHasVersionOverride)
168 cx->overrideVersion(oldVersionOverride);
169 else
170 cx->clearVersionOverride();
171 JS_ASSERT(oldCompileOptions == cx->getCompileOptions());
174 /* The version that this scoped-entity establishes. */
175 JSVersion version() const { return newVersion; }
178 #ifdef HAVE_VA_LIST_AS_ARRAY
179 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
180 #else
181 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
182 #endif
184 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
185 JS_PUBLIC_DATA(jsid) JS_DEFAULT_XML_NAMESPACE_ID = { size_t(JSID_TYPE_DEFAULT_XML_NAMESPACE) };
186 JS_PUBLIC_DATA(jsid) JSID_VOID = { size_t(JSID_TYPE_VOID) };
187 JS_PUBLIC_DATA(jsid) JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) };
188 #endif
190 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
191 JS_PUBLIC_DATA(jsval) JSVAL_NULL = { BUILD_JSVAL(JSVAL_TAG_NULL, 0) };
192 JS_PUBLIC_DATA(jsval) JSVAL_ZERO = { BUILD_JSVAL(JSVAL_TAG_INT32, 0) };
193 JS_PUBLIC_DATA(jsval) JSVAL_ONE = { BUILD_JSVAL(JSVAL_TAG_INT32, 1) };
194 JS_PUBLIC_DATA(jsval) JSVAL_FALSE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_FALSE) };
195 JS_PUBLIC_DATA(jsval) JSVAL_TRUE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_TRUE) };
196 JS_PUBLIC_DATA(jsval) JSVAL_VOID = { BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0) };
197 #endif
199 /* Make sure that jschar is two bytes unsigned integer */
200 JS_STATIC_ASSERT((jschar)-1 > 0);
201 JS_STATIC_ASSERT(sizeof(jschar) == 2);
203 JS_PUBLIC_API(int64)
204 JS_Now()
206 return PRMJ_Now();
209 JS_PUBLIC_API(jsval)
210 JS_GetNaNValue(JSContext *cx)
212 return Jsvalify(cx->runtime->NaNValue);
215 JS_PUBLIC_API(jsval)
216 JS_GetNegativeInfinityValue(JSContext *cx)
218 return Jsvalify(cx->runtime->negativeInfinityValue);
221 JS_PUBLIC_API(jsval)
222 JS_GetPositiveInfinityValue(JSContext *cx)
224 return Jsvalify(cx->runtime->positiveInfinityValue);
227 JS_PUBLIC_API(jsval)
228 JS_GetEmptyStringValue(JSContext *cx)
230 return STRING_TO_JSVAL(cx->runtime->emptyString);
233 JS_PUBLIC_API(JSString *)
234 JS_GetEmptyString(JSRuntime *rt)
236 JS_ASSERT(rt->state == JSRTS_UP);
237 return rt->emptyString;
240 static JSBool
241 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, jsval **vpp, va_list *app)
243 const char *format;
244 JSArgumentFormatMap *map;
246 format = *formatp;
247 for (map = cx->argumentFormatMap; map; map = map->next) {
248 if (!strncmp(format, map->format, map->length)) {
249 *formatp = format + map->length;
250 return map->formatter(cx, format, fromJS, vpp, app);
253 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
254 return JS_FALSE;
257 JS_PUBLIC_API(JSBool)
258 JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format, ...)
260 va_list ap;
261 JSBool ok;
263 va_start(ap, format);
264 ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
265 va_end(ap);
266 return ok;
269 JS_PUBLIC_API(JSBool)
270 JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format, va_list ap)
272 jsval *sp;
273 JSBool required;
274 char c;
275 JSFunction *fun;
276 jsdouble d;
277 JSString *str;
278 JSObject *obj;
280 CHECK_REQUEST(cx);
281 assertSameCompartment(cx, JSValueArray(argv - 2, argc + 2));
282 sp = argv;
283 required = JS_TRUE;
284 while ((c = *format++) != '\0') {
285 if (isspace(c))
286 continue;
287 if (c == '/') {
288 required = JS_FALSE;
289 continue;
291 if (sp == argv + argc) {
292 if (required) {
293 fun = js_ValueToFunction(cx, Valueify(&argv[-2]), 0);
294 if (fun) {
295 char numBuf[12];
296 JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
297 JSAutoByteString funNameBytes;
298 if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
299 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
300 name, numBuf, (argc == 1) ? "" : "s");
303 return JS_FALSE;
305 break;
307 switch (c) {
308 case 'b':
309 *va_arg(ap, JSBool *) = js_ValueToBoolean(Valueify(*sp));
310 break;
311 case 'c':
312 if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
313 return JS_FALSE;
314 break;
315 case 'i':
316 if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
317 return JS_FALSE;
318 break;
319 case 'u':
320 if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
321 return JS_FALSE;
322 break;
323 case 'j':
324 if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
325 return JS_FALSE;
326 break;
327 case 'd':
328 if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
329 return JS_FALSE;
330 break;
331 case 'I':
332 if (!JS_ValueToNumber(cx, *sp, &d))
333 return JS_FALSE;
334 *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
335 break;
336 case 'S':
337 case 'W':
338 str = js_ValueToString(cx, Valueify(*sp));
339 if (!str)
340 return JS_FALSE;
341 *sp = STRING_TO_JSVAL(str);
342 if (c == 'W') {
343 const jschar *chars = js_GetStringChars(cx, str);
344 if (!chars)
345 return JS_FALSE;
346 *va_arg(ap, const jschar **) = chars;
347 } else {
348 *va_arg(ap, JSString **) = str;
350 break;
351 case 'o':
352 if (!js_ValueToObjectOrNull(cx, Valueify(*sp), &obj))
353 return JS_FALSE;
354 *sp = OBJECT_TO_JSVAL(obj);
355 *va_arg(ap, JSObject **) = obj;
356 break;
357 case 'f':
358 obj = js_ValueToFunctionObject(cx, Valueify(sp), 0);
359 if (!obj)
360 return JS_FALSE;
361 *sp = OBJECT_TO_JSVAL(obj);
362 *va_arg(ap, JSFunction **) = GET_FUNCTION_PRIVATE(cx, obj);
363 break;
364 case 'v':
365 *va_arg(ap, jsval *) = *sp;
366 break;
367 case '*':
368 break;
369 default:
370 format--;
371 if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
372 JS_ADDRESSOF_VA_LIST(ap))) {
373 return JS_FALSE;
375 /* NB: the formatter already updated sp, so we continue here. */
376 continue;
378 sp++;
380 return JS_TRUE;
383 JS_PUBLIC_API(JSBool)
384 JS_AddArgumentFormatter(JSContext *cx, const char *format, JSArgumentFormatter formatter)
386 size_t length;
387 JSArgumentFormatMap **mpp, *map;
389 length = strlen(format);
390 mpp = &cx->argumentFormatMap;
391 while ((map = *mpp) != NULL) {
392 /* Insert before any shorter string to match before prefixes. */
393 if (map->length < length)
394 break;
395 if (map->length == length && !strcmp(map->format, format))
396 goto out;
397 mpp = &map->next;
399 map = (JSArgumentFormatMap *) cx->malloc(sizeof *map);
400 if (!map)
401 return JS_FALSE;
402 map->format = format;
403 map->length = length;
404 map->next = *mpp;
405 *mpp = map;
406 out:
407 map->formatter = formatter;
408 return JS_TRUE;
411 JS_PUBLIC_API(void)
412 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
414 size_t length;
415 JSArgumentFormatMap **mpp, *map;
417 length = strlen(format);
418 mpp = &cx->argumentFormatMap;
419 while ((map = *mpp) != NULL) {
420 if (map->length == length && !strcmp(map->format, format)) {
421 *mpp = map->next;
422 cx->free(map);
423 return;
425 mpp = &map->next;
429 JS_PUBLIC_API(JSBool)
430 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
432 JSBool ok;
433 JSObject *obj;
434 JSString *str;
435 jsdouble d;
437 CHECK_REQUEST(cx);
438 assertSameCompartment(cx, v);
439 switch (type) {
440 case JSTYPE_VOID:
441 *vp = JSVAL_VOID;
442 ok = JS_TRUE;
443 break;
444 case JSTYPE_OBJECT:
445 ok = js_ValueToObjectOrNull(cx, Valueify(v), &obj);
446 if (ok)
447 *vp = OBJECT_TO_JSVAL(obj);
448 break;
449 case JSTYPE_FUNCTION:
450 *vp = v;
451 obj = js_ValueToFunctionObject(cx, Valueify(vp), JSV2F_SEARCH_STACK);
452 ok = (obj != NULL);
453 break;
454 case JSTYPE_STRING:
455 str = js_ValueToString(cx, Valueify(v));
456 ok = (str != NULL);
457 if (ok)
458 *vp = STRING_TO_JSVAL(str);
459 break;
460 case JSTYPE_NUMBER:
461 ok = JS_ValueToNumber(cx, v, &d);
462 if (ok)
463 *vp = DOUBLE_TO_JSVAL(d);
464 break;
465 case JSTYPE_BOOLEAN:
466 *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(Valueify(v)));
467 return JS_TRUE;
468 default: {
469 char numBuf[12];
470 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
471 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE, numBuf);
472 ok = JS_FALSE;
473 break;
476 return ok;
479 JS_PUBLIC_API(JSBool)
480 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
482 CHECK_REQUEST(cx);
483 assertSameCompartment(cx, v);
484 return js_ValueToObjectOrNull(cx, Valueify(v), objp);
487 JS_PUBLIC_API(JSFunction *)
488 JS_ValueToFunction(JSContext *cx, jsval v)
490 CHECK_REQUEST(cx);
491 assertSameCompartment(cx, v);
492 return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
495 JS_PUBLIC_API(JSFunction *)
496 JS_ValueToConstructor(JSContext *cx, jsval v)
498 CHECK_REQUEST(cx);
499 assertSameCompartment(cx, v);
500 return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
503 JS_PUBLIC_API(JSString *)
504 JS_ValueToString(JSContext *cx, jsval v)
506 CHECK_REQUEST(cx);
507 assertSameCompartment(cx, v);
508 return js_ValueToString(cx, Valueify(v));
511 JS_PUBLIC_API(JSString *)
512 JS_ValueToSource(JSContext *cx, jsval v)
514 CHECK_REQUEST(cx);
515 assertSameCompartment(cx, v);
516 return js_ValueToSource(cx, Valueify(v));
519 JS_PUBLIC_API(JSBool)
520 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
522 CHECK_REQUEST(cx);
523 assertSameCompartment(cx, v);
525 AutoValueRooter tvr(cx, Valueify(v));
526 return ValueToNumber(cx, tvr.value(), dp);
529 JS_PUBLIC_API(JSBool)
530 JS_DoubleIsInt32(jsdouble d, jsint *ip)
532 return JSDOUBLE_IS_INT32(d, (int32_t *)ip);
535 JS_PUBLIC_API(JSBool)
536 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
538 CHECK_REQUEST(cx);
539 assertSameCompartment(cx, v);
541 AutoValueRooter tvr(cx, Valueify(v));
542 return ValueToECMAInt32(cx, tvr.value(), (int32_t *)ip);
545 JS_PUBLIC_API(JSBool)
546 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
548 CHECK_REQUEST(cx);
549 assertSameCompartment(cx, v);
551 AutoValueRooter tvr(cx, Valueify(v));
552 return ValueToECMAUint32(cx, tvr.value(), (uint32_t *)ip);
555 JS_PUBLIC_API(JSBool)
556 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
558 CHECK_REQUEST(cx);
559 assertSameCompartment(cx, v);
561 AutoValueRooter tvr(cx, Valueify(v));
562 return ValueToInt32(cx, tvr.value(), (int32_t *)ip);
565 JS_PUBLIC_API(JSBool)
566 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
568 CHECK_REQUEST(cx);
569 assertSameCompartment(cx, v);
571 AutoValueRooter tvr(cx, Valueify(v));
572 return ValueToUint16(cx, tvr.value(), (uint16_t *)ip);
575 JS_PUBLIC_API(JSBool)
576 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
578 CHECK_REQUEST(cx);
579 assertSameCompartment(cx, v);
580 *bp = js_ValueToBoolean(Valueify(v));
581 return JS_TRUE;
584 JS_PUBLIC_API(JSType)
585 JS_TypeOfValue(JSContext *cx, jsval v)
587 CHECK_REQUEST(cx);
588 assertSameCompartment(cx, v);
589 return TypeOfValue(cx, Valueify(v));
592 JS_PUBLIC_API(const char *)
593 JS_GetTypeName(JSContext *cx, JSType type)
595 if ((uintN)type >= (uintN)JSTYPE_LIMIT)
596 return NULL;
597 return JS_TYPE_STR(type);
600 JS_PUBLIC_API(JSBool)
601 JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
603 assertSameCompartment(cx, v1, v2);
604 return StrictlyEqual(cx, Valueify(v1), Valueify(v2), equal);
607 JS_PUBLIC_API(JSBool)
608 JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same)
610 assertSameCompartment(cx, v1, v2);
611 return SameValue(cx, Valueify(v1), Valueify(v2), same);
614 /************************************************************************/
617 * Has a new runtime ever been created? This flag is used to detect unsafe
618 * changes to js_CStringsAreUTF8 after a runtime has been created, and to
619 * ensure that "first checks" on runtime creation are run only once.
621 #ifdef DEBUG
622 static JSBool js_NewRuntimeWasCalled = JS_FALSE;
623 #endif
625 JSRuntime::JSRuntime()
626 : gcChunkAllocator(&defaultGCChunkAllocator)
628 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
629 JS_INIT_CLIST(&contextList);
630 JS_INIT_CLIST(&trapList);
631 JS_INIT_CLIST(&watchPointList);
634 bool
635 JSRuntime::init(uint32 maxbytes)
637 #ifdef JS_METHODJIT_SPEW
638 JMCheckLogging();
639 #endif
641 #ifdef DEBUG
642 functionMeterFilename = getenv("JS_FUNCTION_STATFILE");
643 if (functionMeterFilename) {
644 if (!methodReadBarrierCountMap.init())
645 return false;
646 if (!unjoinedFunctionCountMap.init())
647 return false;
649 propTreeStatFilename = getenv("JS_PROPTREE_STATFILE");
650 propTreeDumpFilename = getenv("JS_PROPTREE_DUMPFILE");
651 #endif
653 if (!(atomsCompartment = js_new<JSCompartment>(this)) ||
654 !atomsCompartment->init() ||
655 !compartments.append(atomsCompartment)) {
656 return false;
659 if (!js_InitGC(this, maxbytes) || !js_InitAtomState(this))
660 return false;
662 wrapObjectCallback = js::TransparentObjectWrapper;
664 #ifdef JS_THREADSAFE
665 /* this is asymmetric with JS_ShutDown: */
666 if (!js_SetupLocks(8, 16))
667 return false;
668 rtLock = JS_NEW_LOCK();
669 if (!rtLock)
670 return false;
671 stateChange = JS_NEW_CONDVAR(gcLock);
672 if (!stateChange)
673 return false;
674 debuggerLock = JS_NEW_LOCK();
675 if (!debuggerLock)
676 return false;
677 #endif
679 debugMode = JS_FALSE;
681 return js_InitThreads(this);
684 JSRuntime::~JSRuntime()
686 #ifdef DEBUG
687 /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
688 if (!JS_CLIST_IS_EMPTY(&contextList)) {
689 JSContext *cx, *iter = NULL;
690 uintN cxcount = 0;
691 while ((cx = js_ContextIterator(this, JS_TRUE, &iter)) != NULL) {
692 fprintf(stderr,
693 "JS API usage error: found live context at %p\n",
694 (void *) cx);
695 cxcount++;
697 fprintf(stderr,
698 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
699 cxcount, (cxcount == 1) ? "" : "s");
701 #endif
703 js_FinishThreads(this);
704 js_FreeRuntimeScriptState(this);
705 js_FinishAtomState(this);
707 js_FinishGC(this);
708 #ifdef JS_THREADSAFE
709 if (gcLock)
710 JS_DESTROY_LOCK(gcLock);
711 if (gcDone)
712 JS_DESTROY_CONDVAR(gcDone);
713 if (requestDone)
714 JS_DESTROY_CONDVAR(requestDone);
715 if (rtLock)
716 JS_DESTROY_LOCK(rtLock);
717 if (stateChange)
718 JS_DESTROY_CONDVAR(stateChange);
719 if (debuggerLock)
720 JS_DESTROY_LOCK(debuggerLock);
721 #endif
724 JS_PUBLIC_API(JSRuntime *)
725 JS_NewRuntime(uint32 maxbytes)
727 #ifdef DEBUG
728 if (!js_NewRuntimeWasCalled) {
730 * This code asserts that the numbers associated with the error names
731 * in jsmsg.def are monotonically increasing. It uses values for the
732 * error names enumerated in jscntxt.c. It's not a compile-time check
733 * but it's better than nothing.
735 int errorNumber = 0;
736 #define MSG_DEF(name, number, count, exception, format) \
737 JS_ASSERT(name == errorNumber++);
738 #include "js.msg"
739 #undef MSG_DEF
741 #define MSG_DEF(name, number, count, exception, format) \
742 JS_BEGIN_MACRO \
743 uintN numfmtspecs = 0; \
744 const char *fmt; \
745 for (fmt = format; *fmt != '\0'; fmt++) { \
746 if (*fmt == '{' && isdigit(fmt[1])) \
747 ++numfmtspecs; \
749 JS_ASSERT(count == numfmtspecs); \
750 JS_END_MACRO;
751 #include "js.msg"
752 #undef MSG_DEF
754 js_NewRuntimeWasCalled = JS_TRUE;
756 #endif /* DEBUG */
758 void *mem = js_calloc(sizeof(JSRuntime));
759 if (!mem)
760 return NULL;
762 JSRuntime *rt = new (mem) JSRuntime();
763 if (!rt->init(maxbytes)) {
764 JS_DestroyRuntime(rt);
765 return NULL;
768 return rt;
771 JS_PUBLIC_API(void)
772 JS_DestroyRuntime(JSRuntime *rt)
774 rt->~JSRuntime();
776 js_free(rt);
779 #ifdef JS_REPRMETER
780 namespace reprmeter {
781 extern void js_DumpReprMeter();
783 #endif
785 JS_PUBLIC_API(void)
786 JS_ShutDown(void)
788 #ifdef MOZ_TRACEVIS
789 StopTraceVis();
790 #endif
792 #ifdef JS_OPMETER
793 extern void js_DumpOpMeters();
794 js_DumpOpMeters();
795 #endif
797 #ifdef JS_REPRMETER
798 reprmeter::js_DumpReprMeter();
799 #endif
801 #ifdef JS_THREADSAFE
802 js_CleanupLocks();
803 #endif
804 PRMJ_NowShutdown();
807 JS_PUBLIC_API(void *)
808 JS_GetRuntimePrivate(JSRuntime *rt)
810 return rt->data;
813 JS_PUBLIC_API(void)
814 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
816 rt->data = data;
819 #ifdef JS_THREADSAFE
820 static void
821 StartRequest(JSContext *cx)
823 JSThread *t = cx->thread;
824 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
826 if (t->data.requestDepth) {
827 t->data.requestDepth++;
828 } else {
829 JSRuntime *rt = cx->runtime;
830 AutoLockGC lock(rt);
832 /* Wait until the GC is finished. */
833 if (rt->gcThread != cx->thread) {
834 while (rt->gcThread)
835 JS_AWAIT_GC_DONE(rt);
838 /* Indicate that a request is running. */
839 rt->requestCount++;
840 t->data.requestDepth = 1;
843 * Adjust rt->interruptCounter to reflect any interrupts added while the
844 * thread was suspended.
846 if (t->data.interruptFlags)
847 JS_ATOMIC_INCREMENT(&rt->interruptCounter);
849 if (rt->requestCount == 1 && rt->activityCallback)
850 rt->activityCallback(rt->activityCallbackArg, true);
854 static void
855 StopRequest(JSContext *cx)
857 JSThread *t = cx->thread;
858 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
859 JS_ASSERT(t->data.requestDepth != 0);
860 if (t->data.requestDepth != 1) {
861 t->data.requestDepth--;
862 } else {
863 LeaveTrace(cx); /* for GC safety */
865 t->data.conservativeGC.updateForRequestEnd(t->suspendCount);
867 /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
868 JSRuntime *rt = cx->runtime;
869 AutoLockGC lock(rt);
871 t->data.requestDepth = 0;
874 * Adjust rt->interruptCounter to reflect any interrupts added while the
875 * thread still had active requests.
877 if (t->data.interruptFlags)
878 JS_ATOMIC_DECREMENT(&rt->interruptCounter);
880 /* Give the GC a chance to run if this was the last request running. */
881 JS_ASSERT(rt->requestCount > 0);
882 rt->requestCount--;
883 if (rt->requestCount == 0) {
884 JS_NOTIFY_REQUEST_DONE(rt);
885 if (rt->activityCallback)
886 rt->activityCallback(rt->activityCallbackArg, false);
890 #endif /* JS_THREADSAFE */
892 JS_PUBLIC_API(void)
893 JS_BeginRequest(JSContext *cx)
895 #ifdef JS_THREADSAFE
896 cx->outstandingRequests++;
897 StartRequest(cx);
898 #endif
901 JS_PUBLIC_API(void)
902 JS_EndRequest(JSContext *cx)
904 #ifdef JS_THREADSAFE
905 JS_ASSERT(cx->outstandingRequests != 0);
906 cx->outstandingRequests--;
907 StopRequest(cx);
908 #endif
911 /* Yield to pending GC operations, regardless of request depth */
912 JS_PUBLIC_API(void)
913 JS_YieldRequest(JSContext *cx)
915 #ifdef JS_THREADSAFE
916 CHECK_REQUEST(cx);
917 JS_ResumeRequest(cx, JS_SuspendRequest(cx));
918 #endif
921 JS_PUBLIC_API(jsrefcount)
922 JS_SuspendRequest(JSContext *cx)
924 #ifdef JS_THREADSAFE
925 JSThread *t = cx->thread;
926 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
928 jsrefcount saveDepth = t->data.requestDepth;
929 if (!saveDepth)
930 return 0;
932 t->suspendCount++;
933 t->data.requestDepth = 1;
934 StopRequest(cx);
935 return saveDepth;
936 #else
937 return 0;
938 #endif
941 JS_PUBLIC_API(void)
942 JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
944 #ifdef JS_THREADSAFE
945 JSThread *t = cx->thread;
946 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
947 if (saveDepth == 0)
948 return;
949 JS_ASSERT(saveDepth >= 1);
950 JS_ASSERT(!t->data.requestDepth);
951 JS_ASSERT(t->suspendCount);
952 StartRequest(cx);
953 t->data.requestDepth = saveDepth;
954 t->suspendCount--;
955 #endif
958 JS_PUBLIC_API(JSBool)
959 JS_IsInRequest(JSContext *cx)
961 #ifdef JS_THREADSAFE
962 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
963 return JS_THREAD_DATA(cx)->requestDepth != 0;
964 #else
965 return false;
966 #endif
969 JS_PUBLIC_API(void)
970 JS_Lock(JSRuntime *rt)
972 JS_LOCK_RUNTIME(rt);
975 JS_PUBLIC_API(void)
976 JS_Unlock(JSRuntime *rt)
978 JS_UNLOCK_RUNTIME(rt);
981 JS_PUBLIC_API(JSContextCallback)
982 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
984 JSContextCallback old;
986 old = rt->cxCallback;
987 rt->cxCallback = cxCallback;
988 return old;
991 JS_PUBLIC_API(JSContext *)
992 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
994 return js_NewContext(rt, stackChunkSize);
997 JS_PUBLIC_API(void)
998 JS_DestroyContext(JSContext *cx)
1000 js_DestroyContext(cx, JSDCM_FORCE_GC);
1003 JS_PUBLIC_API(void)
1004 JS_DestroyContextNoGC(JSContext *cx)
1006 js_DestroyContext(cx, JSDCM_NO_GC);
1009 JS_PUBLIC_API(void)
1010 JS_DestroyContextMaybeGC(JSContext *cx)
1012 js_DestroyContext(cx, JSDCM_MAYBE_GC);
1015 JS_PUBLIC_API(void *)
1016 JS_GetContextPrivate(JSContext *cx)
1018 return cx->data;
1021 JS_PUBLIC_API(void)
1022 JS_SetContextPrivate(JSContext *cx, void *data)
1024 cx->data = data;
1027 JS_PUBLIC_API(JSRuntime *)
1028 JS_GetRuntime(JSContext *cx)
1030 return cx->runtime;
1033 JS_PUBLIC_API(JSContext *)
1034 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
1036 return js_ContextIterator(rt, JS_TRUE, iterp);
1039 JS_PUBLIC_API(JSVersion)
1040 JS_GetVersion(JSContext *cx)
1042 return VersionNumber(cx->findVersion());
1045 JS_PUBLIC_API(JSVersion)
1046 JS_SetVersion(JSContext *cx, JSVersion newVersion)
1048 JS_ASSERT(VersionIsKnown(newVersion));
1049 JS_ASSERT(!VersionHasFlags(newVersion));
1050 JSVersion newVersionNumber = newVersion;
1052 #ifdef DEBUG
1053 uintN coptsBefore = cx->getCompileOptions();
1054 #endif
1055 JSVersion oldVersion = cx->findVersion();
1056 JSVersion oldVersionNumber = VersionNumber(oldVersion);
1057 if (oldVersionNumber == newVersionNumber)
1058 return oldVersionNumber; /* No override actually occurs! */
1060 /* We no longer support 1.4 or below. */
1061 if (newVersionNumber != JSVERSION_DEFAULT && newVersionNumber <= JSVERSION_1_4)
1062 return oldVersionNumber;
1064 VersionCopyFlags(&newVersion, oldVersion);
1065 cx->maybeOverrideVersion(newVersion);
1066 JS_ASSERT(cx->getCompileOptions() == coptsBefore);
1067 return oldVersionNumber;
1070 static struct v2smap {
1071 JSVersion version;
1072 const char *string;
1073 } v2smap[] = {
1074 {JSVERSION_1_0, "1.0"},
1075 {JSVERSION_1_1, "1.1"},
1076 {JSVERSION_1_2, "1.2"},
1077 {JSVERSION_1_3, "1.3"},
1078 {JSVERSION_1_4, "1.4"},
1079 {JSVERSION_ECMA_3, "ECMAv3"},
1080 {JSVERSION_1_5, "1.5"},
1081 {JSVERSION_1_6, "1.6"},
1082 {JSVERSION_1_7, "1.7"},
1083 {JSVERSION_1_8, "1.8"},
1084 {JSVERSION_ECMA_5, "ECMAv5"},
1085 {JSVERSION_DEFAULT, js_default_str},
1086 {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
1089 JS_PUBLIC_API(const char *)
1090 JS_VersionToString(JSVersion version)
1092 int i;
1094 for (i = 0; v2smap[i].string; i++)
1095 if (v2smap[i].version == version)
1096 return v2smap[i].string;
1097 return "unknown";
1100 JS_PUBLIC_API(JSVersion)
1101 JS_StringToVersion(const char *string)
1103 int i;
1105 for (i = 0; v2smap[i].string; i++)
1106 if (strcmp(v2smap[i].string, string) == 0)
1107 return v2smap[i].version;
1108 return JSVERSION_UNKNOWN;
1111 JS_PUBLIC_API(uint32)
1112 JS_GetOptions(JSContext *cx)
1115 * Can't check option/version synchronization here.
1116 * We may have been synchronized with a script version that was formerly on
1117 * the stack, but has now been popped.
1119 return cx->allOptions();
1122 static uintN
1123 SetOptionsCommon(JSContext *cx, uintN options)
1125 JS_ASSERT((options & JSALLOPTION_MASK) == options);
1126 uintN oldopts = cx->allOptions();
1127 uintN newropts = options & JSRUNOPTION_MASK;
1128 uintN newcopts = options & JSCOMPILEOPTION_MASK;
1129 cx->setRunOptions(newropts);
1130 cx->setCompileOptions(newcopts);
1131 cx->updateJITEnabled();
1132 return oldopts;
1135 JS_PUBLIC_API(uint32)
1136 JS_SetOptions(JSContext *cx, uint32 options)
1138 AutoLockGC lock(cx->runtime);
1139 return SetOptionsCommon(cx, options);
1142 JS_PUBLIC_API(uint32)
1143 JS_ToggleOptions(JSContext *cx, uint32 options)
1145 AutoLockGC lock(cx->runtime);
1146 uintN oldopts = cx->allOptions();
1147 uintN newopts = oldopts ^ options;
1148 return SetOptionsCommon(cx, newopts);
1151 JS_PUBLIC_API(const char *)
1152 JS_GetImplementationVersion(void)
1154 return "JavaScript-C 1.8.0 pre-release 1 2007-10-03";
1157 JS_PUBLIC_API(JSCompartmentCallback)
1158 JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback)
1160 JSCompartmentCallback old = rt->compartmentCallback;
1161 rt->compartmentCallback = callback;
1162 return old;
1165 JS_PUBLIC_API(JSWrapObjectCallback)
1166 JS_SetWrapObjectCallbacks(JSRuntime *rt,
1167 JSWrapObjectCallback callback,
1168 JSPreWrapCallback precallback)
1170 JSWrapObjectCallback old = rt->wrapObjectCallback;
1171 rt->wrapObjectCallback = callback;
1172 rt->preWrapObjectCallback = precallback;
1173 return old;
1176 JS_PUBLIC_API(JSCrossCompartmentCall *)
1177 JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
1179 CHECK_REQUEST(cx);
1181 JS_ASSERT(target);
1182 AutoCompartment *call = js_new<AutoCompartment>(cx, target);
1183 if (!call)
1184 return NULL;
1185 if (!call->enter()) {
1186 js_delete(call);
1187 return NULL;
1189 return reinterpret_cast<JSCrossCompartmentCall *>(call);
1192 JS_PUBLIC_API(JSCrossCompartmentCall *)
1193 JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
1195 CHECK_REQUEST(cx);
1197 JS_ASSERT(target);
1198 JSObject *scriptObject = target->u.object;
1199 if (!scriptObject) {
1200 SwitchToCompartment sc(cx, target->compartment);
1201 scriptObject = JS_NewGlobalObject(cx, &dummy_class);
1202 if (!scriptObject)
1203 return NULL;
1205 return JS_EnterCrossCompartmentCall(cx, scriptObject);
1208 JS_PUBLIC_API(void)
1209 JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
1211 AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
1212 CHECK_REQUEST(realcall->context);
1213 realcall->leave();
1214 js_delete(realcall);
1217 bool
1218 JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target)
1220 JS_ASSERT(!call);
1221 if (cx->compartment == target->getCompartment()) {
1222 call = reinterpret_cast<JSCrossCompartmentCall*>(1);
1223 return true;
1225 call = JS_EnterCrossCompartmentCall(cx, target);
1226 return call != NULL;
1229 bool
1230 JSAutoEnterCompartment::enter(JSContext *cx, JSScript *target)
1232 JS_ASSERT(!call);
1233 if (cx->compartment == target->compartment) {
1234 call = reinterpret_cast<JSCrossCompartmentCall*>(1);
1235 return true;
1237 call = JS_EnterCrossCompartmentCallScript(cx, target);
1238 return call != NULL;
1241 void
1242 JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target)
1244 (void) enter(cx, target);
1247 JS_PUBLIC_API(void *)
1248 JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data)
1250 CHECK_REQUEST(cx);
1251 void *old = compartment->data;
1252 compartment->data = data;
1253 return old;
1256 JS_PUBLIC_API(void *)
1257 JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment)
1259 CHECK_REQUEST(cx);
1260 return compartment->data;
1263 JS_PUBLIC_API(JSBool)
1264 JS_WrapObject(JSContext *cx, JSObject **objp)
1266 CHECK_REQUEST(cx);
1267 return cx->compartment->wrap(cx, objp);
1270 JS_PUBLIC_API(JSBool)
1271 JS_WrapValue(JSContext *cx, jsval *vp)
1273 CHECK_REQUEST(cx);
1274 return cx->compartment->wrap(cx, Valueify(vp));
1277 JS_PUBLIC_API(JSObject *)
1278 JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target)
1280 // This function is called when an object moves between two
1281 // different compartments. In that case, we need to "move" the
1282 // window from origobj's compartment to target's compartment.
1283 JSCompartment *destination = target->getCompartment();
1284 WrapperMap &map = destination->crossCompartmentWrappers;
1285 Value origv = ObjectValue(*origobj);
1286 JSObject *obj;
1288 if (origobj->getCompartment() == destination) {
1289 // If the original object is in the same compartment as the
1290 // destination, then we know that we won't find wrapper in the
1291 // destination's cross compartment map and that the same
1292 // object will continue to work. Note the rare case where
1293 // |origobj == target|. In that case, we can just treat this
1294 // as a same compartment navigation. The effect is to clear
1295 // all of the wrappers and their holders if they have
1296 // them. This would be cleaner as a separate API.
1297 if (origobj != target && !origobj->swap(cx, target))
1298 return NULL;
1299 obj = origobj;
1300 } else if (WrapperMap::Ptr p = map.lookup(origv)) {
1301 // There might already be a wrapper for the original object in
1302 // the new compartment. If there is, make it the primary outer
1303 // window proxy around the inner (accomplished by swapping
1304 // target's innards with the old, possibly security wrapper,
1305 // innards).
1306 obj = &p->value.toObject();
1307 map.remove(p);
1308 if (!obj->swap(cx, target))
1309 return NULL;
1310 } else {
1311 // Otherwise, this is going to be our outer window proxy in
1312 // the new compartment.
1313 obj = target;
1316 // Now, iterate through other scopes looking for references to the
1317 // old outer window. They need to be updated to point at the new
1318 // outer window. They also might transition between different
1319 // types of security wrappers based on whether the new compartment
1320 // is same origin with them.
1321 Value targetv = ObjectValue(*obj);
1322 WrapperVector &vector = cx->runtime->compartments;
1323 AutoValueVector toTransplant(cx);
1324 toTransplant.reserve(vector.length());
1326 for (JSCompartment **p = vector.begin(), **end = vector.end(); p != end; ++p) {
1327 WrapperMap &pmap = (*p)->crossCompartmentWrappers;
1328 if (WrapperMap::Ptr wp = pmap.lookup(origv)) {
1329 // We found a wrapper. Remember and root it.
1330 toTransplant.append(wp->value);
1334 for (Value *begin = toTransplant.begin(), *end = toTransplant.end(); begin != end; ++begin) {
1335 JSObject *wobj = &begin->toObject();
1336 JSCompartment *wcompartment = wobj->compartment();
1337 WrapperMap &pmap = wcompartment->crossCompartmentWrappers;
1338 JS_ASSERT(pmap.lookup(origv));
1339 pmap.remove(origv);
1341 // First, we wrap it in the new compartment. This will return
1342 // a new wrapper.
1343 AutoCompartment ac(cx, wobj);
1344 JSObject *tobj = obj;
1345 if (!ac.enter() || !wcompartment->wrap(cx, &tobj))
1346 return NULL;
1348 // Now, because we need to maintain object identity, we do a
1349 // brain transplant on the old object. At the same time, we
1350 // update the entry in the compartment's wrapper map to point
1351 // to the old wrapper.
1352 JS_ASSERT(tobj != wobj);
1353 if (!wobj->swap(cx, tobj))
1354 return NULL;
1355 pmap.put(targetv, ObjectValue(*wobj));
1358 // Lastly, update the original object to point to the new one.
1359 if (origobj->getCompartment() != destination) {
1360 AutoCompartment ac(cx, origobj);
1361 JSObject *tobj = obj;
1362 if (!ac.enter() || !JS_WrapObject(cx, &tobj))
1363 return NULL;
1364 if (!origobj->swap(cx, tobj))
1365 return NULL;
1366 origobj->getCompartment()->crossCompartmentWrappers.put(targetv, origv);
1369 return obj;
1372 JS_PUBLIC_API(JSObject *)
1373 JS_GetGlobalObject(JSContext *cx)
1375 return cx->globalObject;
1378 JS_PUBLIC_API(void)
1379 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1381 CHECK_REQUEST(cx);
1383 cx->globalObject = obj;
1384 if (!cx->hasfp())
1385 cx->resetCompartment();
1388 class AutoResolvingEntry {
1389 public:
1390 AutoResolvingEntry() : entry(NULL) {}
1393 * Returns false on error. But N.B. if obj[id] was already being resolved,
1394 * this is a no-op, and we silently treat that as success.
1396 bool start(JSContext *cx, JSObject *obj, jsid id, uint32 flag) {
1397 JS_ASSERT(!entry);
1398 this->cx = cx;
1399 key.obj = obj;
1400 key.id = id;
1401 this->flag = flag;
1402 bool ok = !!js_StartResolving(cx, &key, flag, &entry);
1403 JS_ASSERT_IF(!ok, !entry);
1404 return ok;
1407 ~AutoResolvingEntry() {
1408 if (entry)
1409 js_StopResolving(cx, &key, flag, NULL, 0);
1412 private:
1413 JSContext *cx;
1414 JSResolvingKey key;
1415 uint32 flag;
1416 JSResolvingEntry *entry;
1419 JSObject *
1420 js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1422 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
1423 JSObject *fun_proto, *obj_proto;
1425 /* If cx has no global object, use obj so prototypes can be found. */
1426 if (!cx->globalObject)
1427 JS_SetGlobalObject(cx, obj);
1429 /* Record Function and Object in cx->resolvingTable. */
1430 AutoResolvingEntry e1, e2;
1431 JSAtom **classAtoms = cx->runtime->atomState.classAtoms;
1432 if (!e1.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Function]), JSRESFLAG_LOOKUP) ||
1433 !e2.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Object]), JSRESFLAG_LOOKUP)) {
1434 return NULL;
1437 /* Initialize the function class first so constructors can be made. */
1438 if (!js_GetClassPrototype(cx, obj, JSProto_Function, &fun_proto))
1439 return NULL;
1440 if (!fun_proto) {
1441 fun_proto = js_InitFunctionClass(cx, obj);
1442 if (!fun_proto)
1443 return NULL;
1444 } else {
1445 JSObject *ctor;
1447 ctor = JS_GetConstructor(cx, fun_proto);
1448 if (!ctor)
1449 return NULL;
1450 obj->defineProperty(cx, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
1451 ObjectValue(*ctor), 0, 0, 0);
1454 /* Initialize the object class next so Object.prototype works. */
1455 if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto))
1456 return NULL;
1457 if (!obj_proto)
1458 obj_proto = js_InitObjectClass(cx, obj);
1459 if (!obj_proto)
1460 return NULL;
1462 /* Function.prototype and the global object delegate to Object.prototype. */
1463 fun_proto->setProto(obj_proto);
1464 if (!obj->getProto())
1465 obj->setProto(obj_proto);
1467 return fun_proto;
1470 JS_PUBLIC_API(JSBool)
1471 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1473 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
1474 CHECK_REQUEST(cx);
1477 * JS_SetGlobalObject might or might not change cx's compartment, so call
1478 * it before assertSameCompartment. (The API contract is that *after* this,
1479 * cx and obj must be in the same compartment.)
1481 if (!cx->globalObject)
1482 JS_SetGlobalObject(cx, obj);
1483 assertSameCompartment(cx, obj);
1485 /* Define a top-level property 'undefined' with the undefined value. */
1486 JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1487 if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1488 PropertyStub, StrictPropertyStub,
1489 JSPROP_PERMANENT | JSPROP_READONLY)) {
1490 return JS_FALSE;
1493 /* Function and Object require cooperative bootstrapping magic. */
1494 if (!js_InitFunctionAndObjectClasses(cx, obj))
1495 return JS_FALSE;
1497 /* Initialize the rest of the standard objects and functions. */
1498 return js_InitArrayClass(cx, obj) &&
1499 js_InitBooleanClass(cx, obj) &&
1500 js_InitExceptionClasses(cx, obj) &&
1501 js_InitMathClass(cx, obj) &&
1502 js_InitNumberClass(cx, obj) &&
1503 js_InitJSONClass(cx, obj) &&
1504 js_InitRegExpClass(cx, obj) &&
1505 js_InitStringClass(cx, obj) &&
1506 js_InitTypedArrayClasses(cx, obj) &&
1507 #if JS_HAS_XML_SUPPORT
1508 js_InitXMLClasses(cx, obj) &&
1509 #endif
1510 #if JS_HAS_GENERATORS
1511 js_InitIteratorClasses(cx, obj) &&
1512 #endif
1513 js_InitDateClass(cx, obj) &&
1514 js_InitProxyClass(cx, obj);
1517 #define CLASP(name) (&js_##name##Class)
1518 #define TYPED_ARRAY_CLASP(type) (&TypedArray::fastClasses[TypedArray::type])
1519 #define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
1520 #define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
1521 #define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
1522 #define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
1524 typedef struct JSStdName {
1525 JSObjectOp init;
1526 size_t atomOffset; /* offset of atom pointer in JSAtomState */
1527 const char *name; /* null if atom is pre-pinned, else name */
1528 Class *clasp;
1529 } JSStdName;
1531 static JSAtom *
1532 StdNameToAtom(JSContext *cx, JSStdName *stdn)
1534 size_t offset;
1535 JSAtom *atom;
1536 const char *name;
1538 offset = stdn->atomOffset;
1539 atom = OFFSET_TO_ATOM(cx->runtime, offset);
1540 if (!atom) {
1541 name = stdn->name;
1542 if (name) {
1543 atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1544 OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1547 return atom;
1551 * Table of class initializers and their atom offsets in rt->atomState.
1552 * If you add a "standard" class, remember to update this table.
1554 static JSStdName standard_class_atoms[] = {
1555 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Function)},
1556 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Object)},
1557 {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)},
1558 {js_InitBooleanClass, EAGER_ATOM_AND_CLASP(Boolean)},
1559 {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)},
1560 {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)},
1561 {js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)},
1562 {js_InitStringClass, EAGER_ATOM_AND_CLASP(String)},
1563 {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)},
1564 {js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)},
1565 #if JS_HAS_XML_SUPPORT
1566 {js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)},
1567 {js_InitNamespaceClass, EAGER_ATOM_AND_CLASP(Namespace)},
1568 {js_InitQNameClass, EAGER_ATOM_AND_CLASP(QName)},
1569 #endif
1570 #if JS_HAS_GENERATORS
1571 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
1572 #endif
1573 {js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
1574 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
1575 {NULL, 0, NULL, NULL}
1579 * Table of top-level function and constant names and their init functions.
1580 * If you add a "standard" global function or property, remember to update
1581 * this table.
1583 static JSStdName standard_class_names[] = {
1584 {js_InitObjectClass, EAGER_ATOM(eval), CLASP(Object)},
1586 /* Global properties and functions defined by the Number class. */
1587 {js_InitNumberClass, EAGER_ATOM(NaN), CLASP(Number)},
1588 {js_InitNumberClass, EAGER_ATOM(Infinity), CLASP(Number)},
1589 {js_InitNumberClass, LAZY_ATOM(isNaN), CLASP(Number)},
1590 {js_InitNumberClass, LAZY_ATOM(isFinite), CLASP(Number)},
1591 {js_InitNumberClass, LAZY_ATOM(parseFloat), CLASP(Number)},
1592 {js_InitNumberClass, LAZY_ATOM(parseInt), CLASP(Number)},
1594 /* String global functions. */
1595 {js_InitStringClass, LAZY_ATOM(escape), CLASP(String)},
1596 {js_InitStringClass, LAZY_ATOM(unescape), CLASP(String)},
1597 {js_InitStringClass, LAZY_ATOM(decodeURI), CLASP(String)},
1598 {js_InitStringClass, LAZY_ATOM(encodeURI), CLASP(String)},
1599 {js_InitStringClass, LAZY_ATOM(decodeURIComponent), CLASP(String)},
1600 {js_InitStringClass, LAZY_ATOM(encodeURIComponent), CLASP(String)},
1601 #if JS_HAS_UNEVAL
1602 {js_InitStringClass, LAZY_ATOM(uneval), CLASP(String)},
1603 #endif
1605 /* Exception constructors. */
1606 {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)},
1607 {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
1608 {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
1609 {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
1610 {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
1611 {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
1612 {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
1613 {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)},
1615 #if JS_HAS_XML_SUPPORT
1616 {js_InitXMLClass, LAZY_ATOM(XMLList), CLASP(XML)},
1617 {js_InitXMLClass, LAZY_ATOM(isXMLName), CLASP(XML)},
1618 #endif
1620 #if JS_HAS_GENERATORS
1621 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)},
1622 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Generator)},
1623 #endif
1625 /* Typed Arrays */
1626 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
1627 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int8Array), TYPED_ARRAY_CLASP(TYPE_INT8)},
1628 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8Array), TYPED_ARRAY_CLASP(TYPE_UINT8)},
1629 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int16Array), TYPED_ARRAY_CLASP(TYPE_INT16)},
1630 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint16Array), TYPED_ARRAY_CLASP(TYPE_UINT16)},
1631 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int32Array), TYPED_ARRAY_CLASP(TYPE_INT32)},
1632 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint32Array), TYPED_ARRAY_CLASP(TYPE_UINT32)},
1633 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float32Array), TYPED_ARRAY_CLASP(TYPE_FLOAT32)},
1634 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
1635 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8ClampedArray),
1636 TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
1638 {js_InitProxyClass, EAGER_ATOM_AND_CLASP(Proxy)},
1640 {NULL, 0, NULL, NULL}
1643 static JSStdName object_prototype_names[] = {
1644 /* Object.prototype properties (global delegates to Object.prototype). */
1645 {js_InitObjectClass, EAGER_ATOM(proto), CLASP(Object)},
1646 #if JS_HAS_TOSOURCE
1647 {js_InitObjectClass, EAGER_ATOM(toSource), CLASP(Object)},
1648 #endif
1649 {js_InitObjectClass, EAGER_ATOM(toString), CLASP(Object)},
1650 {js_InitObjectClass, EAGER_ATOM(toLocaleString), CLASP(Object)},
1651 {js_InitObjectClass, EAGER_ATOM(valueOf), CLASP(Object)},
1652 #if JS_HAS_OBJ_WATCHPOINT
1653 {js_InitObjectClass, LAZY_ATOM(watch), CLASP(Object)},
1654 {js_InitObjectClass, LAZY_ATOM(unwatch), CLASP(Object)},
1655 #endif
1656 {js_InitObjectClass, LAZY_ATOM(hasOwnProperty), CLASP(Object)},
1657 {js_InitObjectClass, LAZY_ATOM(isPrototypeOf), CLASP(Object)},
1658 {js_InitObjectClass, LAZY_ATOM(propertyIsEnumerable), CLASP(Object)},
1659 #if OLD_GETTER_SETTER_METHODS
1660 {js_InitObjectClass, LAZY_ATOM(defineGetter), CLASP(Object)},
1661 {js_InitObjectClass, LAZY_ATOM(defineSetter), CLASP(Object)},
1662 {js_InitObjectClass, LAZY_ATOM(lookupGetter), CLASP(Object)},
1663 {js_InitObjectClass, LAZY_ATOM(lookupSetter), CLASP(Object)},
1664 #endif
1666 {NULL, 0, NULL, NULL}
1669 JS_PUBLIC_API(JSBool)
1670 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
1672 JSString *idstr;
1673 JSRuntime *rt;
1674 JSAtom *atom;
1675 JSStdName *stdnm;
1676 uintN i;
1678 CHECK_REQUEST(cx);
1679 assertSameCompartment(cx, obj, id);
1680 *resolved = JS_FALSE;
1682 rt = cx->runtime;
1683 JS_ASSERT(rt->state != JSRTS_DOWN);
1684 if (rt->state == JSRTS_LANDING || !JSID_IS_ATOM(id))
1685 return JS_TRUE;
1687 idstr = JSID_TO_STRING(id);
1689 /* Check whether we're resolving 'undefined', and define it if so. */
1690 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1691 if (idstr == ATOM_TO_STRING(atom)) {
1692 *resolved = JS_TRUE;
1693 return obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1694 PropertyStub, StrictPropertyStub,
1695 JSPROP_PERMANENT | JSPROP_READONLY);
1698 /* Try for class constructors/prototypes named by well-known atoms. */
1699 stdnm = NULL;
1700 for (i = 0; standard_class_atoms[i].init; i++) {
1701 JS_ASSERT(standard_class_atoms[i].clasp);
1702 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1703 if (idstr == ATOM_TO_STRING(atom)) {
1704 stdnm = &standard_class_atoms[i];
1705 break;
1709 if (!stdnm) {
1710 /* Try less frequently used top-level functions and constants. */
1711 for (i = 0; standard_class_names[i].init; i++) {
1712 JS_ASSERT(standard_class_names[i].clasp);
1713 atom = StdNameToAtom(cx, &standard_class_names[i]);
1714 if (!atom)
1715 return JS_FALSE;
1716 if (idstr == ATOM_TO_STRING(atom)) {
1717 stdnm = &standard_class_names[i];
1718 break;
1722 if (!stdnm && !obj->getProto()) {
1724 * Try even less frequently used names delegated from the global
1725 * object to Object.prototype, but only if the Object class hasn't
1726 * yet been initialized.
1728 for (i = 0; object_prototype_names[i].init; i++) {
1729 JS_ASSERT(object_prototype_names[i].clasp);
1730 atom = StdNameToAtom(cx, &object_prototype_names[i]);
1731 if (!atom)
1732 return JS_FALSE;
1733 if (idstr == ATOM_TO_STRING(atom)) {
1734 stdnm = &object_prototype_names[i];
1735 break;
1741 if (stdnm) {
1743 * If this standard class is anonymous, then we don't want to resolve
1744 * by name.
1746 JS_ASSERT(obj->isGlobal());
1747 if (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)
1748 return JS_TRUE;
1750 JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(stdnm->clasp);
1751 if (obj->getReservedSlot(key).isObject())
1752 return JS_TRUE;
1754 if (!stdnm->init(cx, obj))
1755 return JS_FALSE;
1756 *resolved = JS_TRUE;
1758 return JS_TRUE;
1761 JS_PUBLIC_API(JSBool)
1762 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1764 JSRuntime *rt;
1765 JSAtom *atom;
1766 uintN i;
1768 CHECK_REQUEST(cx);
1769 assertSameCompartment(cx, obj);
1770 rt = cx->runtime;
1772 /* Check whether we need to bind 'undefined' and define it if so. */
1773 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1774 if (!obj->nativeContains(ATOM_TO_JSID(atom)) &&
1775 !obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1776 PropertyStub, StrictPropertyStub,
1777 JSPROP_PERMANENT | JSPROP_READONLY)) {
1778 return JS_FALSE;
1781 /* Initialize any classes that have not been resolved yet. */
1782 for (i = 0; standard_class_atoms[i].init; i++) {
1783 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1784 if (!obj->nativeContains(ATOM_TO_JSID(atom)) &&
1785 !standard_class_atoms[i].init(cx, obj)) {
1786 return JS_FALSE;
1790 return JS_TRUE;
1793 namespace js {
1795 JSIdArray *
1796 NewIdArray(JSContext *cx, jsint length)
1798 JSIdArray *ida;
1800 ida = (JSIdArray *)
1801 cx->calloc(offsetof(JSIdArray, vector) + length * sizeof(jsval));
1802 if (ida)
1803 ida->length = length;
1804 return ida;
1810 * Unlike realloc(3), this function frees ida on failure.
1812 static JSIdArray *
1813 SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
1815 JSIdArray *rida;
1817 rida = (JSIdArray *)
1818 JS_realloc(cx, ida,
1819 offsetof(JSIdArray, vector) + length * sizeof(jsval));
1820 if (!rida) {
1821 JS_DestroyIdArray(cx, ida);
1822 } else {
1823 rida->length = length;
1825 return rida;
1828 static JSIdArray *
1829 AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1831 jsint i, length;
1833 i = *ip;
1834 length = ida->length;
1835 if (i >= length) {
1836 ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
1837 if (!ida)
1838 return NULL;
1839 JS_ASSERT(i < ida->length);
1841 ida->vector[i] = ATOM_TO_JSID(atom);
1842 *ip = i + 1;
1843 return ida;
1846 static JSIdArray *
1847 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
1848 jsint *ip, JSBool *foundp)
1850 *foundp = obj->nativeContains(ATOM_TO_JSID(atom));
1851 if (*foundp)
1852 ida = AddAtomToArray(cx, atom, ida, ip);
1853 return ida;
1856 JS_PUBLIC_API(JSIdArray *)
1857 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, JSIdArray *ida)
1859 JSRuntime *rt;
1860 jsint i, j, k;
1861 JSAtom *atom;
1862 JSBool found;
1863 JSObjectOp init;
1865 CHECK_REQUEST(cx);
1866 assertSameCompartment(cx, obj, ida);
1867 rt = cx->runtime;
1868 if (ida) {
1869 i = ida->length;
1870 } else {
1871 ida = NewIdArray(cx, 8);
1872 if (!ida)
1873 return NULL;
1874 i = 0;
1877 /* Check whether 'undefined' has been resolved and enumerate it if so. */
1878 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1879 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1880 if (!ida)
1881 return NULL;
1883 /* Enumerate only classes that *have* been resolved. */
1884 for (j = 0; standard_class_atoms[j].init; j++) {
1885 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
1886 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1887 if (!ida)
1888 return NULL;
1890 if (found) {
1891 init = standard_class_atoms[j].init;
1893 for (k = 0; standard_class_names[k].init; k++) {
1894 if (standard_class_names[k].init == init) {
1895 atom = StdNameToAtom(cx, &standard_class_names[k]);
1896 ida = AddAtomToArray(cx, atom, ida, &i);
1897 if (!ida)
1898 return NULL;
1902 if (init == js_InitObjectClass) {
1903 for (k = 0; object_prototype_names[k].init; k++) {
1904 atom = StdNameToAtom(cx, &object_prototype_names[k]);
1905 ida = AddAtomToArray(cx, atom, ida, &i);
1906 if (!ida)
1907 return NULL;
1913 /* Trim to exact length. */
1914 return SetIdArrayLength(cx, ida, i);
1917 #undef CLASP
1918 #undef EAGER_ATOM
1919 #undef EAGER_CLASS_ATOM
1920 #undef EAGER_ATOM_CLASP
1921 #undef LAZY_ATOM
1923 JS_PUBLIC_API(JSBool)
1924 JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp)
1926 CHECK_REQUEST(cx);
1927 assertSameCompartment(cx, obj);
1928 return js_GetClassObject(cx, obj, key, objp);
1931 JS_PUBLIC_API(JSObject *)
1932 JS_GetScopeChain(JSContext *cx)
1934 CHECK_REQUEST(cx);
1935 return GetScopeChain(cx);
1938 JS_PUBLIC_API(JSObject *)
1939 JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
1941 assertSameCompartment(cx, obj);
1942 return obj->getGlobal();
1945 JS_PUBLIC_API(JSObject *)
1946 JS_GetGlobalForScopeChain(JSContext *cx)
1948 CHECK_REQUEST(cx);
1949 return GetGlobalForScopeChain(cx);
1952 JS_PUBLIC_API(jsval)
1953 JS_ComputeThis(JSContext *cx, jsval *vp)
1955 assertSameCompartment(cx, JSValueArray(vp, 2));
1956 return BoxThisForVp(cx, Valueify(vp)) ? vp[1] : JSVAL_NULL;
1959 JS_PUBLIC_API(void *)
1960 JS_malloc(JSContext *cx, size_t nbytes)
1962 return cx->malloc(nbytes);
1965 JS_PUBLIC_API(void *)
1966 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1968 return cx->realloc(p, nbytes);
1971 JS_PUBLIC_API(void)
1972 JS_free(JSContext *cx, void *p)
1974 return cx->free(p);
1977 JS_PUBLIC_API(void)
1978 JS_updateMallocCounter(JSContext *cx, size_t nbytes)
1980 return cx->runtime->updateMallocCounter(nbytes);
1983 JS_PUBLIC_API(char *)
1984 JS_strdup(JSContext *cx, const char *s)
1986 size_t n;
1987 void *p;
1989 n = strlen(s) + 1;
1990 p = cx->malloc(n);
1991 if (!p)
1992 return NULL;
1993 return (char *)memcpy(p, s, n);
1996 JS_PUBLIC_API(JSBool)
1997 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
1999 d = JS_CANONICALIZE_NAN(d);
2000 Valueify(rval)->setNumber(d);
2001 return JS_TRUE;
2004 #undef JS_AddRoot
2006 JS_PUBLIC_API(JSBool)
2007 JS_AddValueRoot(JSContext *cx, jsval *vp)
2009 CHECK_REQUEST(cx);
2010 return js_AddRoot(cx, Valueify(vp), NULL);
2013 JS_PUBLIC_API(JSBool)
2014 JS_AddStringRoot(JSContext *cx, JSString **rp)
2016 CHECK_REQUEST(cx);
2017 return js_AddGCThingRoot(cx, (void **)rp, NULL);
2020 JS_PUBLIC_API(JSBool)
2021 JS_AddObjectRoot(JSContext *cx, JSObject **rp)
2023 CHECK_REQUEST(cx);
2024 return js_AddGCThingRoot(cx, (void **)rp, NULL);
2027 JS_PUBLIC_API(JSBool)
2028 JS_AddGCThingRoot(JSContext *cx, void **rp)
2030 CHECK_REQUEST(cx);
2031 return js_AddGCThingRoot(cx, (void **)rp, NULL);
2034 JS_PUBLIC_API(JSBool)
2035 JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name)
2037 CHECK_REQUEST(cx);
2038 return js_AddRoot(cx, Valueify(vp), name);
2041 JS_PUBLIC_API(JSBool)
2042 JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name)
2044 CHECK_REQUEST(cx);
2045 return js_AddGCThingRoot(cx, (void **)rp, name);
2048 JS_PUBLIC_API(JSBool)
2049 JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name)
2051 CHECK_REQUEST(cx);
2052 return js_AddGCThingRoot(cx, (void **)rp, name);
2055 JS_PUBLIC_API(JSBool)
2056 JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name)
2058 CHECK_REQUEST(cx);
2059 return js_AddGCThingRoot(cx, (void **)rp, name);
2062 JS_PUBLIC_API(JSBool)
2063 JS_RemoveValueRoot(JSContext *cx, jsval *vp)
2065 CHECK_REQUEST(cx);
2066 return js_RemoveRoot(cx->runtime, (void *)vp);
2069 JS_PUBLIC_API(JSBool)
2070 JS_RemoveStringRoot(JSContext *cx, JSString **rp)
2072 CHECK_REQUEST(cx);
2073 return js_RemoveRoot(cx->runtime, (void *)rp);
2076 JS_PUBLIC_API(JSBool)
2077 JS_RemoveObjectRoot(JSContext *cx, JSObject **rp)
2079 CHECK_REQUEST(cx);
2080 return js_RemoveRoot(cx->runtime, (void *)rp);
2083 JS_PUBLIC_API(JSBool)
2084 JS_RemoveGCThingRoot(JSContext *cx, void **rp)
2086 CHECK_REQUEST(cx);
2087 return js_RemoveRoot(cx->runtime, (void *)rp);
2090 #ifdef DEBUG
2092 JS_PUBLIC_API(void)
2093 JS_DumpNamedRoots(JSRuntime *rt,
2094 void (*dump)(const char *name, void *rp, JSGCRootType type, void *data),
2095 void *data)
2097 js_DumpNamedRoots(rt, dump, data);
2100 #endif /* DEBUG */
2102 JS_PUBLIC_API(uint32)
2103 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
2105 return js_MapGCRoots(rt, map, data);
2108 JS_PUBLIC_API(JSBool)
2109 JS_LockGCThing(JSContext *cx, void *thing)
2111 JSBool ok;
2113 CHECK_REQUEST(cx);
2114 ok = js_LockGCThingRT(cx->runtime, thing);
2115 if (!ok)
2116 JS_ReportOutOfMemory(cx);
2117 return ok;
2120 JS_PUBLIC_API(JSBool)
2121 JS_LockGCThingRT(JSRuntime *rt, void *thing)
2123 return js_LockGCThingRT(rt, thing);
2126 JS_PUBLIC_API(JSBool)
2127 JS_UnlockGCThing(JSContext *cx, void *thing)
2129 CHECK_REQUEST(cx);
2130 js_UnlockGCThingRT(cx->runtime, thing);
2131 return true;
2134 JS_PUBLIC_API(JSBool)
2135 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
2137 js_UnlockGCThingRT(rt, thing);
2138 return true;
2141 JS_PUBLIC_API(void)
2142 JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
2144 rt->gcExtraRootsTraceOp = traceOp;
2145 rt->gcExtraRootsData = data;
2148 JS_PUBLIC_API(void)
2149 JS_TraceRuntime(JSTracer *trc)
2151 TraceRuntime(trc);
2154 JS_PUBLIC_API(void)
2155 JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
2157 JS_ASSERT(thing);
2158 MarkKind(trc, thing, kind);
2161 #ifdef DEBUG
2163 #ifdef HAVE_XPCONNECT
2164 #include "dump_xpc.h"
2165 #endif
2167 JS_PUBLIC_API(void)
2168 JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, uint32 kind,
2169 JSBool details)
2171 const char *name;
2172 size_t n;
2174 if (bufsize == 0)
2175 return;
2177 switch (kind) {
2178 case JSTRACE_OBJECT:
2180 JSObject *obj = (JSObject *)thing;
2181 Class *clasp = obj->getClass();
2183 name = clasp->name;
2184 #ifdef HAVE_XPCONNECT
2185 if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
2186 void *privateThing = obj->getPrivate();
2187 if (privateThing) {
2188 const char *xpcClassName = GetXPCObjectClassName(privateThing);
2189 if (xpcClassName)
2190 name = xpcClassName;
2193 #endif
2194 break;
2197 case JSTRACE_STRING:
2198 name = ((JSString *)thing)->isDependent()
2199 ? "substring"
2200 : "string";
2201 break;
2203 #if JS_HAS_XML_SUPPORT
2204 case JSTRACE_XML:
2205 name = "xml";
2206 break;
2207 #endif
2208 default:
2209 JS_ASSERT(0);
2210 return;
2211 break;
2214 n = strlen(name);
2215 if (n > bufsize - 1)
2216 n = bufsize - 1;
2217 memcpy(buf, name, n + 1);
2218 buf += n;
2219 bufsize -= n;
2221 if (details && bufsize > 2) {
2222 *buf++ = ' ';
2223 bufsize--;
2225 switch (kind) {
2226 case JSTRACE_OBJECT:
2228 JSObject *obj = (JSObject *)thing;
2229 Class *clasp = obj->getClass();
2230 if (clasp == &js_FunctionClass) {
2231 JSFunction *fun = GET_FUNCTION_PRIVATE(trc->context, obj);
2232 if (!fun) {
2233 JS_snprintf(buf, bufsize, "<newborn>");
2234 } else if (FUN_OBJECT(fun) != obj) {
2235 JS_snprintf(buf, bufsize, "%p", fun);
2236 } else {
2237 if (fun->atom)
2238 PutEscapedString(buf, bufsize, ATOM_TO_STRING(fun->atom), 0);
2240 } else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
2241 JS_snprintf(buf, bufsize, "%p", obj->getPrivate());
2242 } else {
2243 JS_snprintf(buf, bufsize, "<no private>");
2245 break;
2248 case JSTRACE_STRING:
2250 JSString *str = (JSString *)thing;
2251 if (str->isLinear())
2252 PutEscapedString(buf, bufsize, str->assertIsLinear(), 0);
2253 else
2254 JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
2255 break;
2258 #if JS_HAS_XML_SUPPORT
2259 case JSTRACE_XML:
2261 extern const char *js_xml_class_str[];
2262 JSXML *xml = (JSXML *)thing;
2264 JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]);
2265 break;
2267 #endif
2268 default:
2269 JS_ASSERT(0);
2270 break;
2273 buf[bufsize - 1] = '\0';
2276 typedef struct JSHeapDumpNode JSHeapDumpNode;
2278 struct JSHeapDumpNode {
2279 void *thing;
2280 uint32 kind;
2281 JSHeapDumpNode *next; /* next sibling */
2282 JSHeapDumpNode *parent; /* node with the thing that refer to thing
2283 from this node */
2284 char edgeName[1]; /* name of the edge from parent->thing
2285 into thing */
2288 typedef struct JSDumpingTracer {
2289 JSTracer base;
2290 JSDHashTable visited;
2291 JSBool ok;
2292 void *startThing;
2293 void *thingToFind;
2294 void *thingToIgnore;
2295 JSHeapDumpNode *parentNode;
2296 JSHeapDumpNode **lastNodep;
2297 char buffer[200];
2298 } JSDumpingTracer;
2300 static void
2301 DumpNotify(JSTracer *trc, void *thing, uint32 kind)
2303 JSDumpingTracer *dtrc;
2304 JSContext *cx;
2305 JSDHashEntryStub *entry;
2306 JSHeapDumpNode *node;
2307 const char *edgeName;
2308 size_t edgeNameSize;
2310 JS_ASSERT(trc->callback == DumpNotify);
2311 dtrc = (JSDumpingTracer *)trc;
2313 if (!dtrc->ok || thing == dtrc->thingToIgnore)
2314 return;
2316 cx = trc->context;
2319 * Check if we have already seen thing unless it is thingToFind to include
2320 * it to the graph each time we reach it and print all live things that
2321 * refer to thingToFind.
2323 * This does not print all possible paths leading to thingToFind since
2324 * when a thing A refers directly or indirectly to thingToFind and A is
2325 * present several times in the graph, we will print only the first path
2326 * leading to A and thingToFind, other ways to reach A will be ignored.
2328 if (dtrc->thingToFind != thing) {
2330 * The startThing check allows to avoid putting startThing into the
2331 * hash table before tracing startThing in JS_DumpHeap.
2333 if (thing == dtrc->startThing)
2334 return;
2335 entry = (JSDHashEntryStub *)
2336 JS_DHashTableOperate(&dtrc->visited, thing, JS_DHASH_ADD);
2337 if (!entry) {
2338 JS_ReportOutOfMemory(cx);
2339 dtrc->ok = JS_FALSE;
2340 return;
2342 if (entry->key)
2343 return;
2344 entry->key = thing;
2347 if (dtrc->base.debugPrinter) {
2348 dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer));
2349 edgeName = dtrc->buffer;
2350 } else if (dtrc->base.debugPrintIndex != (size_t)-1) {
2351 JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]",
2352 (const char *)dtrc->base.debugPrintArg,
2353 dtrc->base.debugPrintIndex);
2354 edgeName = dtrc->buffer;
2355 } else {
2356 edgeName = (const char*)dtrc->base.debugPrintArg;
2359 edgeNameSize = strlen(edgeName) + 1;
2360 node = (JSHeapDumpNode *) js_malloc(offsetof(JSHeapDumpNode, edgeName) + edgeNameSize);
2361 if (!node) {
2362 dtrc->ok = JS_FALSE;
2363 return;
2366 node->thing = thing;
2367 node->kind = kind;
2368 node->next = NULL;
2369 node->parent = dtrc->parentNode;
2370 memcpy(node->edgeName, edgeName, edgeNameSize);
2372 JS_ASSERT(!*dtrc->lastNodep);
2373 *dtrc->lastNodep = node;
2374 dtrc->lastNodep = &node->next;
2377 /* Dump node and the chain that leads to thing it contains. */
2378 static JSBool
2379 DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
2381 JSHeapDumpNode *prev, *following;
2382 size_t chainLimit;
2383 JSBool ok;
2384 enum { MAX_PARENTS_TO_PRINT = 10 };
2386 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2387 &dtrc->base, node->thing, node->kind, JS_TRUE);
2388 if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
2389 return JS_FALSE;
2392 * We need to print the parent chain in the reverse order. To do it in
2393 * O(N) time where N is the chain length we first reverse the chain while
2394 * searching for the top and then print each node while restoring the
2395 * chain order.
2397 chainLimit = MAX_PARENTS_TO_PRINT;
2398 prev = NULL;
2399 for (;;) {
2400 following = node->parent;
2401 node->parent = prev;
2402 prev = node;
2403 node = following;
2404 if (!node)
2405 break;
2406 if (chainLimit == 0) {
2407 if (fputs("...", fp) < 0)
2408 return JS_FALSE;
2409 break;
2411 --chainLimit;
2414 node = prev;
2415 prev = following;
2416 ok = JS_TRUE;
2417 do {
2418 /* Loop must continue even when !ok to restore the parent chain. */
2419 if (ok) {
2420 if (!prev) {
2421 /* Print edge from some runtime root or startThing. */
2422 if (fputs(node->edgeName, fp) < 0)
2423 ok = JS_FALSE;
2424 } else {
2425 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2426 &dtrc->base, prev->thing, prev->kind,
2427 JS_FALSE);
2428 if (fprintf(fp, "(%p %s).%s",
2429 prev->thing, dtrc->buffer, node->edgeName) < 0) {
2430 ok = JS_FALSE;
2434 following = node->parent;
2435 node->parent = prev;
2436 prev = node;
2437 node = following;
2438 } while (node);
2440 return ok && putc('\n', fp) >= 0;
2443 JS_PUBLIC_API(JSBool)
2444 JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind,
2445 void *thingToFind, size_t maxDepth, void *thingToIgnore)
2447 JSDumpingTracer dtrc;
2448 JSHeapDumpNode *node, *children, *next, *parent;
2449 size_t depth;
2450 JSBool thingToFindWasTraced;
2452 if (maxDepth == 0)
2453 return JS_TRUE;
2455 JS_TRACER_INIT(&dtrc.base, cx, DumpNotify);
2456 if (!JS_DHashTableInit(&dtrc.visited, JS_DHashGetStubOps(),
2457 NULL, sizeof(JSDHashEntryStub),
2458 JS_DHASH_DEFAULT_CAPACITY(100))) {
2459 JS_ReportOutOfMemory(cx);
2460 return JS_FALSE;
2462 dtrc.ok = JS_TRUE;
2463 dtrc.startThing = startThing;
2464 dtrc.thingToFind = thingToFind;
2465 dtrc.thingToIgnore = thingToIgnore;
2466 dtrc.parentNode = NULL;
2467 node = NULL;
2468 dtrc.lastNodep = &node;
2469 if (!startThing) {
2470 JS_ASSERT(startKind == 0);
2471 TraceRuntime(&dtrc.base);
2472 } else {
2473 JS_TraceChildren(&dtrc.base, startThing, startKind);
2476 depth = 1;
2477 if (!node)
2478 goto dump_out;
2480 thingToFindWasTraced = thingToFind && thingToFind == startThing;
2481 for (;;) {
2483 * Loop must continue even when !dtrc.ok to free all nodes allocated
2484 * so far.
2486 if (dtrc.ok) {
2487 if (thingToFind == NULL || thingToFind == node->thing)
2488 dtrc.ok = DumpNode(&dtrc, fp, node);
2490 /* Descend into children. */
2491 if (dtrc.ok &&
2492 depth < maxDepth &&
2493 (thingToFind != node->thing || !thingToFindWasTraced)) {
2494 dtrc.parentNode = node;
2495 children = NULL;
2496 dtrc.lastNodep = &children;
2497 JS_TraceChildren(&dtrc.base, node->thing, node->kind);
2498 if (thingToFind == node->thing)
2499 thingToFindWasTraced = JS_TRUE;
2500 if (children != NULL) {
2501 ++depth;
2502 node = children;
2503 continue;
2508 /* Move to next or parents next and free the node. */
2509 for (;;) {
2510 next = node->next;
2511 parent = node->parent;
2512 js_free(node);
2513 node = next;
2514 if (node)
2515 break;
2516 if (!parent)
2517 goto dump_out;
2518 JS_ASSERT(depth > 1);
2519 --depth;
2520 node = parent;
2524 dump_out:
2525 JS_ASSERT(depth == 1);
2526 JS_DHashTableFinish(&dtrc.visited);
2527 return dtrc.ok;
2530 #endif /* DEBUG */
2532 JS_PUBLIC_API(void)
2533 JS_MarkGCThing(JSContext *cx, jsval v, const char *name, void *arg)
2535 JSTracer *trc;
2537 trc = (JSTracer *)arg;
2538 if (!trc)
2539 trc = cx->runtime->gcMarkingTracer;
2540 else
2541 JS_ASSERT(trc == cx->runtime->gcMarkingTracer);
2543 #ifdef JS_THREADSAFE
2544 JS_ASSERT(cx->runtime->gcThread == trc->context->thread);
2545 #endif
2546 MarkValue(trc, Valueify(v), name ? name : "unknown");
2549 extern JS_PUBLIC_API(JSBool)
2550 JS_IsGCMarkingTracer(JSTracer *trc)
2552 return IS_GC_MARKING_TRACER(trc);
2555 JS_PUBLIC_API(void)
2556 JS_GC(JSContext *cx)
2558 LeaveTrace(cx);
2560 /* Don't nuke active arenas if executing or compiling. */
2561 if (cx->tempPool.current == &cx->tempPool.first)
2562 JS_FinishArenaPool(&cx->tempPool);
2563 js_GC(cx, NULL, GC_NORMAL);
2566 JS_PUBLIC_API(void)
2567 JS_MaybeGC(JSContext *cx)
2569 LeaveTrace(cx);
2571 /* Don't nuke active arenas if executing or compiling. */
2572 if (cx->tempPool.current == &cx->tempPool.first)
2573 JS_FinishArenaPool(&cx->tempPool);
2575 MaybeGC(cx);
2578 JS_PUBLIC_API(JSGCCallback)
2579 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
2581 CHECK_REQUEST(cx);
2582 return JS_SetGCCallbackRT(cx->runtime, cb);
2585 JS_PUBLIC_API(JSGCCallback)
2586 JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
2588 JSGCCallback oldcb;
2590 oldcb = rt->gcCallback;
2591 rt->gcCallback = cb;
2592 return oldcb;
2595 JS_PUBLIC_API(JSBool)
2596 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
2598 JS_ASSERT(thing);
2599 JS_ASSERT(!cx->runtime->gcMarkingTracer);
2600 return IsAboutToBeFinalized(cx, thing);
2603 JS_PUBLIC_API(void)
2604 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
2606 switch (key) {
2607 case JSGC_MAX_BYTES:
2608 rt->gcMaxBytes = value;
2609 break;
2610 case JSGC_MAX_MALLOC_BYTES:
2611 rt->setGCMaxMallocBytes(value);
2612 break;
2613 case JSGC_STACKPOOL_LIFESPAN:
2614 rt->gcEmptyArenaPoolLifespan = value;
2615 break;
2616 case JSGC_MODE:
2617 rt->gcMode = JSGCMode(value);
2618 JS_ASSERT(rt->gcMode == JSGC_MODE_GLOBAL ||
2619 rt->gcMode == JSGC_MODE_COMPARTMENT);
2620 break;
2621 default:
2622 JS_ASSERT(key == JSGC_TRIGGER_FACTOR);
2623 JS_ASSERT(value >= 100);
2624 rt->setGCTriggerFactor(value);
2625 return;
2629 JS_PUBLIC_API(uint32)
2630 JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
2632 switch (key) {
2633 case JSGC_MAX_BYTES:
2634 return rt->gcMaxBytes;
2635 case JSGC_MAX_MALLOC_BYTES:
2636 return rt->gcMaxMallocBytes;
2637 case JSGC_STACKPOOL_LIFESPAN:
2638 return rt->gcEmptyArenaPoolLifespan;
2639 case JSGC_TRIGGER_FACTOR:
2640 return rt->gcTriggerFactor;
2641 case JSGC_BYTES:
2642 return rt->gcBytes;
2643 case JSGC_MODE:
2644 return uint32(rt->gcMode);
2645 default:
2646 JS_ASSERT(key == JSGC_NUMBER);
2647 return rt->gcNumber;
2651 JS_PUBLIC_API(void)
2652 JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32 value)
2654 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2655 #ifdef JS_TRACER
2656 SetMaxCodeCacheBytes(cx, value);
2657 #endif
2660 JS_PUBLIC_API(uint32)
2661 JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key)
2663 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2664 #ifdef JS_TRACER
2665 return JS_THREAD_DATA(cx)->maxCodeCacheBytes;
2666 #else
2667 return 0;
2668 #endif
2671 JS_PUBLIC_API(void)
2672 JS_FlushCaches(JSContext *cx)
2674 #ifdef JS_TRACER
2675 FlushJITCache(cx, &cx->compartment->traceMonitor);
2676 #endif
2679 JS_PUBLIC_API(intN)
2680 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
2682 return JSExternalString::changeFinalizer(NULL, finalizer);
2685 JS_PUBLIC_API(intN)
2686 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
2688 return JSExternalString::changeFinalizer(finalizer, NULL);
2691 JS_PUBLIC_API(JSString *)
2692 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
2694 CHECK_REQUEST(cx);
2695 JS_ASSERT(uintN(type) < JSExternalString::TYPE_LIMIT);
2697 JSExternalString *str = js_NewGCExternalString(cx, uintN(type));
2698 if (!str)
2699 return NULL;
2700 str->initFlat(chars, length);
2701 str->externalStringType = type;
2702 cx->runtime->updateMallocCounter((length + 1) * sizeof(jschar));
2703 return str;
2706 JS_PUBLIC_API(intN)
2707 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
2710 * No need to test this in js_GetExternalStringGCType, which asserts its
2711 * inverse instead of wasting cycles on testing a condition we can ensure
2712 * by auditing in-VM calls to the js_... helper.
2714 if (JSString::isStatic(str))
2715 return -1;
2717 return js_GetExternalStringGCType(str);
2720 JS_PUBLIC_API(void)
2721 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
2723 #if JS_STACK_GROWTH_DIRECTION > 0
2724 if (limitAddr == 0)
2725 limitAddr = jsuword(-1);
2726 #endif
2727 cx->stackLimit = limitAddr;
2730 JS_PUBLIC_API(void)
2731 JS_SetNativeStackQuota(JSContext *cx, size_t stackSize)
2733 #ifdef JS_THREADSAFE
2734 JS_ASSERT(cx->thread);
2735 #endif
2737 #if JS_STACK_GROWTH_DIRECTION > 0
2738 if (stackSize == 0) {
2739 cx->stackLimit = jsuword(-1);
2740 } else {
2741 jsuword stackBase = reinterpret_cast<jsuword>(JS_THREAD_DATA(cx)->nativeStackBase);
2742 JS_ASSERT(stackBase <= size_t(-1) - stackSize);
2743 cx->stackLimit = stackBase + stackSize - 1;
2745 #else
2746 if (stackSize == 0) {
2747 cx->stackLimit = 0;
2748 } else {
2749 jsuword stackBase = reinterpret_cast<jsuword>(JS_THREAD_DATA(cx)->nativeStackBase);
2750 JS_ASSERT(stackBase >= stackSize);
2751 cx->stackLimit = stackBase - (stackSize - 1);
2753 #endif
2756 JS_PUBLIC_API(void)
2757 JS_SetScriptStackQuota(JSContext *cx, size_t quota)
2759 cx->scriptStackQuota = quota;
2762 /************************************************************************/
2764 JS_PUBLIC_API(void)
2765 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
2767 cx->free(ida);
2770 JS_PUBLIC_API(JSBool)
2771 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
2773 CHECK_REQUEST(cx);
2774 assertSameCompartment(cx, v);
2775 return ValueToId(cx, Valueify(v), idp);
2778 JS_PUBLIC_API(JSBool)
2779 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
2781 CHECK_REQUEST(cx);
2782 *vp = IdToJsval(id);
2783 assertSameCompartment(cx, *vp);
2784 return JS_TRUE;
2787 JS_PUBLIC_API(JSBool)
2788 JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
2790 return JS_TRUE;
2793 JS_PUBLIC_API(JSBool)
2794 JS_StrictPropertyStub(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
2796 return JS_TRUE;
2799 JS_PUBLIC_API(JSBool)
2800 JS_EnumerateStub(JSContext *cx, JSObject *obj)
2802 return JS_TRUE;
2805 JS_PUBLIC_API(JSBool)
2806 JS_ResolveStub(JSContext *cx, JSObject *obj, jsid id)
2808 return JS_TRUE;
2811 JS_PUBLIC_API(JSBool)
2812 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
2814 JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION);
2815 return js_TryValueOf(cx, obj, type, Valueify(vp));
2818 JS_PUBLIC_API(void)
2819 JS_FinalizeStub(JSContext *cx, JSObject *obj)
2822 JS_PUBLIC_API(JSObject *)
2823 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
2824 JSClass *clasp, JSNative constructor, uintN nargs,
2825 JSPropertySpec *ps, JSFunctionSpec *fs,
2826 JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
2828 CHECK_REQUEST(cx);
2829 assertSameCompartment(cx, obj, parent_proto);
2830 return js_InitClass(cx, obj, parent_proto, Valueify(clasp),
2831 Valueify(constructor), nargs,
2832 ps, fs, static_ps, static_fs);
2835 #ifdef JS_THREADSAFE
2836 JS_PUBLIC_API(JSClass *)
2837 JS_GetClass(JSContext *cx, JSObject *obj)
2839 return Jsvalify(obj->getClass());
2841 #else
2842 JS_PUBLIC_API(JSClass *)
2843 JS_GetClass(JSObject *obj)
2845 return Jsvalify(obj->getClass());
2847 #endif
2849 JS_PUBLIC_API(JSBool)
2850 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2852 CHECK_REQUEST(cx);
2853 assertSameCompartment(cx, obj);
2854 return InstanceOf(cx, obj, Valueify(clasp), Valueify(argv));
2857 JS_PUBLIC_API(JSBool)
2858 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
2860 assertSameCompartment(cx, obj, v);
2861 return HasInstance(cx, obj, Valueify(&v), bp);
2864 JS_PUBLIC_API(void *)
2865 JS_GetPrivate(JSContext *cx, JSObject *obj)
2867 return obj->getPrivate();
2870 JS_PUBLIC_API(JSBool)
2871 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2873 obj->setPrivate(data);
2874 return true;
2877 JS_PUBLIC_API(void *)
2878 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2880 if (!InstanceOf(cx, obj, Valueify(clasp), Valueify(argv)))
2881 return NULL;
2882 return obj->getPrivate();
2885 JS_PUBLIC_API(JSObject *)
2886 JS_GetPrototype(JSContext *cx, JSObject *obj)
2888 JSObject *proto;
2890 CHECK_REQUEST(cx);
2891 assertSameCompartment(cx, obj);
2892 proto = obj->getProto();
2894 /* Beware ref to dead object (we may be called from obj's finalizer). */
2895 return proto && proto->map ? proto : NULL;
2898 JS_PUBLIC_API(JSBool)
2899 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
2901 CHECK_REQUEST(cx);
2902 assertSameCompartment(cx, obj, proto);
2903 return SetProto(cx, obj, proto, JS_FALSE);
2906 JS_PUBLIC_API(JSObject *)
2907 JS_GetParent(JSContext *cx, JSObject *obj)
2909 assertSameCompartment(cx, obj);
2910 JSObject *parent = obj->getParent();
2912 /* Beware ref to dead object (we may be called from obj's finalizer). */
2913 return parent && parent->map ? parent : NULL;
2916 JS_PUBLIC_API(JSBool)
2917 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
2919 CHECK_REQUEST(cx);
2920 JS_ASSERT(parent || !obj->getParent());
2921 assertSameCompartment(cx, obj, parent);
2922 obj->setParent(parent);
2923 return true;
2926 JS_PUBLIC_API(JSObject *)
2927 JS_GetConstructor(JSContext *cx, JSObject *proto)
2929 Value cval;
2931 CHECK_REQUEST(cx);
2932 assertSameCompartment(cx, proto);
2934 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
2936 if (!proto->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), &cval))
2937 return NULL;
2939 JSObject *funobj;
2940 if (!IsFunctionObject(cval, &funobj)) {
2941 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
2942 proto->getClass()->name);
2943 return NULL;
2945 return &cval.toObject();
2948 JS_PUBLIC_API(JSBool)
2949 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
2951 assertSameCompartment(cx, obj);
2952 *idp = OBJECT_TO_JSID(obj);
2953 return JS_TRUE;
2956 JS_PUBLIC_API(JSObject *)
2957 JS_NewGlobalObject(JSContext *cx, JSClass *clasp)
2959 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
2960 CHECK_REQUEST(cx);
2961 JS_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
2962 JSObject *obj = NewNonFunction<WithProto::Given>(cx, Valueify(clasp), NULL, NULL);
2963 if (!obj)
2964 return NULL;
2966 obj->syncSpecialEquality();
2968 /* Construct a regexp statics object for this global object. */
2969 JSObject *res = regexp_statics_construct(cx, obj);
2970 if (!res ||
2971 !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_REGEXP_STATICS, ObjectValue(*res)) ||
2972 !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_FLAGS, Int32Value(0))) {
2973 return NULL;
2976 return obj;
2979 JS_PUBLIC_API(JSObject *)
2980 JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals)
2982 CHECK_REQUEST(cx);
2983 JSCompartment *compartment = NewCompartment(cx, principals);
2984 if (!compartment)
2985 return NULL;
2987 JSCompartment *saved = cx->compartment;
2988 cx->compartment = compartment;
2989 JSObject *obj = JS_NewGlobalObject(cx, clasp);
2990 cx->compartment = saved;
2992 return obj;
2995 JS_PUBLIC_API(JSObject *)
2996 JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
2998 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
2999 CHECK_REQUEST(cx);
3000 assertSameCompartment(cx, proto, parent);
3002 Class *clasp = Valueify(jsclasp);
3003 if (!clasp)
3004 clasp = &js_ObjectClass; /* default class is Object */
3006 JS_ASSERT(clasp != &js_FunctionClass);
3007 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
3009 JSObject *obj = NewNonFunction<WithProto::Class>(cx, clasp, proto, parent);
3010 if (obj)
3011 obj->syncSpecialEquality();
3013 JS_ASSERT_IF(obj, obj->getParent());
3014 return obj;
3017 JS_PUBLIC_API(JSObject *)
3018 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
3020 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
3021 CHECK_REQUEST(cx);
3022 assertSameCompartment(cx, proto, parent);
3024 Class *clasp = Valueify(jsclasp);
3025 if (!clasp)
3026 clasp = &js_ObjectClass; /* default class is Object */
3028 JS_ASSERT(clasp != &js_FunctionClass);
3029 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
3031 JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
3032 if (obj)
3033 obj->syncSpecialEquality();
3034 return obj;
3037 JS_PUBLIC_API(JSObject *)
3038 JS_NewObjectForConstructor(JSContext *cx, const jsval *vp)
3040 CHECK_REQUEST(cx);
3041 assertSameCompartment(cx, *vp);
3043 return js_CreateThis(cx, JSVAL_TO_OBJECT(*vp));
3046 JS_PUBLIC_API(JSBool)
3047 JS_IsExtensible(JSObject *obj)
3049 return obj->isExtensible();
3052 JS_PUBLIC_API(JSBool)
3053 JS_FreezeObject(JSContext *cx, JSObject *obj)
3055 CHECK_REQUEST(cx);
3056 assertSameCompartment(cx, obj);
3058 return obj->freeze(cx);
3061 JS_PUBLIC_API(JSBool)
3062 JS_DeepFreezeObject(JSContext *cx, JSObject *obj)
3064 CHECK_REQUEST(cx);
3065 assertSameCompartment(cx, obj);
3067 /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */
3068 if (!obj->isExtensible())
3069 return true;
3071 if (!obj->freeze(cx))
3072 return false;
3074 /* Walk slots in obj and if any value is a non-null object, seal it. */
3075 for (uint32 i = 0, n = obj->slotSpan(); i < n; ++i) {
3076 const Value &v = obj->getSlot(i);
3077 if (v.isPrimitive())
3078 continue;
3079 if (!JS_DeepFreezeObject(cx, &v.toObject()))
3080 return false;
3083 return true;
3086 JS_PUBLIC_API(JSObject *)
3087 JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
3089 CHECK_REQUEST(cx);
3090 assertSameCompartment(cx, proto, parent);
3091 Class *clasp = Valueify(jsclasp);
3092 if (!clasp)
3093 clasp = &js_ObjectClass; /* default class is Object */
3094 return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
3097 JS_PUBLIC_API(JSObject *)
3098 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *proto,
3099 JSObject *parent, uintN argc, jsval *argv)
3101 CHECK_REQUEST(cx);
3102 assertSameCompartment(cx, proto, parent, JSValueArray(argv, argc));
3103 Class *clasp = Valueify(jsclasp);
3104 if (!clasp)
3105 clasp = &js_ObjectClass; /* default class is Object */
3106 return js_ConstructObject(cx, clasp, proto, parent, argc, Valueify(argv));
3109 static JSBool
3110 LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3111 JSObject **objp, JSProperty **propp)
3113 CHECK_REQUEST(cx);
3114 assertSameCompartment(cx, obj, id);
3116 JSAutoResolveFlags rf(cx, flags);
3117 id = js_CheckForStringIndex(id);
3118 return obj->lookupProperty(cx, id, objp, propp);
3121 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
3123 static JSBool
3124 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, jsid id,
3125 JSProperty *prop, Value *vp)
3127 if (!prop) {
3128 /* XXX bad API: no way to tell "not defined" from "void value" */
3129 vp->setUndefined();
3130 return JS_TRUE;
3133 if (obj2->isNative()) {
3134 Shape *shape = (Shape *) prop;
3136 if (shape->isMethod()) {
3137 AutoShapeRooter root(cx, shape);
3138 vp->setObject(shape->methodObject());
3139 return !!obj2->methodReadBarrier(cx, *shape, vp);
3142 /* Peek at the native property's slot value, without doing a Get. */
3143 if (obj2->containsSlot(shape->slot)) {
3144 *vp = obj2->nativeGetSlot(shape->slot);
3145 return true;
3147 } else {
3148 if (obj2->isDenseArray())
3149 return js_GetDenseArrayElementValue(cx, obj2, id, vp);
3150 if (obj2->isProxy()) {
3151 AutoPropertyDescriptorRooter desc(cx);
3152 if (!JSProxy::getPropertyDescriptor(cx, obj2, id, false, &desc))
3153 return false;
3154 if (!(desc.attrs & JSPROP_SHARED)) {
3155 *vp = desc.value;
3156 return true;
3161 /* XXX bad API: no way to return "defined but value unknown" */
3162 vp->setBoolean(true);
3163 return true;
3166 JS_PUBLIC_API(JSBool)
3167 JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3169 JSObject *obj2;
3170 JSProperty *prop;
3171 return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) &&
3172 LookupResult(cx, obj, obj2, id, prop, Valueify(vp));
3175 JS_PUBLIC_API(JSBool)
3176 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3178 return JS_LookupPropertyById(cx, obj, INT_TO_JSID(index), vp);
3181 JS_PUBLIC_API(JSBool)
3182 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3184 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3185 return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3188 JS_PUBLIC_API(JSBool)
3189 JS_LookupUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3191 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3192 return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3195 JS_PUBLIC_API(JSBool)
3196 JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3197 JSObject **objp, jsval *vp)
3199 JSBool ok;
3200 JSProperty *prop;
3202 CHECK_REQUEST(cx);
3203 assertSameCompartment(cx, obj, id);
3204 ok = obj->isNative()
3205 ? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0
3206 : obj->lookupProperty(cx, id, objp, &prop);
3207 return ok && LookupResult(cx, obj, *objp, id, prop, Valueify(vp));
3210 JS_PUBLIC_API(JSBool)
3211 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, uintN flags, jsval *vp)
3213 JSObject *obj2;
3214 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3215 return atom && JS_LookupPropertyWithFlagsById(cx, obj, ATOM_TO_JSID(atom), flags, &obj2, vp);
3218 JS_PUBLIC_API(JSBool)
3219 JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3221 JSObject *obj2;
3222 JSProperty *prop;
3223 JSBool ok = LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3224 &obj2, &prop);
3225 *foundp = (prop != NULL);
3226 return ok;
3229 JS_PUBLIC_API(JSBool)
3230 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3232 return JS_HasPropertyById(cx, obj, INT_TO_JSID(index), foundp);
3235 JS_PUBLIC_API(JSBool)
3236 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3238 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3239 return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3242 JS_PUBLIC_API(JSBool)
3243 JS_HasUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, JSBool *foundp)
3245 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3246 return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3249 JS_PUBLIC_API(JSBool)
3250 JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3252 CHECK_REQUEST(cx);
3253 assertSameCompartment(cx, obj, id);
3255 if (!obj->isNative()) {
3256 JSObject *obj2;
3257 JSProperty *prop;
3259 if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3260 &obj2, &prop)) {
3261 return JS_FALSE;
3263 *foundp = (obj == obj2);
3264 return JS_TRUE;
3267 *foundp = obj->nativeContains(id);
3268 return JS_TRUE;
3271 JS_PUBLIC_API(JSBool)
3272 JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3274 return JS_AlreadyHasOwnPropertyById(cx, obj, INT_TO_JSID(index), foundp);
3277 JS_PUBLIC_API(JSBool)
3278 JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3280 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3281 return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3284 JS_PUBLIC_API(JSBool)
3285 JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3286 JSBool *foundp)
3288 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3289 return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3292 static JSBool
3293 DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value,
3294 PropertyOp getter, StrictPropertyOp setter, uintN attrs,
3295 uintN flags, intN tinyid)
3297 CHECK_REQUEST(cx);
3298 assertSameCompartment(cx, obj, id, value,
3299 (attrs & JSPROP_GETTER)
3300 ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
3301 : NULL,
3302 (attrs & JSPROP_SETTER)
3303 ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
3304 : NULL);
3306 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
3307 if (flags != 0 && obj->isNative()) {
3308 return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter,
3309 attrs, flags, tinyid, NULL);
3311 return obj->defineProperty(cx, id, value, getter, setter, attrs);
3314 JS_PUBLIC_API(JSBool)
3315 JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
3316 JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
3318 return DefinePropertyById(cx, obj, id, Valueify(value), Valueify(getter),
3319 Valueify(setter), attrs, 0, 0);
3322 JS_PUBLIC_API(JSBool)
3323 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
3324 JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
3326 return DefinePropertyById(cx, obj, INT_TO_JSID(index), Valueify(value),
3327 Valueify(getter), Valueify(setter), attrs, 0, 0);
3330 static JSBool
3331 DefineProperty(JSContext *cx, JSObject *obj, const char *name, const Value &value,
3332 PropertyOp getter, StrictPropertyOp setter, uintN attrs,
3333 uintN flags, intN tinyid)
3335 jsid id;
3336 JSAtom *atom;
3338 if (attrs & JSPROP_INDEX) {
3339 id = INT_TO_JSID(intptr_t(name));
3340 atom = NULL;
3341 attrs &= ~JSPROP_INDEX;
3342 } else {
3343 atom = js_Atomize(cx, name, strlen(name), 0);
3344 if (!atom)
3345 return JS_FALSE;
3346 id = ATOM_TO_JSID(atom);
3348 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid);
3351 JS_PUBLIC_API(JSBool)
3352 JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
3353 JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
3355 return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter),
3356 Valueify(setter), attrs, 0, 0);
3359 JS_PUBLIC_API(JSBool)
3360 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, int8 tinyid,
3361 jsval value, JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
3363 return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter),
3364 Valueify(setter), attrs, Shape::HAS_SHORTID, tinyid);
3367 static JSBool
3368 DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3369 const Value &value, PropertyOp getter, StrictPropertyOp setter, uintN attrs,
3370 uintN flags, intN tinyid)
3372 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3373 return atom && DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs,
3374 flags, tinyid);
3377 JS_PUBLIC_API(JSBool)
3378 JS_DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3379 jsval value, JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
3381 return DefineUCProperty(cx, obj, name, namelen, Valueify(value),
3382 Valueify(getter), Valueify(setter), attrs, 0, 0);
3385 JS_PUBLIC_API(JSBool)
3386 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3387 int8 tinyid, jsval value,
3388 JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
3390 return DefineUCProperty(cx, obj, name, namelen, Valueify(value), Valueify(getter),
3391 Valueify(setter), attrs, Shape::HAS_SHORTID, tinyid);
3394 JS_PUBLIC_API(JSBool)
3395 JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp)
3397 CHECK_REQUEST(cx);
3398 assertSameCompartment(cx, obj, id, descriptor);
3399 return js_DefineOwnProperty(cx, obj, id, Valueify(descriptor), bp);
3402 JS_PUBLIC_API(JSObject *)
3403 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp,
3404 JSObject *proto, uintN attrs)
3406 CHECK_REQUEST(cx);
3407 assertSameCompartment(cx, obj, proto);
3409 Class *clasp = Valueify(jsclasp);
3410 if (!clasp)
3411 clasp = &js_ObjectClass; /* default class is Object */
3413 JSObject *nobj = NewObject<WithProto::Class>(cx, clasp, proto, obj);
3414 if (!nobj)
3415 return NULL;
3417 nobj->syncSpecialEquality();
3419 if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
3420 return NULL;
3422 return nobj;
3425 JS_PUBLIC_API(JSBool)
3426 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
3428 JSBool ok;
3429 uintN attrs;
3431 CHECK_REQUEST(cx);
3432 for (ok = JS_TRUE; cds->name; cds++) {
3433 Value value = DoubleValue(cds->dval);
3434 attrs = cds->flags;
3435 if (!attrs)
3436 attrs = JSPROP_READONLY | JSPROP_PERMANENT;
3437 ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
3438 if (!ok)
3439 break;
3441 return ok;
3444 JS_PUBLIC_API(JSBool)
3445 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
3447 JSBool ok;
3449 for (ok = true; ps->name; ps++) {
3450 ok = DefineProperty(cx, obj, ps->name, UndefinedValue(),
3451 Valueify(ps->getter), Valueify(ps->setter),
3452 ps->flags, Shape::HAS_SHORTID, ps->tinyid);
3453 if (!ok)
3454 break;
3456 return ok;
3459 JS_PUBLIC_API(JSBool)
3460 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *alias)
3462 JSObject *obj2;
3463 JSProperty *prop;
3464 JSBool ok;
3465 Shape *shape;
3467 CHECK_REQUEST(cx);
3468 assertSameCompartment(cx, obj);
3470 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3471 if (!atom)
3472 return JS_FALSE;
3473 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
3474 return JS_FALSE;
3475 if (!prop) {
3476 js_ReportIsNotDefined(cx, name);
3477 return JS_FALSE;
3479 if (obj2 != obj || !obj->isNative()) {
3480 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3481 alias, name, obj2->getClass()->name);
3482 return JS_FALSE;
3484 atom = js_Atomize(cx, alias, strlen(alias), 0);
3485 if (!atom) {
3486 ok = JS_FALSE;
3487 } else {
3488 shape = (Shape *)prop;
3489 ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
3490 shape->getter(), shape->setter(), shape->slot,
3491 shape->attributes(), shape->getFlags() | Shape::ALIAS,
3492 shape->shortid)
3493 != NULL);
3495 return ok;
3498 JS_PUBLIC_API(JSBool)
3499 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
3501 JSObject *obj2;
3502 JSProperty *prop;
3503 Shape *shape;
3505 CHECK_REQUEST(cx);
3506 assertSameCompartment(cx, obj);
3508 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3509 if (!atom)
3510 return JS_FALSE;
3511 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
3512 return JS_FALSE;
3513 if (!prop) {
3514 js_ReportIsNotDefined(cx, name);
3515 return JS_FALSE;
3517 if (obj2 != obj || !obj->isNative()) {
3518 char numBuf[12];
3519 JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
3520 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3521 numBuf, name, obj2->getClass()->name);
3522 return JS_FALSE;
3524 shape = (Shape *)prop;
3525 return js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
3526 shape->getter(), shape->setter(), shape->slot,
3527 shape->attributes(), shape->getFlags() | Shape::ALIAS,
3528 shape->shortid)
3529 != NULL;
3532 static JSBool
3533 GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3534 JSBool own, PropertyDescriptor *desc)
3536 JSObject *obj2;
3537 JSProperty *prop;
3539 if (!LookupPropertyById(cx, obj, id, flags, &obj2, &prop))
3540 return JS_FALSE;
3542 if (!prop || (own && obj != obj2)) {
3543 desc->obj = NULL;
3544 desc->attrs = 0;
3545 desc->getter = NULL;
3546 desc->setter = NULL;
3547 desc->value.setUndefined();
3548 return JS_TRUE;
3551 desc->obj = obj2;
3552 if (obj2->isNative()) {
3553 Shape *shape = (Shape *) prop;
3554 desc->attrs = shape->attributes();
3556 if (shape->isMethod()) {
3557 desc->getter = PropertyStub;
3558 desc->setter = StrictPropertyStub;
3559 desc->value.setObject(shape->methodObject());
3560 } else {
3561 desc->getter = shape->getter();
3562 desc->setter = shape->setter();
3563 if (obj2->containsSlot(shape->slot))
3564 desc->value = obj2->nativeGetSlot(shape->slot);
3565 else
3566 desc->value.setUndefined();
3568 } else {
3569 if (obj2->isProxy()) {
3570 JSAutoResolveFlags rf(cx, flags);
3571 return own
3572 ? JSProxy::getOwnPropertyDescriptor(cx, obj2, id, false, desc)
3573 : JSProxy::getPropertyDescriptor(cx, obj2, id, false, desc);
3575 if (!obj2->getAttributes(cx, id, &desc->attrs))
3576 return false;
3577 desc->getter = NULL;
3578 desc->setter = NULL;
3579 desc->value.setUndefined();
3581 return true;
3584 JS_PUBLIC_API(JSBool)
3585 JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3586 JSPropertyDescriptor *desc)
3588 return GetPropertyDescriptorById(cx, obj, id, flags, JS_FALSE, Valueify(desc));
3591 JS_PUBLIC_API(JSBool)
3592 JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *obj, jsid id,
3593 uintN *attrsp, JSBool *foundp,
3594 JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
3596 PropertyDescriptor desc;
3597 if (!GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, JS_FALSE, &desc))
3598 return false;
3600 *attrsp = desc.attrs;
3601 *foundp = (desc.obj != NULL);
3602 if (getterp)
3603 *getterp = Jsvalify(desc.getter);
3604 if (setterp)
3605 *setterp = Jsvalify(desc.setter);
3606 return true;
3609 JS_PUBLIC_API(JSBool)
3610 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3611 uintN *attrsp, JSBool *foundp)
3613 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3614 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3615 attrsp, foundp, NULL, NULL);
3618 JS_PUBLIC_API(JSBool)
3619 JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3620 uintN *attrsp, JSBool *foundp)
3622 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3623 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3624 attrsp, foundp, NULL, NULL);
3627 JS_PUBLIC_API(JSBool)
3628 JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, const char *name,
3629 uintN *attrsp, JSBool *foundp,
3630 JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
3632 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3633 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3634 attrsp, foundp, getterp, setterp);
3637 JS_PUBLIC_API(JSBool)
3638 JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
3639 const jschar *name, size_t namelen,
3640 uintN *attrsp, JSBool *foundp,
3641 JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
3643 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3644 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3645 attrsp, foundp, getterp, setterp);
3648 JS_PUBLIC_API(JSBool)
3649 JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3651 CHECK_REQUEST(cx);
3652 return js_GetOwnPropertyDescriptor(cx, obj, id, Valueify(vp));
3655 static JSBool
3656 SetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, uintN attrs, JSBool *foundp)
3658 JSObject *obj2;
3659 JSProperty *prop;
3661 if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
3662 return false;
3663 if (!prop || obj != obj2) {
3664 *foundp = false;
3665 return true;
3667 JSBool ok = obj->isNative()
3668 ? js_SetNativeAttributes(cx, obj, (Shape *) prop, attrs)
3669 : obj->setAttributes(cx, id, &attrs);
3670 if (ok)
3671 *foundp = true;
3672 return ok;
3675 JS_PUBLIC_API(JSBool)
3676 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3677 uintN attrs, JSBool *foundp)
3679 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3680 return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
3683 JS_PUBLIC_API(JSBool)
3684 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3685 uintN attrs, JSBool *foundp)
3687 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3688 return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
3691 JS_PUBLIC_API(JSBool)
3692 JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3694 CHECK_REQUEST(cx);
3695 assertSameCompartment(cx, obj, id);
3696 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3697 return obj->getProperty(cx, id, Valueify(vp));
3700 JS_PUBLIC_API(JSBool)
3701 JS_GetPropertyByIdDefault(JSContext *cx, JSObject *obj, jsid id, jsval def, jsval *vp)
3703 return GetPropertyDefault(cx, obj, id, Valueify(def), Valueify(vp));
3706 JS_PUBLIC_API(JSBool)
3707 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3709 return JS_GetPropertyById(cx, obj, INT_TO_JSID(index), vp);
3712 JS_PUBLIC_API(JSBool)
3713 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3715 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3716 return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3719 JS_PUBLIC_API(JSBool)
3720 JS_GetPropertyDefault(JSContext *cx, JSObject *obj, const char *name, jsval def, jsval *vp)
3722 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3723 return atom && JS_GetPropertyByIdDefault(cx, obj, ATOM_TO_JSID(atom), def, vp);
3726 JS_PUBLIC_API(JSBool)
3727 JS_GetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3729 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3730 return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3733 JS_PUBLIC_API(JSBool)
3734 JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval *vp)
3736 CHECK_REQUEST(cx);
3737 assertSameCompartment(cx, obj, id);
3738 if (!js_GetMethod(cx, obj, id, JSGET_METHOD_BARRIER, Valueify(vp)))
3739 return JS_FALSE;
3740 if (objp)
3741 *objp = obj;
3742 return JS_TRUE;
3745 JS_PUBLIC_API(JSBool)
3746 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, jsval *vp)
3748 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3749 return atom && JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), objp, vp);
3752 JS_PUBLIC_API(JSBool)
3753 JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3755 CHECK_REQUEST(cx);
3756 assertSameCompartment(cx, obj, id);
3757 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
3758 return obj->setProperty(cx, id, Valueify(vp), false);
3761 JS_PUBLIC_API(JSBool)
3762 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3764 return JS_SetPropertyById(cx, obj, INT_TO_JSID(index), vp);
3767 JS_PUBLIC_API(JSBool)
3768 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3770 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3771 return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3774 JS_PUBLIC_API(JSBool)
3775 JS_SetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3777 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3778 return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3781 JS_PUBLIC_API(JSBool)
3782 JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
3784 CHECK_REQUEST(cx);
3785 assertSameCompartment(cx, obj, id);
3786 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3787 return obj->deleteProperty(cx, id, Valueify(rval), false);
3790 JS_PUBLIC_API(JSBool)
3791 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
3793 return JS_DeletePropertyById2(cx, obj, INT_TO_JSID(index), rval);
3796 JS_PUBLIC_API(JSBool)
3797 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name, jsval *rval)
3799 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3800 return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
3803 JS_PUBLIC_API(JSBool)
3804 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *rval)
3806 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3807 return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
3810 JS_PUBLIC_API(JSBool)
3811 JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id)
3813 jsval junk;
3814 return JS_DeletePropertyById2(cx, obj, id, &junk);
3817 JS_PUBLIC_API(JSBool)
3818 JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
3820 jsval junk;
3821 return JS_DeleteElement2(cx, obj, index, &junk);
3824 JS_PUBLIC_API(JSBool)
3825 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
3827 jsval junk;
3828 return JS_DeleteProperty2(cx, obj, name, &junk);
3831 JS_PUBLIC_API(void)
3832 JS_ClearScope(JSContext *cx, JSObject *obj)
3834 CHECK_REQUEST(cx);
3835 assertSameCompartment(cx, obj);
3837 JSFinalizeOp clearOp = obj->getOps()->clear;
3838 if (clearOp)
3839 clearOp(cx, obj);
3841 if (obj->isNative())
3842 js_ClearNative(cx, obj);
3844 /* Clear cached class objects on the global object. */
3845 if (obj->isGlobal()) {
3846 /* This can return false but that doesn't mean it failed. */
3847 obj->unbrand(cx);
3849 for (int key = JSProto_Null; key < JSProto_LIMIT * 3; key++)
3850 JS_SetReservedSlot(cx, obj, key, JSVAL_VOID);
3852 /* Clear regexp statics. */
3853 RegExpStatics::extractFrom(obj)->clear();
3855 /* Clear the CSP eval-is-allowed cache. */
3856 JS_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_EVAL_ALLOWED, JSVAL_VOID);
3859 * Mark global as cleared. If we try to execute any compile-and-go
3860 * scripts from here on, we will throw.
3862 int32 flags = obj->getReservedSlot(JSRESERVED_GLOBAL_FLAGS).toInt32();
3863 flags |= JSGLOBAL_FLAGS_CLEARED;
3864 JS_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_FLAGS, Jsvalify(Int32Value(flags)));
3867 js_InitRandom(cx);
3870 JS_PUBLIC_API(JSIdArray *)
3871 JS_Enumerate(JSContext *cx, JSObject *obj)
3873 CHECK_REQUEST(cx);
3874 assertSameCompartment(cx, obj);
3876 AutoIdVector props(cx);
3877 JSIdArray *ida;
3878 if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida))
3879 return false;
3880 for (size_t n = 0; n < size_t(ida->length); ++n)
3881 JS_ASSERT(js_CheckForStringIndex(ida->vector[n]) == ida->vector[n]);
3882 return ida;
3886 * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
3887 * prop_iterator_class somehow...
3888 * + preserve the obj->enumerate API while optimizing the native object case
3889 * + native case here uses a Shape *, but that iterates in reverse!
3890 * + so we make non-native match, by reverse-iterating after JS_Enumerating
3892 const uint32 JSSLOT_ITER_INDEX = 0;
3894 static void
3895 prop_iter_finalize(JSContext *cx, JSObject *obj)
3897 void *pdata = obj->getPrivate();
3898 if (!pdata)
3899 return;
3901 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) {
3902 /* Non-native case: destroy the ida enumerated when obj was created. */
3903 JSIdArray *ida = (JSIdArray *) pdata;
3904 JS_DestroyIdArray(cx, ida);
3908 static void
3909 prop_iter_trace(JSTracer *trc, JSObject *obj)
3911 void *pdata = obj->getPrivate();
3912 if (!pdata)
3913 return;
3915 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
3916 /* Native case: just mark the next property to visit. */
3917 ((Shape *) pdata)->trace(trc);
3918 } else {
3919 /* Non-native case: mark each id in the JSIdArray private. */
3920 JSIdArray *ida = (JSIdArray *) pdata;
3921 MarkIdRange(trc, ida->length, ida->vector, "prop iter");
3925 static Class prop_iter_class = {
3926 "PropertyIterator",
3927 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
3928 JSCLASS_MARK_IS_TRACE,
3929 PropertyStub, /* addProperty */
3930 PropertyStub, /* delProperty */
3931 PropertyStub, /* getProperty */
3932 StrictPropertyStub, /* setProperty */
3933 EnumerateStub,
3934 ResolveStub,
3935 ConvertStub,
3936 prop_iter_finalize,
3937 NULL, /* reserved0 */
3938 NULL, /* checkAccess */
3939 NULL, /* call */
3940 NULL, /* construct */
3941 NULL, /* xdrObject */
3942 NULL, /* hasInstance */
3943 JS_CLASS_TRACE(prop_iter_trace)
3946 JS_PUBLIC_API(JSObject *)
3947 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
3949 JSObject *iterobj;
3950 const void *pdata;
3951 jsint index;
3952 JSIdArray *ida;
3954 CHECK_REQUEST(cx);
3955 assertSameCompartment(cx, obj);
3956 iterobj = NewNonFunction<WithProto::Class>(cx, &prop_iter_class, NULL, obj);
3957 if (!iterobj)
3958 return NULL;
3960 if (obj->isNative()) {
3961 /* Native case: start with the last property in obj. */
3962 pdata = obj->lastProperty();
3963 index = -1;
3964 } else {
3966 * Non-native case: enumerate a JSIdArray and keep it via private.
3968 * Note: we have to make sure that we root obj around the call to
3969 * JS_Enumerate to protect against multiple allocations under it.
3971 AutoObjectRooter tvr(cx, iterobj);
3972 ida = JS_Enumerate(cx, obj);
3973 if (!ida)
3974 return NULL;
3975 pdata = ida;
3976 index = ida->length;
3979 /* iterobj cannot escape to other threads here. */
3980 iterobj->setPrivate(const_cast<void *>(pdata));
3981 iterobj->getSlotRef(JSSLOT_ITER_INDEX).setInt32(index);
3982 return iterobj;
3985 JS_PUBLIC_API(JSBool)
3986 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
3988 jsint i;
3989 const Shape *shape;
3990 JSIdArray *ida;
3992 CHECK_REQUEST(cx);
3993 assertSameCompartment(cx, iterobj);
3994 i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
3995 if (i < 0) {
3996 /* Native case: private data is a property tree node pointer. */
3997 JS_ASSERT(iterobj->getParent()->isNative());
3998 shape = (Shape *) iterobj->getPrivate();
4000 while (shape->previous() && (!shape->enumerable() || shape->isAlias()))
4001 shape = shape->previous();
4003 if (!shape->previous()) {
4004 JS_ASSERT(JSID_IS_EMPTY(shape->id));
4005 *idp = JSID_VOID;
4006 } else {
4007 iterobj->setPrivate(const_cast<Shape *>(shape->previous()));
4008 *idp = shape->id;
4010 } else {
4011 /* Non-native case: use the ida enumerated when iterobj was created. */
4012 ida = (JSIdArray *) iterobj->getPrivate();
4013 JS_ASSERT(i <= ida->length);
4014 STATIC_ASSUME(i <= ida->length);
4015 if (i == 0) {
4016 *idp = JSID_VOID;
4017 } else {
4018 *idp = ida->vector[--i];
4019 iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i));
4022 return JS_TRUE;
4025 JS_PUBLIC_API(JSBool)
4026 JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
4028 CHECK_REQUEST(cx);
4029 assertSameCompartment(cx, obj);
4030 return js_GetReservedSlot(cx, obj, index, Valueify(vp));
4033 JS_PUBLIC_API(JSBool)
4034 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
4036 CHECK_REQUEST(cx);
4037 assertSameCompartment(cx, obj, v);
4038 return js_SetReservedSlot(cx, obj, index, Valueify(v));
4041 JS_PUBLIC_API(JSObject *)
4042 JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
4044 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4045 CHECK_REQUEST(cx);
4046 /* NB: jsuint cast does ToUint32. */
4047 assertSameCompartment(cx, JSValueArray(vector, vector ? (jsuint)length : 0));
4048 return NewDenseCopiedArray(cx, (jsuint)length, Valueify(vector));
4051 JS_PUBLIC_API(JSBool)
4052 JS_IsArrayObject(JSContext *cx, JSObject *obj)
4054 assertSameCompartment(cx, obj);
4055 return obj->isArray() ||
4056 (obj->isWrapper() && JSWrapper::wrappedObject(obj)->isArray());
4059 JS_PUBLIC_API(JSBool)
4060 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
4062 CHECK_REQUEST(cx);
4063 assertSameCompartment(cx, obj);
4064 return js_GetLengthProperty(cx, obj, lengthp);
4067 JS_PUBLIC_API(JSBool)
4068 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
4070 CHECK_REQUEST(cx);
4071 assertSameCompartment(cx, obj);
4072 return js_SetLengthProperty(cx, obj, length);
4075 JS_PUBLIC_API(JSBool)
4076 JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
4078 CHECK_REQUEST(cx);
4079 assertSameCompartment(cx, obj);
4080 return js_HasLengthProperty(cx, obj, lengthp);
4083 JS_PUBLIC_API(JSBool)
4084 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
4085 jsval *vp, uintN *attrsp)
4087 CHECK_REQUEST(cx);
4088 assertSameCompartment(cx, obj, id);
4089 return CheckAccess(cx, obj, id, mode, Valueify(vp), attrsp);
4092 #ifdef JS_THREADSAFE
4093 JS_PUBLIC_API(jsrefcount)
4094 JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
4096 return JS_ATOMIC_INCREMENT(&principals->refcount);
4099 JS_PUBLIC_API(jsrefcount)
4100 JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
4102 jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
4103 if (rc == 0)
4104 principals->destroy(cx, principals);
4105 return rc;
4107 #endif
4109 JS_PUBLIC_API(JSSecurityCallbacks *)
4110 JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks)
4112 JSSecurityCallbacks *oldcallbacks;
4114 oldcallbacks = rt->securityCallbacks;
4115 rt->securityCallbacks = callbacks;
4116 return oldcallbacks;
4119 JS_PUBLIC_API(JSSecurityCallbacks *)
4120 JS_GetRuntimeSecurityCallbacks(JSRuntime *rt)
4122 return rt->securityCallbacks;
4125 JS_PUBLIC_API(JSSecurityCallbacks *)
4126 JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks)
4128 JSSecurityCallbacks *oldcallbacks;
4130 oldcallbacks = cx->securityCallbacks;
4131 cx->securityCallbacks = callbacks;
4132 return oldcallbacks;
4135 JS_PUBLIC_API(JSSecurityCallbacks *)
4136 JS_GetSecurityCallbacks(JSContext *cx)
4138 return cx->securityCallbacks
4139 ? cx->securityCallbacks
4140 : cx->runtime->securityCallbacks;
4143 JS_PUBLIC_API(JSFunction *)
4144 JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
4145 JSObject *parent, const char *name)
4147 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4148 JSAtom *atom;
4150 CHECK_REQUEST(cx);
4151 assertSameCompartment(cx, parent);
4153 if (!name) {
4154 atom = NULL;
4155 } else {
4156 atom = js_Atomize(cx, name, strlen(name), 0);
4157 if (!atom)
4158 return NULL;
4160 return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, atom);
4163 JS_PUBLIC_API(JSFunction *)
4164 JS_NewFunctionById(JSContext *cx, JSNative native, uintN nargs, uintN flags, JSObject *parent,
4165 jsid id)
4167 JS_ASSERT(JSID_IS_STRING(id));
4168 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4169 CHECK_REQUEST(cx);
4170 assertSameCompartment(cx, parent);
4172 return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, JSID_TO_ATOM(id));
4175 JS_PUBLIC_API(JSObject *)
4176 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
4178 CHECK_REQUEST(cx);
4179 assertSameCompartment(cx, parent); // XXX no funobj for now
4180 if (!parent) {
4181 if (cx->hasfp())
4182 parent = GetScopeChain(cx, cx->fp());
4183 if (!parent)
4184 parent = cx->globalObject;
4185 JS_ASSERT(parent);
4188 if (funobj->getClass() != &js_FunctionClass) {
4190 * We cannot clone this object, so fail (we used to return funobj, bad
4191 * idea, but we changed incompatibly to teach any abusers a lesson!).
4193 Value v = ObjectValue(*funobj);
4194 js_ReportIsNotFunction(cx, &v, 0);
4195 return NULL;
4198 JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
4199 if (!FUN_FLAT_CLOSURE(fun))
4200 return CloneFunctionObject(cx, fun, parent);
4203 * A flat closure carries its own environment, so why clone it? In case
4204 * someone wants to mutate its fixed slots or add ad-hoc properties. API
4205 * compatibility suggests we not return funobj and let callers mutate the
4206 * returned object at will.
4208 * But it's worse than that: API compatibility according to the test for
4209 * bug 300079 requires we get "upvars" from parent and its ancestors! So
4210 * we do that (grudgingly!). The scope chain ancestors are searched as if
4211 * they were activations, respecting the skip field in each upvar's cookie
4212 * but looking up the property by name instead of frame slot.
4214 JSObject *clone = js_AllocFlatClosure(cx, fun, parent);
4215 if (!clone)
4216 return NULL;
4218 JSUpvarArray *uva = fun->u.i.script->upvars();
4219 uint32 i = uva->length;
4220 JS_ASSERT(i != 0);
4222 for (Shape::Range r(fun->script()->bindings.lastUpvar()); i-- != 0; r.popFront()) {
4223 JSObject *obj = parent;
4224 int skip = uva->vector[i].level();
4225 while (--skip > 0) {
4226 if (!obj) {
4227 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4228 JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
4229 return NULL;
4231 obj = obj->getParent();
4234 if (!obj->getProperty(cx, r.front().id, clone->getFlatClosureUpvars() + i))
4235 return NULL;
4238 return clone;
4241 JS_PUBLIC_API(JSObject *)
4242 JS_GetFunctionObject(JSFunction *fun)
4244 return FUN_OBJECT(fun);
4247 JS_PUBLIC_API(JSString *)
4248 JS_GetFunctionId(JSFunction *fun)
4250 return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
4253 JS_PUBLIC_API(uintN)
4254 JS_GetFunctionFlags(JSFunction *fun)
4256 return fun->flags;
4259 JS_PUBLIC_API(uint16)
4260 JS_GetFunctionArity(JSFunction *fun)
4262 return fun->nargs;
4265 JS_PUBLIC_API(JSBool)
4266 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
4268 return obj->getClass() == &js_FunctionClass;
4271 JS_PUBLIC_API(JSBool)
4272 JS_ObjectIsCallable(JSContext *cx, JSObject *obj)
4274 return obj->isCallable();
4277 static JSBool
4278 js_generic_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp)
4280 JSFunctionSpec *fs = (JSFunctionSpec *) vp->toObject().getReservedSlot(0).toPrivate();
4281 JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
4283 if (argc < 1) {
4284 js_ReportMissingArg(cx, *vp, 0);
4285 return JS_FALSE;
4289 * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
4290 * which is almost always the class constructor object, e.g. Array. Then
4291 * call the corresponding prototype native method with our first argument
4292 * passed as |this|.
4294 memmove(vp + 1, vp + 2, argc * sizeof(jsval));
4296 /* Clear the last parameter in case too few arguments were passed. */
4297 vp[2 + --argc].setUndefined();
4299 Native native =
4300 #ifdef JS_TRACER
4301 (fs->flags & JSFUN_TRCINFO)
4302 ? JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native
4304 #endif
4305 Valueify(fs->call);
4306 return native(cx, argc, vp);
4309 JS_PUBLIC_API(JSBool)
4310 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
4312 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4313 uintN flags;
4314 JSObject *ctor;
4315 JSFunction *fun;
4317 CHECK_REQUEST(cx);
4318 assertSameCompartment(cx, obj);
4319 ctor = NULL;
4320 for (; fs->name; fs++) {
4321 flags = fs->flags;
4324 * Define a generic arity N+1 static method for the arity N prototype
4325 * method if flags contains JSFUN_GENERIC_NATIVE.
4327 if (flags & JSFUN_GENERIC_NATIVE) {
4328 if (!ctor) {
4329 ctor = JS_GetConstructor(cx, obj);
4330 if (!ctor)
4331 return JS_FALSE;
4334 flags &= ~JSFUN_GENERIC_NATIVE;
4335 fun = JS_DefineFunction(cx, ctor, fs->name,
4336 Jsvalify(js_generic_native_method_dispatcher),
4337 fs->nargs + 1,
4338 flags & ~JSFUN_TRCINFO);
4339 if (!fun)
4340 return JS_FALSE;
4343 * As jsapi.h notes, fs must point to storage that lives as long
4344 * as fun->object lives.
4346 Value priv = PrivateValue(fs);
4347 if (!js_SetReservedSlot(cx, FUN_OBJECT(fun), 0, priv))
4348 return JS_FALSE;
4351 fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
4352 if (!fun)
4353 return JS_FALSE;
4355 return JS_TRUE;
4358 JS_PUBLIC_API(JSFunction *)
4359 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
4360 uintN nargs, uintN attrs)
4362 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4363 CHECK_REQUEST(cx);
4364 assertSameCompartment(cx, obj);
4365 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
4366 if (!atom)
4367 return NULL;
4368 return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs);
4371 JS_PUBLIC_API(JSFunction *)
4372 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
4373 const jschar *name, size_t namelen, JSNative call,
4374 uintN nargs, uintN attrs)
4376 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4377 CHECK_REQUEST(cx);
4378 assertSameCompartment(cx, obj);
4379 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
4380 if (!atom)
4381 return NULL;
4382 return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs);
4385 extern JS_PUBLIC_API(JSFunction *)
4386 JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call,
4387 uintN nargs, uintN attrs)
4389 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4390 CHECK_REQUEST(cx);
4391 assertSameCompartment(cx, obj);
4392 return js_DefineFunction(cx, obj, id, Valueify(call), nargs, attrs);
4395 inline static void
4396 LAST_FRAME_EXCEPTION_CHECK(JSContext *cx, bool result)
4398 if (!result && !cx->hasRunOption(JSOPTION_DONT_REPORT_UNCAUGHT))
4399 js_ReportUncaughtException(cx);
4402 inline static void
4403 LAST_FRAME_CHECKS(JSContext *cx, bool result)
4405 if (!JS_IsRunning(cx)) {
4406 LAST_FRAME_EXCEPTION_CHECK(cx, result);
4410 inline static uint32
4411 JS_OPTIONS_TO_TCFLAGS(JSContext *cx)
4413 return (cx->hasRunOption(JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) |
4414 (cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0);
4417 static JSScript *
4418 CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4419 const jschar *chars, size_t length,
4420 const char *filename, uintN lineno, JSVersion version)
4422 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4423 CHECK_REQUEST(cx);
4424 assertSameCompartment(cx, obj, principals);
4426 uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4427 JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
4428 chars, length, filename, lineno, version);
4429 if (script && !js_NewScriptObject(cx, script)) {
4430 js_DestroyScript(cx, script);
4431 script = NULL;
4433 LAST_FRAME_CHECKS(cx, script);
4434 return script;
4437 extern JS_PUBLIC_API(JSScript *)
4438 JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4439 JSPrincipals *principals,
4440 const jschar *chars, size_t length,
4441 const char *filename, uintN lineno,
4442 JSVersion version)
4444 AutoVersionAPI avi(cx, version);
4445 return CompileUCScriptForPrincipalsCommon(cx, obj, principals, chars, length, filename, lineno,
4446 avi.version());
4449 JS_PUBLIC_API(JSScript *)
4450 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4451 const jschar *chars, size_t length,
4452 const char *filename, uintN lineno)
4454 return CompileUCScriptForPrincipalsCommon(cx, obj, principals, chars, length, filename, lineno,
4455 cx->findVersion());
4458 JS_PUBLIC_API(JSScript *)
4459 JS_CompileUCScript(JSContext *cx, JSObject *obj, const jschar *chars, size_t length,
4460 const char *filename, uintN lineno)
4462 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4463 return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno);
4466 JS_PUBLIC_API(JSScript *)
4467 JS_CompileScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4468 JSPrincipals *principals,
4469 const char *bytes, size_t length,
4470 const char *filename, uintN lineno,
4471 JSVersion version)
4473 AutoVersionAPI ava(cx, version);
4474 return JS_CompileScriptForPrincipals(cx, obj, principals, bytes, length, filename, lineno);
4477 JS_PUBLIC_API(JSScript *)
4478 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
4479 JSPrincipals *principals,
4480 const char *bytes, size_t length,
4481 const char *filename, uintN lineno)
4483 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4484 CHECK_REQUEST(cx);
4486 jschar *chars = js_InflateString(cx, bytes, &length);
4487 if (!chars)
4488 return NULL;
4489 JSScript *script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno);
4490 cx->free(chars);
4491 return script;
4494 JS_PUBLIC_API(JSScript *)
4495 JS_CompileScript(JSContext *cx, JSObject *obj, const char *bytes, size_t length,
4496 const char *filename, uintN lineno)
4498 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4499 return JS_CompileScriptForPrincipals(cx, obj, NULL, bytes, length, filename, lineno);
4502 JS_PUBLIC_API(JSBool)
4503 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, const char *bytes, size_t length)
4505 jschar *chars;
4506 JSBool result;
4507 JSExceptionState *exnState;
4508 JSErrorReporter older;
4510 CHECK_REQUEST(cx);
4511 assertSameCompartment(cx, obj);
4512 chars = js_InflateString(cx, bytes, &length);
4513 if (!chars)
4514 return JS_TRUE;
4517 * Return true on any out-of-memory error, so our caller doesn't try to
4518 * collect more buffered source.
4520 result = JS_TRUE;
4521 exnState = JS_SaveExceptionState(cx);
4523 Parser parser(cx);
4524 if (parser.init(chars, length, NULL, 1, cx->findVersion())) {
4525 older = JS_SetErrorReporter(cx, NULL);
4526 if (!parser.parse(obj) &&
4527 parser.tokenStream.isUnexpectedEOF()) {
4529 * We ran into an error. If it was because we ran out of
4530 * source, we return false so our caller knows to try to
4531 * collect more buffered source.
4533 result = JS_FALSE;
4535 JS_SetErrorReporter(cx, older);
4538 cx->free(chars);
4539 JS_RestoreExceptionState(cx, exnState);
4540 return result;
4543 /* Use the fastest available getc. */
4544 #if defined(HAVE_GETC_UNLOCKED)
4545 # define fast_getc getc_unlocked
4546 #elif defined(HAVE__GETC_NOLOCK)
4547 # define fast_getc _getc_nolock
4548 #else
4549 # define fast_getc getc
4550 #endif
4552 static JSScript *
4553 CompileFileHelper(JSContext *cx, JSObject *obj, JSPrincipals *principals, uint32 tcflags,
4554 const char* filename, FILE *fp)
4556 struct stat st;
4557 int ok = fstat(fileno(fp), &st);
4558 if (ok != 0)
4559 return NULL;
4561 jschar *buf = NULL;
4562 size_t len = st.st_size;
4563 size_t i = 0;
4564 JSScript *script;
4566 /* Read in the whole file, then compile it. */
4567 if (fp == stdin) {
4568 JS_ASSERT(len == 0);
4569 len = 8; /* start with a small buffer, expand as necessary */
4570 int c;
4571 bool hitEOF = false;
4572 while (!hitEOF) {
4573 len *= 2;
4574 jschar* tmpbuf = (jschar *) cx->realloc(buf, len * sizeof(jschar));
4575 if (!tmpbuf) {
4576 cx->free(buf);
4577 return NULL;
4579 buf = tmpbuf;
4581 while (i < len) {
4582 c = fast_getc(fp);
4583 if (c == EOF) {
4584 hitEOF = true;
4585 break;
4587 buf[i++] = (jschar) (unsigned char) c;
4590 } else {
4591 buf = (jschar *) cx->malloc(len * sizeof(jschar));
4592 if (!buf)
4593 return NULL;
4595 int c;
4596 while ((c = fast_getc(fp)) != EOF)
4597 buf[i++] = (jschar) (unsigned char) c;
4600 JS_ASSERT(i <= len);
4601 len = i;
4602 script = Compiler::compileScript(cx, obj, NULL, principals, tcflags, buf, len, filename, 1,
4603 cx->findVersion());
4604 cx->free(buf);
4605 return script;
4608 JS_PUBLIC_API(JSScript *)
4609 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
4611 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4612 FILE *fp;
4613 uint32 tcflags;
4614 JSScript *script;
4616 CHECK_REQUEST(cx);
4617 assertSameCompartment(cx, obj);
4618 if (!filename || strcmp(filename, "-") == 0) {
4619 fp = stdin;
4620 } else {
4621 fp = fopen(filename, "r");
4622 if (!fp) {
4623 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
4624 filename, "No such file or directory");
4625 return NULL;
4629 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4630 script = CompileFileHelper(cx, obj, NULL, tcflags, filename, fp);
4632 if (fp != stdin)
4633 fclose(fp);
4634 if (script && !js_NewScriptObject(cx, script)) {
4635 js_DestroyScript(cx, script);
4636 script = NULL;
4638 LAST_FRAME_CHECKS(cx, script);
4639 return script;
4642 JS_PUBLIC_API(JSScript *)
4643 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *filename, FILE *file,
4644 JSPrincipals *principals)
4646 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4647 uint32 tcflags;
4648 JSScript *script;
4650 CHECK_REQUEST(cx);
4651 assertSameCompartment(cx, obj, principals);
4652 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4653 script = CompileFileHelper(cx, obj, principals, tcflags, filename, file);
4655 if (script && !js_NewScriptObject(cx, script)) {
4656 js_DestroyScript(cx, script);
4657 script = NULL;
4659 LAST_FRAME_CHECKS(cx, script);
4660 return script;
4663 JS_PUBLIC_API(JSScript *)
4664 JS_CompileFileHandleForPrincipalsVersion(JSContext *cx, JSObject *obj, const char *filename,
4665 FILE *file, JSPrincipals *principals, JSVersion version)
4667 AutoVersionAPI ava(cx, version);
4668 return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, principals);
4671 JS_PUBLIC_API(JSScript *)
4672 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *file)
4674 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4675 return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
4678 JS_PUBLIC_API(JSObject *)
4679 JS_NewScriptObject(JSContext *cx, JSScript *script)
4681 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4682 CHECK_REQUEST(cx);
4683 assertSameCompartment(cx, script);
4684 if (!script)
4685 return NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
4688 * This function should only ever be applied to JSScripts that had
4689 * script objects allocated for them when they were created, as
4690 * described in the comment for JSScript::u.object.
4692 JS_ASSERT(script->u.object);
4693 return script->u.object;
4696 JS_PUBLIC_API(JSObject *)
4697 JS_GetScriptObject(JSScript *script)
4700 * This function should only ever be applied to JSScripts that had
4701 * script objects allocated for them when they were created, as
4702 * described in the comment for JSScript::u.object.
4704 JS_ASSERT(script->u.object);
4705 return script->u.object;
4708 JS_PUBLIC_API(void)
4709 JS_DestroyScript(JSContext *cx, JSScript *script)
4711 CHECK_REQUEST(cx);
4714 * Originally, JSScript lifetimes were managed explicitly, and this function
4715 * was used to free a JSScript. Now, this function does nothing, and the
4716 * garbage collector manages JSScripts; you must root the JSScript's script
4717 * object (obtained via JS_GetScriptObject) to keep it alive.
4719 * However, since the script objects have taken over this responsibility, it
4720 * follows that every script passed here must have a script object.
4722 JS_ASSERT(script->u.object);
4725 static JSFunction *
4726 CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj,
4727 JSPrincipals *principals, const char *name,
4728 uintN nargs, const char **argnames,
4729 const jschar *chars, size_t length,
4730 const char *filename, uintN lineno, JSVersion version)
4732 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4733 JSFunction *fun;
4734 JSAtom *funAtom, *argAtom;
4735 uintN i;
4737 CHECK_REQUEST(cx);
4738 assertSameCompartment(cx, obj, principals);
4739 if (!name) {
4740 funAtom = NULL;
4741 } else {
4742 funAtom = js_Atomize(cx, name, strlen(name), 0);
4743 if (!funAtom) {
4744 fun = NULL;
4745 goto out2;
4749 fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
4750 if (!fun)
4751 goto out2;
4754 AutoObjectRooter tvr(cx, FUN_OBJECT(fun));
4755 MUST_FLOW_THROUGH("out");
4757 Bindings bindings(cx);
4758 AutoBindingsRooter root(cx, bindings);
4759 for (i = 0; i < nargs; i++) {
4760 argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
4761 if (!argAtom) {
4762 fun = NULL;
4763 goto out2;
4766 uint16 dummy;
4767 if (!bindings.addArgument(cx, argAtom, &dummy)) {
4768 fun = NULL;
4769 goto out2;
4773 if (!Compiler::compileFunctionBody(cx, fun, principals, &bindings,
4774 chars, length, filename, lineno, version)) {
4775 fun = NULL;
4776 goto out2;
4779 if (obj && funAtom &&
4780 !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), ObjectValue(*fun),
4781 NULL, NULL, JSPROP_ENUMERATE)) {
4782 fun = NULL;
4785 #ifdef JS_SCOPE_DEPTH_METER
4786 if (fun && obj) {
4787 JSObject *pobj = obj;
4788 uintN depth = 1;
4790 while ((pobj = pobj->getParent()) != NULL)
4791 ++depth;
4792 JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
4794 #endif
4797 out2:
4798 LAST_FRAME_CHECKS(cx, fun);
4799 return fun;
4801 JS_PUBLIC_API(JSFunction *)
4802 JS_CompileUCFunctionForPrincipalsVersion(JSContext *cx, JSObject *obj,
4803 JSPrincipals *principals, const char *name,
4804 uintN nargs, const char **argnames,
4805 const jschar *chars, size_t length,
4806 const char *filename, uintN lineno,
4807 JSVersion version)
4809 AutoVersionAPI avi(cx, version);
4810 return CompileUCFunctionForPrincipalsCommon(cx, obj, principals, name, nargs, argnames, chars,
4811 length, filename, lineno, avi.version());
4814 JS_PUBLIC_API(JSFunction *)
4815 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
4816 JSPrincipals *principals, const char *name,
4817 uintN nargs, const char **argnames,
4818 const jschar *chars, size_t length,
4819 const char *filename, uintN lineno)
4821 return CompileUCFunctionForPrincipalsCommon(cx, obj, principals, name, nargs, argnames, chars,
4822 length, filename, lineno, cx->findVersion());
4825 JS_PUBLIC_API(JSFunction *)
4826 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
4827 uintN nargs, const char **argnames,
4828 const jschar *chars, size_t length,
4829 const char *filename, uintN lineno)
4831 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4832 return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames,
4833 chars, length, filename, lineno);
4836 JS_PUBLIC_API(JSFunction *)
4837 JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
4838 JSPrincipals *principals, const char *name,
4839 uintN nargs, const char **argnames,
4840 const char *bytes, size_t length,
4841 const char *filename, uintN lineno)
4843 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4844 jschar *chars = js_InflateString(cx, bytes, &length);
4845 if (!chars)
4846 return NULL;
4847 JSFunction *fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
4848 nargs, argnames, chars, length,
4849 filename, lineno);
4850 cx->free(chars);
4851 return fun;
4854 JS_PUBLIC_API(JSFunction *)
4855 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
4856 uintN nargs, const char **argnames,
4857 const char *bytes, size_t length,
4858 const char *filename, uintN lineno)
4860 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4861 return JS_CompileFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames, bytes, length,
4862 filename, lineno);
4865 JS_PUBLIC_API(JSString *)
4866 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, uintN indent)
4868 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4869 JSPrinter *jp;
4870 JSString *str;
4872 CHECK_REQUEST(cx);
4873 #ifdef DEBUG
4874 if (cx->compartment != script->compartment)
4875 CompartmentChecker::fail(cx->compartment, script->compartment);
4876 #endif
4877 jp = js_NewPrinter(cx, name, NULL,
4878 indent & ~JS_DONT_PRETTY_PRINT,
4879 !(indent & JS_DONT_PRETTY_PRINT),
4880 false, false);
4881 if (!jp)
4882 return NULL;
4883 if (js_DecompileScript(jp, script))
4884 str = js_GetPrinterOutput(jp);
4885 else
4886 str = NULL;
4887 js_DestroyPrinter(jp);
4888 return str;
4891 JS_PUBLIC_API(JSString *)
4892 JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
4894 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4895 CHECK_REQUEST(cx);
4896 assertSameCompartment(cx, fun);
4897 return js_DecompileToString(cx, "JS_DecompileFunction", fun,
4898 indent & ~JS_DONT_PRETTY_PRINT,
4899 !(indent & JS_DONT_PRETTY_PRINT),
4900 false, false, js_DecompileFunction);
4903 JS_PUBLIC_API(JSString *)
4904 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
4906 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4907 CHECK_REQUEST(cx);
4908 assertSameCompartment(cx, fun);
4909 return js_DecompileToString(cx, "JS_DecompileFunctionBody", fun,
4910 indent & ~JS_DONT_PRETTY_PRINT,
4911 !(indent & JS_DONT_PRETTY_PRINT),
4912 false, false, js_DecompileFunctionBody);
4915 JS_PUBLIC_API(JSBool)
4916 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
4918 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4919 JSBool ok;
4921 CHECK_REQUEST(cx);
4922 assertSameCompartment(cx, obj, script);
4923 /* This should receive only scripts handed out via the JSAPI. */
4924 JS_ASSERT(script->u.object);
4925 ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
4926 LAST_FRAME_CHECKS(cx, ok);
4927 return ok;
4930 JS_PUBLIC_API(JSBool)
4931 JS_ExecuteScriptVersion(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval,
4932 JSVersion version)
4934 AutoVersionAPI ava(cx, version);
4935 return JS_ExecuteScript(cx, obj, script, rval);
4938 bool
4939 EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj,
4940 JSPrincipals *principals,
4941 const jschar *chars, uintN length,
4942 const char *filename, uintN lineno,
4943 jsval *rval, JSVersion compileVersion)
4945 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4947 CHECK_REQUEST(cx);
4948 JSScript *script = Compiler::compileScript(cx, obj, NULL, principals,
4949 !rval
4950 ? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
4951 : TCF_COMPILE_N_GO,
4952 chars, length, filename, lineno, compileVersion);
4953 if (!script) {
4954 LAST_FRAME_CHECKS(cx, script);
4955 return false;
4957 JS_ASSERT(script->getVersion() == compileVersion);
4958 bool ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
4959 LAST_FRAME_CHECKS(cx, ok);
4960 js_DestroyScript(cx, script);
4961 return ok;
4965 JS_PUBLIC_API(JSBool)
4966 JS_EvaluateUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4967 JSPrincipals *principals,
4968 const jschar *chars, uintN length,
4969 const char *filename, uintN lineno,
4970 jsval *rval, JSVersion version)
4972 AutoVersionAPI avi(cx, version);
4973 return EvaluateUCScriptForPrincipalsCommon(cx, obj, principals, chars, length,
4974 filename, lineno, rval, avi.version());
4977 JS_PUBLIC_API(JSBool)
4978 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
4979 JSPrincipals *principals,
4980 const jschar *chars, uintN length,
4981 const char *filename, uintN lineno,
4982 jsval *rval)
4984 return EvaluateUCScriptForPrincipalsCommon(cx, obj, principals, chars, length,
4985 filename, lineno, rval, cx->findVersion());
4988 JS_PUBLIC_API(JSBool)
4989 JS_EvaluateUCScript(JSContext *cx, JSObject *obj, const jschar *chars, uintN length,
4990 const char *filename, uintN lineno, jsval *rval)
4992 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4993 return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno, rval);
4996 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
4997 JS_PUBLIC_API(JSBool)
4998 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4999 const char *bytes, uintN nbytes,
5000 const char *filename, uintN lineno, jsval *rval)
5002 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5003 size_t length = nbytes;
5004 jschar *chars = js_InflateString(cx, bytes, &length);
5005 if (!chars)
5006 return JS_FALSE;
5007 JSBool ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
5008 filename, lineno, rval);
5009 cx->free(chars);
5010 return ok;
5013 JS_PUBLIC_API(JSBool)
5014 JS_EvaluateScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, JSPrincipals *principals,
5015 const char *bytes, uintN nbytes,
5016 const char *filename, uintN lineno, jsval *rval, JSVersion version)
5018 AutoVersionAPI avi(cx, version);
5019 return JS_EvaluateScriptForPrincipals(cx, obj, principals, bytes, nbytes, filename, lineno,
5020 rval);
5023 JS_PUBLIC_API(JSBool)
5024 JS_EvaluateScript(JSContext *cx, JSObject *obj, const char *bytes, uintN nbytes,
5025 const char *filename, uintN lineno, jsval *rval)
5027 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5028 return JS_EvaluateScriptForPrincipals(cx, obj, NULL, bytes, nbytes, filename, lineno, rval);
5031 JS_PUBLIC_API(JSBool)
5032 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, jsval *argv,
5033 jsval *rval)
5035 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5036 CHECK_REQUEST(cx);
5037 assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc));
5038 JSBool ok = ExternalInvoke(cx, ObjectOrNullValue(obj), ObjectValue(*fun), argc,
5039 Valueify(argv), Valueify(rval));
5040 LAST_FRAME_CHECKS(cx, ok);
5041 return ok;
5044 JS_PUBLIC_API(JSBool)
5045 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, jsval *argv,
5046 jsval *rval)
5048 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5049 CHECK_REQUEST(cx);
5050 assertSameCompartment(cx, obj, JSValueArray(argv, argc));
5052 AutoValueRooter tvr(cx);
5053 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
5054 JSBool ok =
5055 atom &&
5056 js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, tvr.addr()) &&
5057 ExternalInvoke(cx, ObjectOrNullValue(obj), tvr.value(), argc, Valueify(argv),
5058 Valueify(rval));
5059 LAST_FRAME_CHECKS(cx, ok);
5060 return ok;
5063 JS_PUBLIC_API(JSBool)
5064 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, jsval *argv,
5065 jsval *rval)
5067 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5069 CHECK_REQUEST(cx);
5070 assertSameCompartment(cx, obj, fval, JSValueArray(argv, argc));
5071 JSBool ok = ExternalInvoke(cx, ObjectOrNullValue(obj), Valueify(fval), argc, Valueify(argv),
5072 Valueify(rval));
5073 LAST_FRAME_CHECKS(cx, ok);
5074 return ok;
5077 namespace JS {
5079 JS_PUBLIC_API(bool)
5080 Call(JSContext *cx, jsval thisv, jsval fval, uintN argc, jsval *argv, jsval *rval)
5082 JSBool ok;
5084 CHECK_REQUEST(cx);
5085 assertSameCompartment(cx, thisv, fval, JSValueArray(argv, argc));
5086 ok = ExternalInvoke(cx, Valueify(thisv), Valueify(fval), argc, Valueify(argv), Valueify(rval));
5087 LAST_FRAME_CHECKS(cx, ok);
5088 return ok;
5091 } // namespace JS
5093 JS_PUBLIC_API(JSObject *)
5094 JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv)
5096 CHECK_REQUEST(cx);
5097 assertSameCompartment(cx, ctor, JSValueArray(argv, argc));
5099 // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
5100 // is not a simple variation of JSOP_CALL. We have to determine what class
5101 // of object to create, create it, and clamp the return value to an object,
5102 // among other details. js_InvokeConstructor does the hard work.
5103 InvokeArgsGuard args;
5104 if (!cx->stack().pushInvokeArgs(cx, argc, &args))
5105 return NULL;
5107 args.callee().setObject(*ctor);
5108 args.thisv().setNull();
5109 memcpy(args.argv(), argv, argc * sizeof(jsval));
5111 bool ok = InvokeConstructor(cx, args);
5113 JSObject *obj = NULL;
5114 if (ok) {
5115 if (args.rval().isObject()) {
5116 obj = &args.rval().toObject();
5117 } else {
5119 * Although constructors may return primitives (via proxies), this
5120 * API is asking for an object, so we report an error.
5122 JSAutoByteString bytes;
5123 if (js_ValueToPrintable(cx, args.rval(), &bytes)) {
5124 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_NEW_RESULT,
5125 bytes.ptr());
5130 LAST_FRAME_CHECKS(cx, ok);
5131 return obj;
5134 JS_PUBLIC_API(JSOperationCallback)
5135 JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback)
5137 #ifdef JS_THREADSAFE
5138 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
5139 #endif
5140 JSOperationCallback old = cx->operationCallback;
5141 cx->operationCallback = callback;
5142 return old;
5145 JS_PUBLIC_API(JSOperationCallback)
5146 JS_GetOperationCallback(JSContext *cx)
5148 return cx->operationCallback;
5151 JS_PUBLIC_API(void)
5152 JS_TriggerOperationCallback(JSContext *cx)
5154 #ifdef JS_THREADSAFE
5155 AutoLockGC lock(cx->runtime);
5156 #endif
5157 TriggerOperationCallback(cx);
5160 JS_PUBLIC_API(void)
5161 JS_TriggerAllOperationCallbacks(JSRuntime *rt)
5163 #ifdef JS_THREADSAFE
5164 AutoLockGC lock(rt);
5165 #endif
5166 TriggerAllOperationCallbacks(rt);
5169 JS_PUBLIC_API(JSBool)
5170 JS_IsRunning(JSContext *cx)
5173 * The use of cx->fp below is safe. Rationale: Here we don't care if the
5174 * interpreter state is stale. We just want to know if there *is* any
5175 * interpreter state.
5177 VOUCH_DOES_NOT_REQUIRE_STACK();
5179 #ifdef JS_TRACER
5180 JS_ASSERT_IF(JS_ON_TRACE(cx) && JS_TRACE_MONITOR_ON_TRACE(cx)->tracecx == cx, cx->hasfp());
5181 #endif
5182 JSStackFrame *fp = cx->maybefp();
5183 while (fp && fp->isDummyFrame())
5184 fp = fp->prev();
5185 return fp != NULL;
5188 JS_PUBLIC_API(JSStackFrame *)
5189 JS_SaveFrameChain(JSContext *cx)
5191 CHECK_REQUEST(cx);
5192 JSStackFrame *fp = js_GetTopStackFrame(cx);
5193 if (!fp)
5194 return NULL;
5195 cx->saveActiveSegment();
5196 return fp;
5199 JS_PUBLIC_API(void)
5200 JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
5202 CHECK_REQUEST(cx);
5203 JS_ASSERT_NOT_ON_TRACE(cx);
5204 JS_ASSERT(!cx->hasfp());
5205 if (!fp)
5206 return;
5207 cx->restoreSegment();
5210 /************************************************************************/
5211 JS_PUBLIC_API(JSString *)
5212 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
5214 CHECK_REQUEST(cx);
5215 return js_NewStringCopyN(cx, s, n);
5218 JS_PUBLIC_API(JSString *)
5219 JS_NewStringCopyZ(JSContext *cx, const char *s)
5221 size_t n;
5222 jschar *js;
5223 JSString *str;
5225 CHECK_REQUEST(cx);
5226 if (!s)
5227 return cx->runtime->emptyString;
5228 n = strlen(s);
5229 js = js_InflateString(cx, s, &n);
5230 if (!js)
5231 return NULL;
5232 str = js_NewString(cx, js, n);
5233 if (!str)
5234 cx->free(js);
5235 return str;
5238 JS_PUBLIC_API(JSBool)
5239 JS_StringHasBeenInterned(JSString *str)
5241 return str->isAtomized();
5244 JS_PUBLIC_API(JSString *)
5245 JS_InternJSString(JSContext *cx, JSString *str)
5247 CHECK_REQUEST(cx);
5248 JSAtom *atom = js_AtomizeString(cx, str, 0);
5249 if (!atom)
5250 return NULL;
5251 return ATOM_TO_STRING(atom);
5254 JS_PUBLIC_API(JSString *)
5255 JS_InternString(JSContext *cx, const char *s)
5257 JSAtom *atom;
5259 CHECK_REQUEST(cx);
5260 atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
5261 if (!atom)
5262 return NULL;
5263 return ATOM_TO_STRING(atom);
5266 JS_PUBLIC_API(JSString *)
5267 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
5269 CHECK_REQUEST(cx);
5270 return js_NewString(cx, chars, length);
5273 JS_PUBLIC_API(JSString *)
5274 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
5276 CHECK_REQUEST(cx);
5277 return js_NewStringCopyN(cx, s, n);
5280 JS_PUBLIC_API(JSString *)
5281 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
5283 CHECK_REQUEST(cx);
5284 if (!s)
5285 return cx->runtime->emptyString;
5286 return js_NewStringCopyZ(cx, s);
5289 JS_PUBLIC_API(JSString *)
5290 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
5292 JSAtom *atom;
5294 CHECK_REQUEST(cx);
5295 atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
5296 if (!atom)
5297 return NULL;
5298 return ATOM_TO_STRING(atom);
5301 JS_PUBLIC_API(JSString *)
5302 JS_InternUCString(JSContext *cx, const jschar *s)
5304 return JS_InternUCStringN(cx, s, js_strlen(s));
5307 JS_PUBLIC_API(size_t)
5308 JS_GetStringLength(JSString *str)
5310 return str->length();
5313 JS_PUBLIC_API(const jschar *)
5314 JS_GetStringCharsZ(JSContext *cx, JSString *str)
5316 CHECK_REQUEST(cx);
5317 assertSameCompartment(cx, str);
5318 return str->getCharsZ(cx);
5321 JS_PUBLIC_API(const jschar *)
5322 JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength)
5324 CHECK_REQUEST(cx);
5325 assertSameCompartment(cx, str);
5326 *plength = str->length();
5327 return str->getCharsZ(cx);
5330 JS_PUBLIC_API(const jschar *)
5331 JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
5333 CHECK_REQUEST(cx);
5334 assertSameCompartment(cx, str);
5335 *plength = str->length();
5336 return str->getChars(cx);
5339 JS_PUBLIC_API(const jschar *)
5340 JS_GetInternedStringChars(JSString *str)
5342 JS_ASSERT(str->isAtomized());
5343 return str->flatChars();
5346 JS_PUBLIC_API(const jschar *)
5347 JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength)
5349 JS_ASSERT(str->isAtomized());
5350 *plength = str->flatLength();
5351 return str->flatChars();
5354 extern JS_PUBLIC_API(JSFlatString *)
5355 JS_FlattenString(JSContext *cx, JSString *str)
5357 CHECK_REQUEST(cx);
5358 assertSameCompartment(cx, str);
5359 return str->getCharsZ(cx) ? (JSFlatString *)str : NULL;
5362 extern JS_PUBLIC_API(const jschar *)
5363 JS_GetFlatStringChars(JSFlatString *str)
5365 return str->chars();
5368 JS_PUBLIC_API(JSBool)
5369 JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result)
5371 return CompareStrings(cx, str1, str2, result);
5374 JS_PUBLIC_API(JSBool)
5375 JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match)
5377 JSLinearString *linearStr = str->ensureLinear(cx);
5378 if (!linearStr)
5379 return false;
5380 *match = StringEqualsAscii(linearStr, asciiBytes);
5381 return true;
5384 JS_PUBLIC_API(JSBool)
5385 JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes)
5387 return StringEqualsAscii(str, asciiBytes);
5390 JS_PUBLIC_API(size_t)
5391 JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote)
5393 return PutEscapedString(buffer, size, str, quote);
5396 JS_PUBLIC_API(size_t)
5397 JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote)
5399 JSLinearString *linearStr = str->ensureLinear(cx);
5400 if (!linearStr)
5401 return size_t(-1);
5402 return PutEscapedString(buffer, size, linearStr, quote);
5405 JS_PUBLIC_API(JSBool)
5406 JS_FileEscapedString(FILE *fp, JSString *str, char quote)
5408 JSLinearString *linearStr = str->ensureLinear(NULL);
5409 return linearStr && FileEscapedString(fp, linearStr, quote);
5412 JS_PUBLIC_API(JSString *)
5413 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
5415 CHECK_REQUEST(cx);
5416 return js_NewString(cx, chars, length);
5419 JS_PUBLIC_API(JSString *)
5420 JS_NewDependentString(JSContext *cx, JSString *str, size_t start, size_t length)
5422 CHECK_REQUEST(cx);
5423 return js_NewDependentString(cx, str, start, length);
5426 JS_PUBLIC_API(JSString *)
5427 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
5429 CHECK_REQUEST(cx);
5430 return js_ConcatStrings(cx, left, right);
5433 JS_PUBLIC_API(const jschar *)
5434 JS_UndependString(JSContext *cx, JSString *str)
5436 CHECK_REQUEST(cx);
5437 return str->getCharsZ(cx);
5440 JS_PUBLIC_API(JSBool)
5441 JS_MakeStringImmutable(JSContext *cx, JSString *str)
5443 CHECK_REQUEST(cx);
5444 return js_MakeStringImmutable(cx, str);
5447 JS_PUBLIC_API(JSBool)
5448 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, size_t *dstlenp)
5450 size_t n;
5451 if (!dst) {
5452 n = js_GetDeflatedStringLength(cx, src, srclen);
5453 if (n == (size_t)-1) {
5454 *dstlenp = 0;
5455 return JS_FALSE;
5457 *dstlenp = n;
5458 return JS_TRUE;
5461 return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5464 JS_PUBLIC_API(JSBool)
5465 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp)
5467 return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5470 JS_PUBLIC_API(char *)
5471 JS_EncodeString(JSContext *cx, JSString *str)
5473 const jschar *chars = str->getChars(cx);
5474 if (!chars)
5475 return NULL;
5476 return js_DeflateString(cx, chars, str->length());
5479 JS_PUBLIC_API(size_t)
5480 JS_GetStringEncodingLength(JSContext *cx, JSString *str)
5482 const jschar *chars = str->getChars(cx);
5483 if (!chars)
5484 return size_t(-1);
5485 return js_GetDeflatedStringLength(cx, chars, str->length());
5488 JS_PUBLIC_API(size_t)
5489 JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length)
5492 * FIXME bug 612141 - fix js_DeflateStringToBuffer interface so the result
5493 * would allow to distinguish between insufficient buffer and encoding
5494 * error.
5496 size_t writtenLength = length;
5497 const jschar *chars = str->getChars(NULL);
5498 if (!chars)
5499 return size_t(-1);
5500 if (js_DeflateStringToBuffer(NULL, chars, str->length(), buffer, &writtenLength)) {
5501 JS_ASSERT(writtenLength <= length);
5502 return writtenLength;
5504 JS_ASSERT(writtenLength <= length);
5505 size_t necessaryLength = js_GetDeflatedStringLength(NULL, chars, str->length());
5506 if (necessaryLength == size_t(-1))
5507 return size_t(-1);
5508 if (writtenLength != length) {
5509 /* Make sure that the buffer contains only valid UTF-8 sequences. */
5510 JS_ASSERT(js_CStringsAreUTF8);
5511 PodZero(buffer + writtenLength, length - writtenLength);
5513 return necessaryLength;
5516 JS_PUBLIC_API(JSBool)
5517 JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
5518 JSONWriteCallback callback, void *data)
5520 CHECK_REQUEST(cx);
5521 assertSameCompartment(cx, replacer, space);
5522 StringBuffer sb(cx);
5523 if (!js_Stringify(cx, Valueify(vp), replacer, Valueify(space), sb))
5524 return false;
5525 return callback(sb.begin(), sb.length(), data);
5528 JS_PUBLIC_API(JSBool)
5529 JS_TryJSON(JSContext *cx, jsval *vp)
5531 CHECK_REQUEST(cx);
5532 assertSameCompartment(cx, *vp);
5533 return js_TryJSON(cx, Valueify(vp));
5536 JS_PUBLIC_API(JSONParser *)
5537 JS_BeginJSONParse(JSContext *cx, jsval *vp)
5539 CHECK_REQUEST(cx);
5540 return js_BeginJSONParse(cx, Valueify(vp));
5543 JS_PUBLIC_API(JSBool)
5544 JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len)
5546 CHECK_REQUEST(cx);
5547 return js_ConsumeJSONText(cx, jp, data, len);
5550 JS_PUBLIC_API(JSBool)
5551 JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver)
5553 CHECK_REQUEST(cx);
5554 assertSameCompartment(cx, reviver);
5555 return js_FinishJSONParse(cx, jp, Valueify(reviver));
5558 JS_PUBLIC_API(JSBool)
5559 JS_ReadStructuredClone(JSContext *cx, const uint64 *buf, size_t nbytes,
5560 uint32 version, jsval *vp,
5561 const JSStructuredCloneCallbacks *optionalCallbacks,
5562 void *closure)
5564 if (version > JS_STRUCTURED_CLONE_VERSION) {
5565 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CLONE_VERSION);
5566 return false;
5568 const JSStructuredCloneCallbacks *callbacks =
5569 optionalCallbacks ?
5570 optionalCallbacks :
5571 cx->runtime->structuredCloneCallbacks;
5572 return ReadStructuredClone(cx, buf, nbytes, Valueify(vp), callbacks, closure);
5575 JS_PUBLIC_API(JSBool)
5576 JS_WriteStructuredClone(JSContext *cx, jsval v, uint64 **bufp, size_t *nbytesp,
5577 const JSStructuredCloneCallbacks *optionalCallbacks,
5578 void *closure)
5580 const JSStructuredCloneCallbacks *callbacks =
5581 optionalCallbacks ?
5582 optionalCallbacks :
5583 cx->runtime->structuredCloneCallbacks;
5584 return WriteStructuredClone(cx, Valueify(v), (uint64_t **) bufp, nbytesp,
5585 callbacks, closure);
5588 JS_PUBLIC_API(JSBool)
5589 JS_StructuredClone(JSContext *cx, jsval v, jsval *vp,
5590 ReadStructuredCloneOp optionalReadOp,
5591 const JSStructuredCloneCallbacks *optionalCallbacks,
5592 void *closure)
5594 const JSStructuredCloneCallbacks *callbacks =
5595 optionalCallbacks ?
5596 optionalCallbacks :
5597 cx->runtime->structuredCloneCallbacks;
5598 JSAutoStructuredCloneBuffer buf;
5599 return buf.write(cx, v, callbacks, closure) &&
5600 buf.read(vp, cx, callbacks, closure);
5603 JS_PUBLIC_API(void)
5604 JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks)
5606 rt->structuredCloneCallbacks = callbacks;
5609 JS_PUBLIC_API(JSBool)
5610 JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32 *p1, uint32 *p2)
5612 return r->input().readPair((uint32_t *) p1, (uint32_t *) p2);
5615 JS_PUBLIC_API(JSBool)
5616 JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len)
5618 return r->input().readBytes(p, len);
5621 JS_PUBLIC_API(JSBool)
5622 JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32 tag, uint32 data)
5624 return w->output().writePair(tag, data);
5627 JS_PUBLIC_API(JSBool)
5628 JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len)
5630 return w->output().writeBytes(p, len);
5634 * The following determines whether C Strings are to be treated as UTF-8
5635 * or ISO-8859-1. For correct operation, it must be set prior to the
5636 * first call to JS_NewRuntime.
5638 #ifndef JS_C_STRINGS_ARE_UTF8
5639 JSBool js_CStringsAreUTF8 = JS_FALSE;
5640 #endif
5642 JS_PUBLIC_API(JSBool)
5643 JS_CStringsAreUTF8()
5645 return js_CStringsAreUTF8;
5648 JS_PUBLIC_API(void)
5649 JS_SetCStringsAreUTF8()
5651 JS_ASSERT(!js_NewRuntimeWasCalled);
5653 #ifndef JS_C_STRINGS_ARE_UTF8
5654 js_CStringsAreUTF8 = JS_TRUE;
5655 #endif
5658 /************************************************************************/
5660 JS_PUBLIC_API(void)
5661 JS_ReportError(JSContext *cx, const char *format, ...)
5663 va_list ap;
5665 va_start(ap, format);
5666 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
5667 va_end(ap);
5670 JS_PUBLIC_API(void)
5671 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
5672 void *userRef, const uintN errorNumber, ...)
5674 va_list ap;
5676 va_start(ap, errorNumber);
5677 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5678 errorNumber, JS_TRUE, ap);
5679 va_end(ap);
5682 JS_PUBLIC_API(void)
5683 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
5684 void *userRef, const uintN errorNumber, ...)
5686 va_list ap;
5688 va_start(ap, errorNumber);
5689 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5690 errorNumber, JS_FALSE, ap);
5691 va_end(ap);
5694 JS_PUBLIC_API(JSBool)
5695 JS_ReportWarning(JSContext *cx, const char *format, ...)
5697 va_list ap;
5698 JSBool ok;
5700 va_start(ap, format);
5701 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
5702 va_end(ap);
5703 return ok;
5706 JS_PUBLIC_API(JSBool)
5707 JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
5708 JSErrorCallback errorCallback, void *userRef,
5709 const uintN errorNumber, ...)
5711 va_list ap;
5712 JSBool ok;
5714 va_start(ap, errorNumber);
5715 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5716 errorNumber, JS_TRUE, ap);
5717 va_end(ap);
5718 return ok;
5721 JS_PUBLIC_API(JSBool)
5722 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
5723 JSErrorCallback errorCallback, void *userRef,
5724 const uintN errorNumber, ...)
5726 va_list ap;
5727 JSBool ok;
5729 va_start(ap, errorNumber);
5730 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5731 errorNumber, JS_FALSE, ap);
5732 va_end(ap);
5733 return ok;
5736 JS_PUBLIC_API(void)
5737 JS_ReportOutOfMemory(JSContext *cx)
5739 js_ReportOutOfMemory(cx);
5742 JS_PUBLIC_API(void)
5743 JS_ReportAllocationOverflow(JSContext *cx)
5745 js_ReportAllocationOverflow(cx);
5748 JS_PUBLIC_API(JSErrorReporter)
5749 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
5751 JSErrorReporter older;
5753 older = cx->errorReporter;
5754 cx->errorReporter = er;
5755 return older;
5758 /************************************************************************/
5761 * Dates.
5763 JS_PUBLIC_API(JSObject *)
5764 JS_NewDateObject(JSContext *cx, int year, int mon, int mday, int hour, int min, int sec)
5766 CHECK_REQUEST(cx);
5767 return js_NewDateObject(cx, year, mon, mday, hour, min, sec);
5770 JS_PUBLIC_API(JSObject *)
5771 JS_NewDateObjectMsec(JSContext *cx, jsdouble msec)
5773 CHECK_REQUEST(cx);
5774 return js_NewDateObjectMsec(cx, msec);
5777 JS_PUBLIC_API(JSBool)
5778 JS_ObjectIsDate(JSContext *cx, JSObject *obj)
5780 JS_ASSERT(obj);
5781 return obj->isDate();
5784 /************************************************************************/
5787 * Regular Expressions.
5789 JS_PUBLIC_API(JSObject *)
5790 JS_NewRegExpObject(JSContext *cx, JSObject *obj, char *bytes, size_t length, uintN flags)
5792 CHECK_REQUEST(cx);
5793 jschar *chars = js_InflateString(cx, bytes, &length);
5794 if (!chars)
5795 return NULL;
5796 RegExpStatics *res = RegExpStatics::extractFrom(obj);
5797 JSObject *reobj = RegExp::createObject(cx, res, chars, length, flags);
5798 cx->free(chars);
5799 return reobj;
5802 JS_PUBLIC_API(JSObject *)
5803 JS_NewUCRegExpObject(JSContext *cx, JSObject *obj, jschar *chars, size_t length, uintN flags)
5805 CHECK_REQUEST(cx);
5806 RegExpStatics *res = RegExpStatics::extractFrom(obj);
5807 return RegExp::createObject(cx, res, chars, length, flags);
5810 JS_PUBLIC_API(void)
5811 JS_SetRegExpInput(JSContext *cx, JSObject *obj, JSString *input, JSBool multiline)
5813 CHECK_REQUEST(cx);
5814 assertSameCompartment(cx, input);
5816 RegExpStatics::extractFrom(obj)->reset(input, !!multiline);
5819 JS_PUBLIC_API(void)
5820 JS_ClearRegExpStatics(JSContext *cx, JSObject *obj)
5822 CHECK_REQUEST(cx);
5823 JS_ASSERT(obj);
5825 RegExpStatics::extractFrom(obj)->clear();
5828 JS_PUBLIC_API(JSBool)
5829 JS_ExecuteRegExp(JSContext *cx, JSObject *obj, JSObject *reobj, jschar *chars, size_t length,
5830 size_t *indexp, JSBool test, jsval *rval)
5832 CHECK_REQUEST(cx);
5834 RegExp *re = RegExp::extractFrom(reobj);
5835 if (!re)
5836 return false;
5838 JSString *str = js_NewStringCopyN(cx, chars, length);
5839 if (!str)
5840 return false;
5842 return re->execute(cx, RegExpStatics::extractFrom(obj), str, indexp, test, Valueify(rval));
5845 JS_PUBLIC_API(JSObject *)
5846 JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, uintN flags)
5848 CHECK_REQUEST(cx);
5849 jschar *chars = js_InflateString(cx, bytes, &length);
5850 if (!chars)
5851 return NULL;
5852 JSObject *obj = RegExp::createObjectNoStatics(cx, chars, length, flags);
5853 cx->free(chars);
5854 return obj;
5857 JS_PUBLIC_API(JSObject *)
5858 JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, uintN flags)
5860 CHECK_REQUEST(cx);
5861 return RegExp::createObjectNoStatics(cx, chars, length, flags);
5864 JS_PUBLIC_API(JSBool)
5865 JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *obj, jschar *chars, size_t length,
5866 size_t *indexp, JSBool test, jsval *rval)
5868 CHECK_REQUEST(cx);
5870 RegExp *re = RegExp::extractFrom(obj);
5871 if (!re)
5872 return false;
5874 JSString *str = js_NewStringCopyN(cx, chars, length);
5875 if (!str)
5876 return false;
5878 return re->executeNoStatics(cx, str, indexp, test, Valueify(rval));
5881 /************************************************************************/
5883 JS_PUBLIC_API(void)
5884 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
5886 cx->localeCallbacks = callbacks;
5889 JS_PUBLIC_API(JSLocaleCallbacks *)
5890 JS_GetLocaleCallbacks(JSContext *cx)
5892 return cx->localeCallbacks;
5895 /************************************************************************/
5897 JS_PUBLIC_API(JSBool)
5898 JS_IsExceptionPending(JSContext *cx)
5900 return (JSBool) cx->isExceptionPending();
5903 JS_PUBLIC_API(JSBool)
5904 JS_GetPendingException(JSContext *cx, jsval *vp)
5906 CHECK_REQUEST(cx);
5907 if (!cx->isExceptionPending())
5908 return JS_FALSE;
5909 Valueify(*vp) = cx->getPendingException();
5910 assertSameCompartment(cx, *vp);
5911 return JS_TRUE;
5914 JS_PUBLIC_API(void)
5915 JS_SetPendingException(JSContext *cx, jsval v)
5917 CHECK_REQUEST(cx);
5918 assertSameCompartment(cx, v);
5919 cx->setPendingException(Valueify(v));
5922 JS_PUBLIC_API(void)
5923 JS_ClearPendingException(JSContext *cx)
5925 cx->clearPendingException();
5928 JS_PUBLIC_API(JSBool)
5929 JS_ReportPendingException(JSContext *cx)
5931 JSBool ok;
5932 JSPackedBool save;
5934 CHECK_REQUEST(cx);
5937 * Set cx->generatingError to suppress the standard error-to-exception
5938 * conversion done by all {js,JS}_Report* functions except for OOM. The
5939 * cx->generatingError flag was added to suppress recursive divergence
5940 * under js_ErrorToException, but it serves for our purposes here too.
5942 save = cx->generatingError;
5943 cx->generatingError = JS_TRUE;
5944 ok = js_ReportUncaughtException(cx);
5945 cx->generatingError = save;
5946 return ok;
5949 struct JSExceptionState {
5950 JSBool throwing;
5951 jsval exception;
5954 JS_PUBLIC_API(JSExceptionState *)
5955 JS_SaveExceptionState(JSContext *cx)
5957 JSExceptionState *state;
5959 CHECK_REQUEST(cx);
5960 state = (JSExceptionState *) cx->malloc(sizeof(JSExceptionState));
5961 if (state) {
5962 state->throwing = JS_GetPendingException(cx, &state->exception);
5963 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
5964 js_AddRoot(cx, Valueify(&state->exception), "JSExceptionState.exception");
5966 return state;
5969 JS_PUBLIC_API(void)
5970 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
5972 CHECK_REQUEST(cx);
5973 if (state) {
5974 if (state->throwing)
5975 JS_SetPendingException(cx, state->exception);
5976 else
5977 JS_ClearPendingException(cx);
5978 JS_DropExceptionState(cx, state);
5982 JS_PUBLIC_API(void)
5983 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
5985 CHECK_REQUEST(cx);
5986 if (state) {
5987 if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
5988 assertSameCompartment(cx, state->exception);
5989 JS_RemoveValueRoot(cx, &state->exception);
5991 cx->free(state);
5995 JS_PUBLIC_API(JSErrorReport *)
5996 JS_ErrorFromException(JSContext *cx, jsval v)
5998 CHECK_REQUEST(cx);
5999 assertSameCompartment(cx, v);
6000 return js_ErrorFromException(cx, v);
6003 JS_PUBLIC_API(JSBool)
6004 JS_ThrowReportedError(JSContext *cx, const char *message,
6005 JSErrorReport *reportp)
6007 return JS_IsRunning(cx) &&
6008 js_ErrorToException(cx, message, reportp, NULL, NULL);
6011 JS_PUBLIC_API(JSBool)
6012 JS_ThrowStopIteration(JSContext *cx)
6014 return js_ThrowStopIteration(cx);
6018 * Get the owning thread id of a context. Returns 0 if the context is not
6019 * owned by any thread.
6021 JS_PUBLIC_API(jsword)
6022 JS_GetContextThread(JSContext *cx)
6024 #ifdef JS_THREADSAFE
6025 return reinterpret_cast<jsword>(JS_THREAD_ID(cx));
6026 #else
6027 return 0;
6028 #endif
6032 * Set the current thread as the owning thread of a context. Returns the
6033 * old owning thread id, or -1 if the operation failed.
6035 JS_PUBLIC_API(jsword)
6036 JS_SetContextThread(JSContext *cx)
6038 #ifdef JS_THREADSAFE
6039 JS_ASSERT(!cx->outstandingRequests);
6040 if (cx->thread) {
6041 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
6042 return reinterpret_cast<jsword>(cx->thread->id);
6045 if (!js_InitContextThread(cx)) {
6046 js_ReportOutOfMemory(cx);
6047 return -1;
6050 /* Here the GC lock is still held after js_InitContextThread took it. */
6051 JS_UNLOCK_GC(cx->runtime);
6052 #endif
6053 return 0;
6056 JS_PUBLIC_API(jsword)
6057 JS_ClearContextThread(JSContext *cx)
6059 #ifdef JS_THREADSAFE
6061 * cx must have exited all requests it entered and, if cx is associated
6062 * with a thread, this must be called only from that thread. If not, this
6063 * is a harmless no-op.
6065 JS_ASSERT(cx->outstandingRequests == 0);
6066 JSThread *t = cx->thread;
6067 if (!t)
6068 return 0;
6069 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
6072 * We must not race with a GC that accesses cx->thread for all threads,
6073 * see bug 476934.
6075 JSRuntime *rt = cx->runtime;
6076 AutoLockGC lock(rt);
6077 js_WaitForGC(rt);
6078 js_ClearContextThread(cx);
6079 JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth);
6082 * We can access t->id as long as the GC lock is held and we cannot race
6083 * with the GC that may delete t.
6085 return reinterpret_cast<jsword>(t->id);
6086 #else
6087 return 0;
6088 #endif
6091 #ifdef MOZ_TRACE_JSCALLS
6092 JS_PUBLIC_API(void)
6093 JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb)
6095 cx->functionCallback = fcb;
6098 JS_PUBLIC_API(JSFunctionCallback)
6099 JS_GetFunctionCallback(JSContext *cx)
6101 return cx->functionCallback;
6103 #endif
6105 #ifdef JS_GC_ZEAL
6106 JS_PUBLIC_API(void)
6107 JS_SetGCZeal(JSContext *cx, uint8 zeal)
6109 cx->runtime->gcZeal = zeal;
6111 #endif
6113 /************************************************************************/
6115 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN) && !defined (WINCE)
6117 #include "jswin.h"
6120 * Initialization routine for the JS DLL.
6122 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
6124 return TRUE;
6127 #endif