Back out b70659aca040, burning XPCShell tests. (no_r=me)
[mozilla-central.git] / js / src / jsapi.cpp
blob902ba10bd8987891ed8084ebd8e0fb1752b05655
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=78:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
25 * Contributor(s):
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 * JavaScript API.
44 #include <ctype.h>
45 #include <stdarg.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include "jstypes.h"
49 #include "jsstdint.h"
50 #include "jsarena.h" /* Added by JSIFY */
51 #include "jsutil.h" /* Added by JSIFY */
52 #include "jsclist.h"
53 #include "jsdhash.h"
54 #include "jsprf.h"
55 #include "jsapi.h"
56 #include "jsarray.h"
57 #include "jsatom.h"
58 #include "jsbool.h"
59 #include "jsbuiltins.h"
60 #include "jscntxt.h"
61 #include "jsversion.h"
62 #include "jsdate.h"
63 #include "jsemit.h"
64 #include "jsexn.h"
65 #include "jsfun.h"
66 #include "jsgc.h"
67 #include "jsinterp.h"
68 #include "jsiter.h"
69 #include "jslock.h"
70 #include "jsmath.h"
71 #include "jsnum.h"
72 #include "json.h"
73 #include "jsobj.h"
74 #include "jsopcode.h"
75 #include "jsparse.h"
76 #include "jsproxy.h"
77 #include "jsregexp.h"
78 #include "jsscan.h"
79 #include "jsscope.h"
80 #include "jsscript.h"
81 #include "jsstr.h"
82 #include "jstracer.h"
83 #include "jsdbgapi.h"
84 #include "prmjtime.h"
85 #include "jsstaticcheck.h"
86 #include "jsvector.h"
87 #include "jswrapper.h"
88 #include "jstypedarray.h"
90 #include "jsatominlines.h"
91 #include "jscntxtinlines.h"
92 #include "jsinterpinlines.h"
93 #include "jsobjinlines.h"
94 #include "jsscopeinlines.h"
95 #include "jscntxtinlines.h"
96 #include "jsregexpinlines.h"
97 #include "assembler/wtf/Platform.h"
99 #if ENABLE_YARR_JIT
100 #include "assembler/jit/ExecutableAllocator.h"
101 #include "methodjit/Logging.h"
102 #endif
104 #if JS_HAS_XML_SUPPORT
105 #include "jsxml.h"
106 #endif
108 using namespace js;
110 class AutoVersionAPI
112 JSContext * const cx;
113 JSVersion oldVersion;
114 bool oldVersionWasOverride;
115 uint32 oldOptions;
117 public:
118 explicit AutoVersionAPI(JSContext *cx, JSVersion newVersion)
119 : cx(cx), oldVersion(cx->findVersion()), oldVersionWasOverride(cx->isVersionOverridden()),
120 oldOptions(cx->options) {
121 JS_ASSERT(!VersionExtractFlags(newVersion) ||
122 VersionExtractFlags(newVersion) == VersionFlags::HAS_XML);
123 cx->options = VersionHasXML(newVersion)
124 ? (cx->options | JSOPTION_XML)
125 : (cx->options & ~JSOPTION_XML);
126 cx->maybeOverrideVersion(newVersion);
127 SyncOptionsToVersion(cx);
130 ~AutoVersionAPI() {
131 cx->options = oldOptions;
132 if (oldVersionWasOverride) {
133 JS_ALWAYS_TRUE(cx->maybeOverrideVersion(oldVersion));
134 } else {
135 cx->clearVersionOverride();
136 cx->setDefaultVersion(oldVersion);
138 JS_ASSERT(cx->findVersion() == oldVersion);
142 #ifdef HAVE_VA_LIST_AS_ARRAY
143 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
144 #else
145 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
146 #endif
148 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
149 JS_PUBLIC_DATA(jsid) JS_DEFAULT_XML_NAMESPACE_ID = { size_t(JSID_TYPE_DEFAULT_XML_NAMESPACE) };
150 JS_PUBLIC_DATA(jsid) JSID_VOID = { size_t(JSID_TYPE_VOID) };
151 JS_PUBLIC_DATA(jsid) JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) };
152 #endif
154 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
155 JS_PUBLIC_DATA(jsval) JSVAL_NULL = { BUILD_JSVAL(JSVAL_TAG_NULL, 0) };
156 JS_PUBLIC_DATA(jsval) JSVAL_ZERO = { BUILD_JSVAL(JSVAL_TAG_INT32, 0) };
157 JS_PUBLIC_DATA(jsval) JSVAL_ONE = { BUILD_JSVAL(JSVAL_TAG_INT32, 1) };
158 JS_PUBLIC_DATA(jsval) JSVAL_FALSE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_FALSE) };
159 JS_PUBLIC_DATA(jsval) JSVAL_TRUE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_TRUE) };
160 JS_PUBLIC_DATA(jsval) JSVAL_VOID = { BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0) };
161 #endif
163 /* Make sure that jschar is two bytes unsigned integer */
164 JS_STATIC_ASSERT((jschar)-1 > 0);
165 JS_STATIC_ASSERT(sizeof(jschar) == 2);
167 JS_PUBLIC_API(int64)
168 JS_Now()
170 return PRMJ_Now();
173 JS_PUBLIC_API(jsval)
174 JS_GetNaNValue(JSContext *cx)
176 return Jsvalify(cx->runtime->NaNValue);
179 JS_PUBLIC_API(jsval)
180 JS_GetNegativeInfinityValue(JSContext *cx)
182 return Jsvalify(cx->runtime->negativeInfinityValue);
185 JS_PUBLIC_API(jsval)
186 JS_GetPositiveInfinityValue(JSContext *cx)
188 return Jsvalify(cx->runtime->positiveInfinityValue);
191 JS_PUBLIC_API(jsval)
192 JS_GetEmptyStringValue(JSContext *cx)
194 return STRING_TO_JSVAL(cx->runtime->emptyString);
197 static JSBool
198 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, jsval **vpp, va_list *app)
200 const char *format;
201 JSArgumentFormatMap *map;
203 format = *formatp;
204 for (map = cx->argumentFormatMap; map; map = map->next) {
205 if (!strncmp(format, map->format, map->length)) {
206 *formatp = format + map->length;
207 return map->formatter(cx, format, fromJS, vpp, app);
210 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
211 return JS_FALSE;
214 JS_PUBLIC_API(JSBool)
215 JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format, ...)
217 va_list ap;
218 JSBool ok;
220 va_start(ap, format);
221 ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
222 va_end(ap);
223 return ok;
226 JS_PUBLIC_API(JSBool)
227 JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format, va_list ap)
229 jsval *sp;
230 JSBool required;
231 char c;
232 JSFunction *fun;
233 jsdouble d;
234 JSString *str;
235 JSObject *obj;
237 CHECK_REQUEST(cx);
238 assertSameCompartment(cx, JSValueArray(argv - 2, argc + 2));
239 sp = argv;
240 required = JS_TRUE;
241 while ((c = *format++) != '\0') {
242 if (isspace(c))
243 continue;
244 if (c == '/') {
245 required = JS_FALSE;
246 continue;
248 if (sp == argv + argc) {
249 if (required) {
250 fun = js_ValueToFunction(cx, Valueify(&argv[-2]), 0);
251 if (fun) {
252 char numBuf[12];
253 JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
254 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
255 JSMSG_MORE_ARGS_NEEDED,
256 JS_GetFunctionName(fun), numBuf,
257 (argc == 1) ? "" : "s");
259 return JS_FALSE;
261 break;
263 switch (c) {
264 case 'b':
265 *va_arg(ap, JSBool *) = js_ValueToBoolean(Valueify(*sp));
266 break;
267 case 'c':
268 if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
269 return JS_FALSE;
270 break;
271 case 'i':
272 if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
273 return JS_FALSE;
274 break;
275 case 'u':
276 if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
277 return JS_FALSE;
278 break;
279 case 'j':
280 if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
281 return JS_FALSE;
282 break;
283 case 'd':
284 if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
285 return JS_FALSE;
286 break;
287 case 'I':
288 if (!JS_ValueToNumber(cx, *sp, &d))
289 return JS_FALSE;
290 *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
291 break;
292 case 's':
293 case 'S':
294 case 'W':
295 str = js_ValueToString(cx, Valueify(*sp));
296 if (!str)
297 return JS_FALSE;
298 *sp = STRING_TO_JSVAL(str);
299 if (c == 's') {
300 const char *bytes = js_GetStringBytes(cx, str);
301 if (!bytes)
302 return JS_FALSE;
303 *va_arg(ap, const char **) = bytes;
304 } else if (c == 'W') {
305 const jschar *chars = js_GetStringChars(cx, str);
306 if (!chars)
307 return JS_FALSE;
308 *va_arg(ap, const jschar **) = chars;
309 } else {
310 *va_arg(ap, JSString **) = str;
312 break;
313 case 'o':
314 if (!js_ValueToObjectOrNull(cx, Valueify(*sp), &obj))
315 return JS_FALSE;
316 *sp = OBJECT_TO_JSVAL(obj);
317 *va_arg(ap, JSObject **) = obj;
318 break;
319 case 'f':
320 obj = js_ValueToFunctionObject(cx, Valueify(sp), 0);
321 if (!obj)
322 return JS_FALSE;
323 *sp = OBJECT_TO_JSVAL(obj);
324 *va_arg(ap, JSFunction **) = GET_FUNCTION_PRIVATE(cx, obj);
325 break;
326 case 'v':
327 *va_arg(ap, jsval *) = *sp;
328 break;
329 case '*':
330 break;
331 default:
332 format--;
333 if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
334 JS_ADDRESSOF_VA_LIST(ap))) {
335 return JS_FALSE;
337 /* NB: the formatter already updated sp, so we continue here. */
338 continue;
340 sp++;
342 return JS_TRUE;
345 JS_PUBLIC_API(JSBool)
346 JS_AddArgumentFormatter(JSContext *cx, const char *format, JSArgumentFormatter formatter)
348 size_t length;
349 JSArgumentFormatMap **mpp, *map;
351 length = strlen(format);
352 mpp = &cx->argumentFormatMap;
353 while ((map = *mpp) != NULL) {
354 /* Insert before any shorter string to match before prefixes. */
355 if (map->length < length)
356 break;
357 if (map->length == length && !strcmp(map->format, format))
358 goto out;
359 mpp = &map->next;
361 map = (JSArgumentFormatMap *) cx->malloc(sizeof *map);
362 if (!map)
363 return JS_FALSE;
364 map->format = format;
365 map->length = length;
366 map->next = *mpp;
367 *mpp = map;
368 out:
369 map->formatter = formatter;
370 return JS_TRUE;
373 JS_PUBLIC_API(void)
374 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
376 size_t length;
377 JSArgumentFormatMap **mpp, *map;
379 length = strlen(format);
380 mpp = &cx->argumentFormatMap;
381 while ((map = *mpp) != NULL) {
382 if (map->length == length && !strcmp(map->format, format)) {
383 *mpp = map->next;
384 cx->free(map);
385 return;
387 mpp = &map->next;
391 JS_PUBLIC_API(JSBool)
392 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
394 JSBool ok;
395 JSObject *obj;
396 JSString *str;
397 jsdouble d;
399 CHECK_REQUEST(cx);
400 assertSameCompartment(cx, v);
401 switch (type) {
402 case JSTYPE_VOID:
403 *vp = JSVAL_VOID;
404 ok = JS_TRUE;
405 break;
406 case JSTYPE_OBJECT:
407 ok = js_ValueToObjectOrNull(cx, Valueify(v), &obj);
408 if (ok)
409 *vp = OBJECT_TO_JSVAL(obj);
410 break;
411 case JSTYPE_FUNCTION:
412 *vp = v;
413 obj = js_ValueToFunctionObject(cx, Valueify(vp), JSV2F_SEARCH_STACK);
414 ok = (obj != NULL);
415 break;
416 case JSTYPE_STRING:
417 str = js_ValueToString(cx, Valueify(v));
418 ok = (str != NULL);
419 if (ok)
420 *vp = STRING_TO_JSVAL(str);
421 break;
422 case JSTYPE_NUMBER:
423 ok = JS_ValueToNumber(cx, v, &d);
424 if (ok)
425 *vp = DOUBLE_TO_JSVAL(d);
426 break;
427 case JSTYPE_BOOLEAN:
428 *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(Valueify(v)));
429 return JS_TRUE;
430 default: {
431 char numBuf[12];
432 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
433 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE, numBuf);
434 ok = JS_FALSE;
435 break;
438 return ok;
441 JS_PUBLIC_API(JSBool)
442 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
444 CHECK_REQUEST(cx);
445 assertSameCompartment(cx, v);
446 return js_ValueToObjectOrNull(cx, Valueify(v), objp);
449 JS_PUBLIC_API(JSFunction *)
450 JS_ValueToFunction(JSContext *cx, jsval v)
452 CHECK_REQUEST(cx);
453 assertSameCompartment(cx, v);
454 return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
457 JS_PUBLIC_API(JSFunction *)
458 JS_ValueToConstructor(JSContext *cx, jsval v)
460 CHECK_REQUEST(cx);
461 assertSameCompartment(cx, v);
462 return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
465 JS_PUBLIC_API(JSString *)
466 JS_ValueToString(JSContext *cx, jsval v)
468 CHECK_REQUEST(cx);
469 assertSameCompartment(cx, v);
470 return js_ValueToString(cx, Valueify(v));
473 JS_PUBLIC_API(JSString *)
474 JS_ValueToSource(JSContext *cx, jsval v)
476 CHECK_REQUEST(cx);
477 assertSameCompartment(cx, v);
478 return js_ValueToSource(cx, Valueify(v));
481 JS_PUBLIC_API(JSBool)
482 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
484 CHECK_REQUEST(cx);
485 assertSameCompartment(cx, v);
487 AutoValueRooter tvr(cx, Valueify(v));
488 return ValueToNumber(cx, tvr.value(), dp);
491 JS_PUBLIC_API(JSBool)
492 JS_DoubleIsInt32(jsdouble d, jsint *ip)
494 return JSDOUBLE_IS_INT32(d, (int32_t *)ip);
497 JS_PUBLIC_API(JSBool)
498 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
500 CHECK_REQUEST(cx);
501 assertSameCompartment(cx, v);
503 AutoValueRooter tvr(cx, Valueify(v));
504 return ValueToECMAInt32(cx, tvr.value(), (int32_t *)ip);
507 JS_PUBLIC_API(JSBool)
508 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
510 CHECK_REQUEST(cx);
511 assertSameCompartment(cx, v);
513 AutoValueRooter tvr(cx, Valueify(v));
514 return ValueToECMAUint32(cx, tvr.value(), (uint32_t *)ip);
517 JS_PUBLIC_API(JSBool)
518 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
520 CHECK_REQUEST(cx);
521 assertSameCompartment(cx, v);
523 AutoValueRooter tvr(cx, Valueify(v));
524 return ValueToInt32(cx, tvr.value(), (int32_t *)ip);
527 JS_PUBLIC_API(JSBool)
528 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
530 CHECK_REQUEST(cx);
531 assertSameCompartment(cx, v);
533 AutoValueRooter tvr(cx, Valueify(v));
534 return ValueToUint16(cx, tvr.value(), (uint16_t *)ip);
537 JS_PUBLIC_API(JSBool)
538 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
540 CHECK_REQUEST(cx);
541 assertSameCompartment(cx, v);
542 *bp = js_ValueToBoolean(Valueify(v));
543 return JS_TRUE;
546 JS_PUBLIC_API(JSType)
547 JS_TypeOfValue(JSContext *cx, jsval v)
549 CHECK_REQUEST(cx);
550 assertSameCompartment(cx, v);
551 return TypeOfValue(cx, Valueify(v));
554 JS_PUBLIC_API(const char *)
555 JS_GetTypeName(JSContext *cx, JSType type)
557 if ((uintN)type >= (uintN)JSTYPE_LIMIT)
558 return NULL;
559 return JS_TYPE_STR(type);
562 JS_PUBLIC_API(JSBool)
563 JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2)
565 assertSameCompartment(cx, v1, v2);
566 return StrictlyEqual(cx, Valueify(v1), Valueify(v2));
569 JS_PUBLIC_API(JSBool)
570 JS_SameValue(JSContext *cx, jsval v1, jsval v2)
572 assertSameCompartment(cx, v1, v2);
573 return SameValue(Valueify(v1), Valueify(v2), cx);
576 /************************************************************************/
579 * Has a new runtime ever been created? This flag is used to detect unsafe
580 * changes to js_CStringsAreUTF8 after a runtime has been created, and to
581 * ensure that "first checks" on runtime creation are run only once.
583 #ifdef DEBUG
584 static JSBool js_NewRuntimeWasCalled = JS_FALSE;
585 #endif
587 JSRuntime::JSRuntime()
588 : gcChunkAllocator(&defaultGCChunkAllocator)
590 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
591 JS_INIT_CLIST(&contextList);
592 JS_INIT_CLIST(&trapList);
593 JS_INIT_CLIST(&watchPointList);
596 bool
597 JSRuntime::init(uint32 maxbytes)
599 #ifdef JS_METHODJIT_SPEW
600 JMCheckLogging();
601 #endif
603 #ifdef DEBUG
604 functionMeterFilename = getenv("JS_FUNCTION_STATFILE");
605 if (functionMeterFilename) {
606 if (!methodReadBarrierCountMap.init())
607 return false;
608 if (!unjoinedFunctionCountMap.init())
609 return false;
611 propTreeStatFilename = getenv("JS_PROPTREE_STATFILE");
612 propTreeDumpFilename = getenv("JS_PROPTREE_DUMPFILE");
613 if (meterEmptyShapes()) {
614 if (!emptyShapes.init())
615 return false;
617 #endif
619 if (!(defaultCompartment = new JSCompartment(this)) ||
620 !defaultCompartment->init() ||
621 !compartments.append(defaultCompartment)) {
622 return false;
625 if (!js_InitGC(this, maxbytes) || !js_InitAtomState(this))
626 return false;
628 #if ENABLE_YARR_JIT
629 regExpAllocator = new JSC::ExecutableAllocator();
630 if (!regExpAllocator)
631 return false;
632 #endif
634 deflatedStringCache = new js::DeflatedStringCache();
635 if (!deflatedStringCache || !deflatedStringCache->init())
636 return false;
638 wrapObjectCallback = js::TransparentObjectWrapper;
640 #ifdef JS_THREADSAFE
641 /* this is asymmetric with JS_ShutDown: */
642 if (!js_SetupLocks(8, 16))
643 return false;
644 rtLock = JS_NEW_LOCK();
645 if (!rtLock)
646 return false;
647 stateChange = JS_NEW_CONDVAR(gcLock);
648 if (!stateChange)
649 return false;
650 titleSharingDone = JS_NEW_CONDVAR(gcLock);
651 if (!titleSharingDone)
652 return false;
653 titleSharingTodo = NO_TITLE_SHARING_TODO;
654 debuggerLock = JS_NEW_LOCK();
655 if (!debuggerLock)
656 return false;
657 #endif
658 return propertyTree.init() && js_InitThreads(this);
661 JSRuntime::~JSRuntime()
663 #ifdef DEBUG
664 /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
665 if (!JS_CLIST_IS_EMPTY(&contextList)) {
666 JSContext *cx, *iter = NULL;
667 uintN cxcount = 0;
668 while ((cx = js_ContextIterator(this, JS_TRUE, &iter)) != NULL) {
669 fprintf(stderr,
670 "JS API usage error: found live context at %p\n",
671 (void *) cx);
672 cxcount++;
674 fprintf(stderr,
675 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
676 cxcount, (cxcount == 1) ? "" : "s");
678 #endif
680 js_FinishThreads(this);
681 js_FreeRuntimeScriptState(this);
682 js_FinishAtomState(this);
685 * Finish the deflated string cache after the last GC and after
686 * calling js_FinishAtomState, which finalizes strings.
688 delete deflatedStringCache;
689 #if ENABLE_YARR_JIT
690 delete regExpAllocator;
691 #endif
692 js_FinishGC(this);
693 #ifdef JS_THREADSAFE
694 if (gcLock)
695 JS_DESTROY_LOCK(gcLock);
696 if (gcDone)
697 JS_DESTROY_CONDVAR(gcDone);
698 if (requestDone)
699 JS_DESTROY_CONDVAR(requestDone);
700 if (rtLock)
701 JS_DESTROY_LOCK(rtLock);
702 if (stateChange)
703 JS_DESTROY_CONDVAR(stateChange);
704 if (titleSharingDone)
705 JS_DESTROY_CONDVAR(titleSharingDone);
706 if (debuggerLock)
707 JS_DESTROY_LOCK(debuggerLock);
708 #endif
709 propertyTree.finish();
710 /* Delete all remaining Compartments. Ideally only the defaultCompartment should be left. */
711 for (JSCompartment **c = compartments.begin(); c != compartments.end(); ++c)
712 delete *c;
713 compartments.clear();
716 JS_PUBLIC_API(JSRuntime *)
717 JS_NewRuntime(uint32 maxbytes)
719 #ifdef DEBUG
720 if (!js_NewRuntimeWasCalled) {
722 * This code asserts that the numbers associated with the error names
723 * in jsmsg.def are monotonically increasing. It uses values for the
724 * error names enumerated in jscntxt.c. It's not a compile-time check
725 * but it's better than nothing.
727 int errorNumber = 0;
728 #define MSG_DEF(name, number, count, exception, format) \
729 JS_ASSERT(name == errorNumber++);
730 #include "js.msg"
731 #undef MSG_DEF
733 #define MSG_DEF(name, number, count, exception, format) \
734 JS_BEGIN_MACRO \
735 uintN numfmtspecs = 0; \
736 const char *fmt; \
737 for (fmt = format; *fmt != '\0'; fmt++) { \
738 if (*fmt == '{' && isdigit(fmt[1])) \
739 ++numfmtspecs; \
741 JS_ASSERT(count == numfmtspecs); \
742 JS_END_MACRO;
743 #include "js.msg"
744 #undef MSG_DEF
746 js_NewRuntimeWasCalled = JS_TRUE;
748 #endif /* DEBUG */
750 void *mem = js_calloc(sizeof(JSRuntime));
751 if (!mem)
752 return NULL;
754 JSRuntime *rt = new (mem) JSRuntime();
755 if (!rt->init(maxbytes)) {
756 JS_DestroyRuntime(rt);
757 return NULL;
760 return rt;
763 JS_PUBLIC_API(void)
764 JS_CommenceRuntimeShutDown(JSRuntime *rt)
766 rt->gcFlushCodeCaches = true;
769 JS_PUBLIC_API(void)
770 JS_DestroyRuntime(JSRuntime *rt)
772 rt->~JSRuntime();
774 js_free(rt);
777 #ifdef JS_REPRMETER
778 namespace reprmeter {
779 extern void js_DumpReprMeter();
781 #endif
783 JS_PUBLIC_API(void)
784 JS_ShutDown(void)
786 #ifdef MOZ_TRACEVIS
787 StopTraceVis();
788 #endif
790 #ifdef JS_OPMETER
791 extern void js_DumpOpMeters();
792 js_DumpOpMeters();
793 #endif
795 #ifdef JS_REPRMETER
796 reprmeter::js_DumpReprMeter();
797 #endif
799 #ifdef JS_THREADSAFE
800 js_CleanupLocks();
801 #endif
802 PRMJ_NowShutdown();
805 JS_PUBLIC_API(void *)
806 JS_GetRuntimePrivate(JSRuntime *rt)
808 return rt->data;
811 JS_PUBLIC_API(void)
812 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
814 rt->data = data;
817 #ifdef JS_THREADSAFE
818 static void
819 StartRequest(JSContext *cx)
821 JSThread *t = cx->thread;
822 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
824 if (t->data.requestDepth) {
825 t->data.requestDepth++;
826 } else {
827 JSRuntime *rt = cx->runtime;
828 AutoLockGC lock(rt);
830 /* Wait until the GC is finished. */
831 if (rt->gcThread != cx->thread) {
832 while (rt->gcThread)
833 JS_AWAIT_GC_DONE(rt);
836 /* Indicate that a request is running. */
837 rt->requestCount++;
838 t->data.requestDepth = 1;
841 * Adjust rt->interruptCounter to reflect any interrupts added while the
842 * thread was suspended.
844 if (t->data.interruptFlags)
845 JS_ATOMIC_INCREMENT(&rt->interruptCounter);
847 if (rt->requestCount == 1 && rt->activityCallback)
848 rt->activityCallback(rt->activityCallbackArg, true);
852 static void
853 StopRequest(JSContext *cx)
855 JSThread *t = cx->thread;
856 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
857 JS_ASSERT(t->data.requestDepth != 0);
858 if (t->data.requestDepth != 1) {
859 t->data.requestDepth--;
860 } else {
861 LeaveTrace(cx); /* for GC safety */
863 t->data.conservativeGC.updateForRequestEnd(t->suspendCount);
865 /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
866 JSRuntime *rt = cx->runtime;
867 AutoLockGC lock(rt);
869 t->data.requestDepth = 0;
872 * Adjust rt->interruptCounter to reflect any interrupts added while the
873 * thread still had active requests.
875 if (t->data.interruptFlags)
876 JS_ATOMIC_DECREMENT(&rt->interruptCounter);
878 js_ShareWaitingTitles(cx);
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(void)
959 JS_Lock(JSRuntime *rt)
961 JS_LOCK_RUNTIME(rt);
964 JS_PUBLIC_API(void)
965 JS_Unlock(JSRuntime *rt)
967 JS_UNLOCK_RUNTIME(rt);
970 JS_PUBLIC_API(JSContextCallback)
971 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
973 JSContextCallback old;
975 old = rt->cxCallback;
976 rt->cxCallback = cxCallback;
977 return old;
980 JS_PUBLIC_API(JSContext *)
981 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
983 return js_NewContext(rt, stackChunkSize);
986 JS_PUBLIC_API(void)
987 JS_DestroyContext(JSContext *cx)
989 js_DestroyContext(cx, JSDCM_FORCE_GC);
992 JS_PUBLIC_API(void)
993 JS_DestroyContextNoGC(JSContext *cx)
995 js_DestroyContext(cx, JSDCM_NO_GC);
998 JS_PUBLIC_API(void)
999 JS_DestroyContextMaybeGC(JSContext *cx)
1001 js_DestroyContext(cx, JSDCM_MAYBE_GC);
1004 JS_PUBLIC_API(void *)
1005 JS_GetContextPrivate(JSContext *cx)
1007 return cx->data;
1010 JS_PUBLIC_API(void)
1011 JS_SetContextPrivate(JSContext *cx, void *data)
1013 cx->data = data;
1016 JS_PUBLIC_API(JSRuntime *)
1017 JS_GetRuntime(JSContext *cx)
1019 return cx->runtime;
1022 JS_PUBLIC_API(JSContext *)
1023 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
1025 return js_ContextIterator(rt, JS_TRUE, iterp);
1028 JS_PUBLIC_API(JSVersion)
1029 JS_GetVersion(JSContext *cx)
1031 return VersionNumber(cx->findVersion());
1034 static void
1035 CheckOptionVersionSync(JSContext *cx)
1037 #if DEBUG
1038 uint32 options = cx->options;
1039 JSVersion version = cx->findVersion();
1040 JS_ASSERT(OptionsHasXML(options) == VersionHasXML(version));
1041 JS_ASSERT(OptionsHasAnonFunFix(options) == VersionHasAnonFunFix(version));
1042 #endif
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 JSVersion oldVersion = cx->findVersion();
1053 JSVersion oldVersionNumber = VersionNumber(oldVersion);
1054 if (oldVersionNumber == newVersionNumber)
1055 return oldVersionNumber; /* No override actually occurs! */
1057 /* We no longer support 1.4 or below. */
1058 if (newVersionNumber != JSVERSION_DEFAULT && newVersionNumber <= JSVERSION_1_4)
1059 return oldVersionNumber;
1061 VersionCloneFlags(oldVersion, &newVersion);
1062 cx->maybeOverrideVersion(newVersion);
1063 CheckOptionVersionSync(cx);
1064 return oldVersionNumber;
1067 static struct v2smap {
1068 JSVersion version;
1069 const char *string;
1070 } v2smap[] = {
1071 {JSVERSION_1_0, "1.0"},
1072 {JSVERSION_1_1, "1.1"},
1073 {JSVERSION_1_2, "1.2"},
1074 {JSVERSION_1_3, "1.3"},
1075 {JSVERSION_1_4, "1.4"},
1076 {JSVERSION_ECMA_3, "ECMAv3"},
1077 {JSVERSION_1_5, "1.5"},
1078 {JSVERSION_1_6, "1.6"},
1079 {JSVERSION_1_7, "1.7"},
1080 {JSVERSION_1_8, "1.8"},
1081 {JSVERSION_ECMA_5, "ECMAv5"},
1082 {JSVERSION_DEFAULT, js_default_str},
1083 {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
1086 JS_PUBLIC_API(const char *)
1087 JS_VersionToString(JSVersion version)
1089 int i;
1091 for (i = 0; v2smap[i].string; i++)
1092 if (v2smap[i].version == version)
1093 return v2smap[i].string;
1094 return "unknown";
1097 JS_PUBLIC_API(JSVersion)
1098 JS_StringToVersion(const char *string)
1100 int i;
1102 for (i = 0; v2smap[i].string; i++)
1103 if (strcmp(v2smap[i].string, string) == 0)
1104 return v2smap[i].version;
1105 return JSVERSION_UNKNOWN;
1108 JS_PUBLIC_API(uint32)
1109 JS_GetOptions(JSContext *cx)
1112 * Can't check option/version synchronization here.
1113 * We may have been synchronized with a script version that was formerly on
1114 * the stack, but has now been popped.
1116 return cx->options;
1119 JS_PUBLIC_API(uint32)
1120 JS_SetOptions(JSContext *cx, uint32 options)
1122 AutoLockGC lock(cx->runtime);
1123 uint32 oldopts = cx->options;
1124 cx->options = options;
1125 SyncOptionsToVersion(cx);
1126 cx->updateJITEnabled();
1127 CheckOptionVersionSync(cx);
1128 return oldopts;
1131 JS_PUBLIC_API(uint32)
1132 JS_ToggleOptions(JSContext *cx, uint32 options)
1134 AutoLockGC lock(cx->runtime);
1135 CheckOptionVersionSync(cx);
1136 uint32 oldopts = cx->options;
1137 cx->options ^= options;
1138 (void) SyncOptionsToVersion(cx);
1139 cx->updateJITEnabled();
1140 CheckOptionVersionSync(cx);
1141 return oldopts;
1144 JS_PUBLIC_API(const char *)
1145 JS_GetImplementationVersion(void)
1147 return "JavaScript-C 1.8.0 pre-release 1 2007-10-03";
1150 JS_PUBLIC_API(JSCompartmentCallback)
1151 JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback)
1153 JSCompartmentCallback old = rt->compartmentCallback;
1154 rt->compartmentCallback = callback;
1155 return old;
1158 JS_PUBLIC_API(JSWrapObjectCallback)
1159 JS_SetWrapObjectCallback(JSContext *cx, JSWrapObjectCallback callback)
1161 JSRuntime *rt = cx->runtime;
1162 JSWrapObjectCallback old = rt->wrapObjectCallback;
1163 rt->wrapObjectCallback = callback;
1164 return old;
1167 JS_PUBLIC_API(JSCrossCompartmentCall *)
1168 JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
1170 CHECK_REQUEST(cx);
1172 JS_ASSERT(target);
1173 AutoCompartment *call = new AutoCompartment(cx, target);
1174 if (!call)
1175 return NULL;
1176 if (!call->enter()) {
1177 delete call;
1178 return NULL;
1180 return reinterpret_cast<JSCrossCompartmentCall *>(call);
1183 JS_PUBLIC_API(void)
1184 JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
1186 AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
1187 CHECK_REQUEST(realcall->context);
1188 realcall->leave();
1189 delete realcall;
1192 bool
1193 JSAutoCrossCompartmentCall::enter(JSContext *cx, JSObject *target)
1195 JS_ASSERT(!call);
1196 if (cx->compartment == target->getCompartment(cx))
1197 return true;
1198 call = JS_EnterCrossCompartmentCall(cx, target);
1199 return call != NULL;
1202 JS_FRIEND_API(JSCompartment *)
1203 js_SwitchToCompartment(JSContext *cx, JSCompartment *compartment)
1205 JSCompartment *c = cx->compartment;
1206 cx->compartment = compartment;
1207 return c;
1210 JS_FRIEND_API(JSCompartment *)
1211 js_SwitchToObjectCompartment(JSContext *cx, JSObject *obj)
1213 JSCompartment *c = cx->compartment;
1214 cx->compartment = obj->getCompartment(cx);
1215 return c;
1218 JS_PUBLIC_API(void *)
1219 JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data)
1221 CHECK_REQUEST(cx);
1222 void *old = compartment->data;
1223 compartment->data = data;
1224 return old;
1227 JS_PUBLIC_API(void *)
1228 JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment)
1230 CHECK_REQUEST(cx);
1231 return compartment->data;
1234 JS_PUBLIC_API(JSBool)
1235 JS_WrapObject(JSContext *cx, JSObject **objp)
1237 CHECK_REQUEST(cx);
1238 return cx->compartment->wrap(cx, objp);
1241 JS_PUBLIC_API(JSBool)
1242 JS_WrapValue(JSContext *cx, jsval *vp)
1244 CHECK_REQUEST(cx);
1245 return cx->compartment->wrap(cx, Valueify(vp));
1248 JS_PUBLIC_API(JSObject *)
1249 JS_GetGlobalObject(JSContext *cx)
1251 return cx->globalObject;
1254 JS_PUBLIC_API(void)
1255 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1257 CHECK_REQUEST(cx);
1259 cx->globalObject = obj;
1260 if (!cx->maybefp())
1261 cx->compartment = obj ? obj->getCompartment(cx) : cx->runtime->defaultCompartment;
1264 class AutoResolvingEntry {
1265 public:
1266 AutoResolvingEntry() : entry(NULL) {}
1269 * Returns false on error. But N.B. if obj[id] was already being resolved,
1270 * this is a no-op, and we silently treat that as success.
1272 bool start(JSContext *cx, JSObject *obj, jsid id, uint32 flag) {
1273 JS_ASSERT(!entry);
1274 this->cx = cx;
1275 key.obj = obj;
1276 key.id = id;
1277 this->flag = flag;
1278 bool ok = !!js_StartResolving(cx, &key, flag, &entry);
1279 JS_ASSERT_IF(!ok, !entry);
1280 return ok;
1283 ~AutoResolvingEntry() {
1284 if (entry)
1285 js_StopResolving(cx, &key, flag, NULL, 0);
1288 private:
1289 JSContext *cx;
1290 JSResolvingKey key;
1291 uint32 flag;
1292 JSResolvingEntry *entry;
1295 JSObject *
1296 js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1298 JSObject *fun_proto, *obj_proto;
1300 /* If cx has no global object, use obj so prototypes can be found. */
1301 if (!cx->globalObject)
1302 JS_SetGlobalObject(cx, obj);
1304 /* Record Function and Object in cx->resolvingTable. */
1305 AutoResolvingEntry e1, e2;
1306 JSAtom **classAtoms = cx->runtime->atomState.classAtoms;
1307 if (!e1.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Function]), JSRESFLAG_LOOKUP) ||
1308 !e2.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Object]), JSRESFLAG_LOOKUP)) {
1309 return NULL;
1312 /* Initialize the function class first so constructors can be made. */
1313 if (!js_GetClassPrototype(cx, obj, JSProto_Function, &fun_proto))
1314 return NULL;
1315 if (!fun_proto) {
1316 fun_proto = js_InitFunctionClass(cx, obj);
1317 if (!fun_proto)
1318 return NULL;
1319 } else {
1320 JSObject *ctor;
1322 ctor = JS_GetConstructor(cx, fun_proto);
1323 if (!ctor)
1324 return NULL;
1325 obj->defineProperty(cx, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
1326 ObjectValue(*ctor), 0, 0, 0);
1329 /* Initialize the object class next so Object.prototype works. */
1330 if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto))
1331 return NULL;
1332 if (!obj_proto)
1333 obj_proto = js_InitObjectClass(cx, obj);
1334 if (!obj_proto)
1335 return NULL;
1337 /* Function.prototype and the global object delegate to Object.prototype. */
1338 fun_proto->setProto(obj_proto);
1339 if (!obj->getProto())
1340 obj->setProto(obj_proto);
1342 return fun_proto;
1345 JS_PUBLIC_API(JSBool)
1346 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1348 CHECK_REQUEST(cx);
1351 * JS_SetGlobalObject might or might not change cx's compartment, so call
1352 * it before assertSameCompartment. (The API contract is that *after* this,
1353 * cx and obj must be in the same compartment.)
1355 if (!cx->globalObject)
1356 JS_SetGlobalObject(cx, obj);
1357 assertSameCompartment(cx, obj);
1359 /* Define a top-level property 'undefined' with the undefined value. */
1360 JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1361 if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1362 PropertyStub, PropertyStub,
1363 JSPROP_PERMANENT | JSPROP_READONLY)) {
1364 return JS_FALSE;
1367 /* Function and Object require cooperative bootstrapping magic. */
1368 if (!js_InitFunctionAndObjectClasses(cx, obj))
1369 return JS_FALSE;
1371 /* Initialize the rest of the standard objects and functions. */
1372 return js_InitArrayClass(cx, obj) &&
1373 js_InitBooleanClass(cx, obj) &&
1374 js_InitExceptionClasses(cx, obj) &&
1375 js_InitMathClass(cx, obj) &&
1376 js_InitNumberClass(cx, obj) &&
1377 js_InitJSONClass(cx, obj) &&
1378 js_InitRegExpClass(cx, obj) &&
1379 js_InitStringClass(cx, obj) &&
1380 js_InitTypedArrayClasses(cx, obj) &&
1381 #if JS_HAS_XML_SUPPORT
1382 js_InitXMLClasses(cx, obj) &&
1383 #endif
1384 #if JS_HAS_GENERATORS
1385 js_InitIteratorClasses(cx, obj) &&
1386 #endif
1387 js_InitDateClass(cx, obj) &&
1388 js_InitProxyClass(cx, obj);
1391 #define CLASP(name) (&js_##name##Class)
1392 #define TYPED_ARRAY_CLASP(type) (&TypedArray::fastClasses[TypedArray::type])
1393 #define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
1394 #define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
1395 #define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
1396 #define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
1398 typedef struct JSStdName {
1399 JSObjectOp init;
1400 size_t atomOffset; /* offset of atom pointer in JSAtomState */
1401 const char *name; /* null if atom is pre-pinned, else name */
1402 Class *clasp;
1403 } JSStdName;
1405 static JSAtom *
1406 StdNameToAtom(JSContext *cx, JSStdName *stdn)
1408 size_t offset;
1409 JSAtom *atom;
1410 const char *name;
1412 offset = stdn->atomOffset;
1413 atom = OFFSET_TO_ATOM(cx->runtime, offset);
1414 if (!atom) {
1415 name = stdn->name;
1416 if (name) {
1417 atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1418 OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1421 return atom;
1425 * Table of class initializers and their atom offsets in rt->atomState.
1426 * If you add a "standard" class, remember to update this table.
1428 static JSStdName standard_class_atoms[] = {
1429 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Function)},
1430 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Object)},
1431 {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)},
1432 {js_InitBooleanClass, EAGER_ATOM_AND_CLASP(Boolean)},
1433 {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)},
1434 {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)},
1435 {js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)},
1436 {js_InitStringClass, EAGER_ATOM_AND_CLASP(String)},
1437 {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)},
1438 {js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)},
1439 #if JS_HAS_XML_SUPPORT
1440 {js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)},
1441 {js_InitNamespaceClass, EAGER_ATOM_AND_CLASP(Namespace)},
1442 {js_InitQNameClass, EAGER_ATOM_AND_CLASP(QName)},
1443 #endif
1444 #if JS_HAS_GENERATORS
1445 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
1446 #endif
1447 {js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
1448 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
1449 {NULL, 0, NULL, NULL}
1453 * Table of top-level function and constant names and their init functions.
1454 * If you add a "standard" global function or property, remember to update
1455 * this table.
1457 static JSStdName standard_class_names[] = {
1458 {js_InitObjectClass, EAGER_ATOM(eval), CLASP(Object)},
1460 /* Global properties and functions defined by the Number class. */
1461 {js_InitNumberClass, LAZY_ATOM(NaN), CLASP(Number)},
1462 {js_InitNumberClass, LAZY_ATOM(Infinity), CLASP(Number)},
1463 {js_InitNumberClass, LAZY_ATOM(isNaN), CLASP(Number)},
1464 {js_InitNumberClass, LAZY_ATOM(isFinite), CLASP(Number)},
1465 {js_InitNumberClass, LAZY_ATOM(parseFloat), CLASP(Number)},
1466 {js_InitNumberClass, LAZY_ATOM(parseInt), CLASP(Number)},
1468 /* String global functions. */
1469 {js_InitStringClass, LAZY_ATOM(escape), CLASP(String)},
1470 {js_InitStringClass, LAZY_ATOM(unescape), CLASP(String)},
1471 {js_InitStringClass, LAZY_ATOM(decodeURI), CLASP(String)},
1472 {js_InitStringClass, LAZY_ATOM(encodeURI), CLASP(String)},
1473 {js_InitStringClass, LAZY_ATOM(decodeURIComponent), CLASP(String)},
1474 {js_InitStringClass, LAZY_ATOM(encodeURIComponent), CLASP(String)},
1475 #if JS_HAS_UNEVAL
1476 {js_InitStringClass, LAZY_ATOM(uneval), CLASP(String)},
1477 #endif
1479 /* Exception constructors. */
1480 {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)},
1481 {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
1482 {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
1483 {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
1484 {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
1485 {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
1486 {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
1487 {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)},
1489 #if JS_HAS_XML_SUPPORT
1490 {js_InitAnyNameClass, EAGER_ATOM_AND_CLASP(AnyName)},
1491 {js_InitAttributeNameClass, EAGER_ATOM_AND_CLASP(AttributeName)},
1492 {js_InitXMLClass, LAZY_ATOM(XMLList), CLASP(XML)},
1493 {js_InitXMLClass, LAZY_ATOM(isXMLName), CLASP(XML)},
1494 #endif
1496 #if JS_HAS_GENERATORS
1497 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)},
1498 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Generator)},
1499 #endif
1501 /* Typed Arrays */
1502 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
1503 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int8Array), TYPED_ARRAY_CLASP(TYPE_INT8)},
1504 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8Array), TYPED_ARRAY_CLASP(TYPE_UINT8)},
1505 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int16Array), TYPED_ARRAY_CLASP(TYPE_INT16)},
1506 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint16Array), TYPED_ARRAY_CLASP(TYPE_UINT16)},
1507 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int32Array), TYPED_ARRAY_CLASP(TYPE_INT32)},
1508 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint32Array), TYPED_ARRAY_CLASP(TYPE_UINT32)},
1509 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float32Array), TYPED_ARRAY_CLASP(TYPE_FLOAT32)},
1510 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
1511 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8ClampedArray),
1512 TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
1514 {js_InitProxyClass, EAGER_ATOM_AND_CLASP(Proxy)},
1516 {NULL, 0, NULL, NULL}
1519 static JSStdName object_prototype_names[] = {
1520 /* Object.prototype properties (global delegates to Object.prototype). */
1521 {js_InitObjectClass, EAGER_ATOM(proto), CLASP(Object)},
1522 #if JS_HAS_TOSOURCE
1523 {js_InitObjectClass, EAGER_ATOM(toSource), CLASP(Object)},
1524 #endif
1525 {js_InitObjectClass, EAGER_ATOM(toString), CLASP(Object)},
1526 {js_InitObjectClass, EAGER_ATOM(toLocaleString), CLASP(Object)},
1527 {js_InitObjectClass, EAGER_ATOM(valueOf), CLASP(Object)},
1528 #if JS_HAS_OBJ_WATCHPOINT
1529 {js_InitObjectClass, LAZY_ATOM(watch), CLASP(Object)},
1530 {js_InitObjectClass, LAZY_ATOM(unwatch), CLASP(Object)},
1531 #endif
1532 {js_InitObjectClass, LAZY_ATOM(hasOwnProperty), CLASP(Object)},
1533 {js_InitObjectClass, LAZY_ATOM(isPrototypeOf), CLASP(Object)},
1534 {js_InitObjectClass, LAZY_ATOM(propertyIsEnumerable), CLASP(Object)},
1535 #if OLD_GETTER_SETTER_METHODS
1536 {js_InitObjectClass, LAZY_ATOM(defineGetter), CLASP(Object)},
1537 {js_InitObjectClass, LAZY_ATOM(defineSetter), CLASP(Object)},
1538 {js_InitObjectClass, LAZY_ATOM(lookupGetter), CLASP(Object)},
1539 {js_InitObjectClass, LAZY_ATOM(lookupSetter), CLASP(Object)},
1540 #endif
1542 {NULL, 0, NULL, NULL}
1545 JS_PUBLIC_API(JSBool)
1546 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
1548 JSString *idstr;
1549 JSRuntime *rt;
1550 JSAtom *atom;
1551 JSStdName *stdnm;
1552 uintN i;
1554 CHECK_REQUEST(cx);
1555 assertSameCompartment(cx, obj, id);
1556 *resolved = JS_FALSE;
1558 rt = cx->runtime;
1559 JS_ASSERT(rt->state != JSRTS_DOWN);
1560 if (rt->state == JSRTS_LANDING || !JSID_IS_ATOM(id))
1561 return JS_TRUE;
1563 idstr = JSID_TO_STRING(id);
1565 /* Check whether we're resolving 'undefined', and define it if so. */
1566 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1567 if (idstr == ATOM_TO_STRING(atom)) {
1568 *resolved = JS_TRUE;
1569 return obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1570 PropertyStub, PropertyStub,
1571 JSPROP_PERMANENT | JSPROP_READONLY);
1574 /* Try for class constructors/prototypes named by well-known atoms. */
1575 stdnm = NULL;
1576 for (i = 0; standard_class_atoms[i].init; i++) {
1577 JS_ASSERT(standard_class_atoms[i].clasp);
1578 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1579 if (idstr == ATOM_TO_STRING(atom)) {
1580 stdnm = &standard_class_atoms[i];
1581 break;
1585 if (!stdnm) {
1586 /* Try less frequently used top-level functions and constants. */
1587 for (i = 0; standard_class_names[i].init; i++) {
1588 JS_ASSERT(standard_class_names[i].clasp);
1589 atom = StdNameToAtom(cx, &standard_class_names[i]);
1590 if (!atom)
1591 return JS_FALSE;
1592 if (idstr == ATOM_TO_STRING(atom)) {
1593 stdnm = &standard_class_names[i];
1594 break;
1598 if (!stdnm && !obj->getProto()) {
1600 * Try even less frequently used names delegated from the global
1601 * object to Object.prototype, but only if the Object class hasn't
1602 * yet been initialized.
1604 for (i = 0; object_prototype_names[i].init; i++) {
1605 JS_ASSERT(object_prototype_names[i].clasp);
1606 atom = StdNameToAtom(cx, &object_prototype_names[i]);
1607 if (!atom)
1608 return JS_FALSE;
1609 if (idstr == ATOM_TO_STRING(atom)) {
1610 stdnm = &object_prototype_names[i];
1611 break;
1617 if (stdnm) {
1619 * If this standard class is anonymous, then we don't want to resolve
1620 * by name.
1622 JS_ASSERT(obj->getClass()->flags & JSCLASS_IS_GLOBAL);
1623 if (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)
1624 return JS_TRUE;
1626 JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(stdnm->clasp);
1627 if (obj->getReservedSlot(key).isObject())
1628 return JS_TRUE;
1630 if (!stdnm->init(cx, obj))
1631 return JS_FALSE;
1632 *resolved = JS_TRUE;
1634 return JS_TRUE;
1637 static JSBool
1638 AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom)
1640 JS_LOCK_OBJ(cx, obj);
1641 bool found = obj->nativeContains(ATOM_TO_JSID(atom));
1642 JS_UNLOCK_OBJ(cx, obj);
1643 return found;
1646 JS_PUBLIC_API(JSBool)
1647 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1649 JSRuntime *rt;
1650 JSAtom *atom;
1651 uintN i;
1653 CHECK_REQUEST(cx);
1654 assertSameCompartment(cx, obj);
1655 rt = cx->runtime;
1657 /* Check whether we need to bind 'undefined' and define it if so. */
1658 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1659 if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1660 !obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1661 PropertyStub, PropertyStub,
1662 JSPROP_PERMANENT | JSPROP_READONLY)) {
1663 return JS_FALSE;
1666 /* Initialize any classes that have not been resolved yet. */
1667 for (i = 0; standard_class_atoms[i].init; i++) {
1668 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1669 if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1670 !standard_class_atoms[i].init(cx, obj)) {
1671 return JS_FALSE;
1675 return JS_TRUE;
1678 namespace js {
1680 JSIdArray *
1681 NewIdArray(JSContext *cx, jsint length)
1683 JSIdArray *ida;
1685 ida = (JSIdArray *)
1686 cx->calloc(offsetof(JSIdArray, vector) + length * sizeof(jsval));
1687 if (ida)
1688 ida->length = length;
1689 return ida;
1695 * Unlike realloc(3), this function frees ida on failure.
1697 static JSIdArray *
1698 SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
1700 JSIdArray *rida;
1702 rida = (JSIdArray *)
1703 JS_realloc(cx, ida,
1704 offsetof(JSIdArray, vector) + length * sizeof(jsval));
1705 if (!rida) {
1706 JS_DestroyIdArray(cx, ida);
1707 } else {
1708 rida->length = length;
1710 return rida;
1713 static JSIdArray *
1714 AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1716 jsint i, length;
1718 i = *ip;
1719 length = ida->length;
1720 if (i >= length) {
1721 ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
1722 if (!ida)
1723 return NULL;
1724 JS_ASSERT(i < ida->length);
1726 ida->vector[i] = ATOM_TO_JSID(atom);
1727 *ip = i + 1;
1728 return ida;
1731 static JSIdArray *
1732 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
1733 jsint *ip, JSBool *foundp)
1735 *foundp = AlreadyHasOwnProperty(cx, obj, atom);
1736 if (*foundp)
1737 ida = AddAtomToArray(cx, atom, ida, ip);
1738 return ida;
1741 JS_PUBLIC_API(JSIdArray *)
1742 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, JSIdArray *ida)
1744 JSRuntime *rt;
1745 jsint i, j, k;
1746 JSAtom *atom;
1747 JSBool found;
1748 JSObjectOp init;
1750 CHECK_REQUEST(cx);
1751 assertSameCompartment(cx, obj, ida);
1752 rt = cx->runtime;
1753 if (ida) {
1754 i = ida->length;
1755 } else {
1756 ida = NewIdArray(cx, 8);
1757 if (!ida)
1758 return NULL;
1759 i = 0;
1762 /* Check whether 'undefined' has been resolved and enumerate it if so. */
1763 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1764 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1765 if (!ida)
1766 return NULL;
1768 /* Enumerate only classes that *have* been resolved. */
1769 for (j = 0; standard_class_atoms[j].init; j++) {
1770 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
1771 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1772 if (!ida)
1773 return NULL;
1775 if (found) {
1776 init = standard_class_atoms[j].init;
1778 for (k = 0; standard_class_names[k].init; k++) {
1779 if (standard_class_names[k].init == init) {
1780 atom = StdNameToAtom(cx, &standard_class_names[k]);
1781 ida = AddAtomToArray(cx, atom, ida, &i);
1782 if (!ida)
1783 return NULL;
1787 if (init == js_InitObjectClass) {
1788 for (k = 0; object_prototype_names[k].init; k++) {
1789 atom = StdNameToAtom(cx, &object_prototype_names[k]);
1790 ida = AddAtomToArray(cx, atom, ida, &i);
1791 if (!ida)
1792 return NULL;
1798 /* Trim to exact length. */
1799 return SetIdArrayLength(cx, ida, i);
1802 #undef CLASP
1803 #undef EAGER_ATOM
1804 #undef EAGER_CLASS_ATOM
1805 #undef EAGER_ATOM_CLASP
1806 #undef LAZY_ATOM
1808 JS_PUBLIC_API(JSBool)
1809 JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp)
1811 CHECK_REQUEST(cx);
1812 assertSameCompartment(cx, obj);
1813 return js_GetClassObject(cx, obj, key, objp);
1816 JS_PUBLIC_API(JSObject *)
1817 JS_GetScopeChain(JSContext *cx)
1819 JSStackFrame *fp;
1821 CHECK_REQUEST(cx);
1822 fp = js_GetTopStackFrame(cx);
1823 if (!fp) {
1825 * There is no code active on this context. In place of an actual
1826 * scope chain, use the context's global object, which is set in
1827 * js_InitFunctionAndObjectClasses, and which represents the default
1828 * scope chain for the embedding. See also js_FindClassObject.
1830 * For embeddings that use the inner and outer object hooks, the inner
1831 * object represents the ultimate global object, with the outer object
1832 * acting as a stand-in.
1834 JSObject *obj = cx->globalObject;
1835 if (!obj) {
1836 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
1837 return NULL;
1840 OBJ_TO_INNER_OBJECT(cx, obj);
1841 return obj;
1843 return js_GetScopeChain(cx, fp);
1846 JS_PUBLIC_API(JSObject *)
1847 JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
1849 assertSameCompartment(cx, obj);
1850 return obj->getGlobal();
1853 JS_PUBLIC_API(JSObject *)
1854 JS_GetGlobalForScopeChain(JSContext *cx)
1857 * This is essentially JS_GetScopeChain(cx)->getGlobal(), but without
1858 * falling off trace.
1860 * This use of cx->fp, possibly on trace, is deliberate:
1861 * cx->fp->scopeChain->getGlobal() returns the same object whether we're on
1862 * trace or not, since we do not trace calls across global objects.
1864 VOUCH_DOES_NOT_REQUIRE_STACK();
1866 if (cx->hasfp())
1867 return cx->fp()->scopeChain().getGlobal();
1869 JSObject *scope = cx->globalObject;
1870 if (!scope) {
1871 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
1872 return NULL;
1874 OBJ_TO_INNER_OBJECT(cx, scope);
1875 return scope;
1878 JS_PUBLIC_API(jsval)
1879 JS_ComputeThis(JSContext *cx, jsval *vp)
1881 assertSameCompartment(cx, JSValueArray(vp, 2));
1882 if (!ComputeThisFromVp(cx, Valueify(vp)))
1883 return JSVAL_NULL;
1884 return vp[1];
1887 JS_PUBLIC_API(void *)
1888 JS_malloc(JSContext *cx, size_t nbytes)
1890 return cx->malloc(nbytes);
1893 JS_PUBLIC_API(void *)
1894 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1896 return cx->realloc(p, nbytes);
1899 JS_PUBLIC_API(void)
1900 JS_free(JSContext *cx, void *p)
1902 return cx->free(p);
1905 JS_PUBLIC_API(void)
1906 JS_updateMallocCounter(JSContext *cx, size_t nbytes)
1908 return cx->runtime->updateMallocCounter(nbytes);
1911 JS_PUBLIC_API(char *)
1912 JS_strdup(JSContext *cx, const char *s)
1914 size_t n;
1915 void *p;
1917 n = strlen(s) + 1;
1918 p = cx->malloc(n);
1919 if (!p)
1920 return NULL;
1921 return (char *)memcpy(p, s, n);
1924 JS_PUBLIC_API(JSBool)
1925 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
1927 d = JS_CANONICALIZE_NAN(d);
1928 Valueify(rval)->setNumber(d);
1929 return JS_TRUE;
1932 #undef JS_AddRoot
1934 JS_PUBLIC_API(JSBool)
1935 JS_AddValueRoot(JSContext *cx, jsval *vp)
1937 CHECK_REQUEST(cx);
1938 return js_AddRoot(cx, Valueify(vp), NULL);
1941 JS_PUBLIC_API(JSBool)
1942 JS_AddStringRoot(JSContext *cx, JSString **rp)
1944 CHECK_REQUEST(cx);
1945 return js_AddGCThingRoot(cx, (void **)rp, NULL);
1948 JS_PUBLIC_API(JSBool)
1949 JS_AddObjectRoot(JSContext *cx, JSObject **rp)
1951 CHECK_REQUEST(cx);
1952 return js_AddGCThingRoot(cx, (void **)rp, NULL);
1955 JS_PUBLIC_API(JSBool)
1956 JS_AddGCThingRoot(JSContext *cx, void **rp)
1958 CHECK_REQUEST(cx);
1959 return js_AddGCThingRoot(cx, (void **)rp, NULL);
1962 JS_PUBLIC_API(JSBool)
1963 JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name)
1965 CHECK_REQUEST(cx);
1966 return js_AddRoot(cx, Valueify(vp), name);
1969 JS_PUBLIC_API(JSBool)
1970 JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name)
1972 CHECK_REQUEST(cx);
1973 return js_AddGCThingRoot(cx, (void **)rp, name);
1976 JS_PUBLIC_API(JSBool)
1977 JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name)
1979 CHECK_REQUEST(cx);
1980 return js_AddGCThingRoot(cx, (void **)rp, name);
1983 JS_PUBLIC_API(JSBool)
1984 JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name)
1986 CHECK_REQUEST(cx);
1987 return js_AddGCThingRoot(cx, (void **)rp, name);
1990 JS_PUBLIC_API(JSBool)
1991 JS_RemoveValueRoot(JSContext *cx, jsval *vp)
1993 CHECK_REQUEST(cx);
1994 return js_RemoveRoot(cx->runtime, (void *)vp);
1997 JS_PUBLIC_API(JSBool)
1998 JS_RemoveStringRoot(JSContext *cx, JSString **rp)
2000 CHECK_REQUEST(cx);
2001 return js_RemoveRoot(cx->runtime, (void *)rp);
2004 JS_PUBLIC_API(JSBool)
2005 JS_RemoveObjectRoot(JSContext *cx, JSObject **rp)
2007 CHECK_REQUEST(cx);
2008 return js_RemoveRoot(cx->runtime, (void *)rp);
2011 JS_PUBLIC_API(JSBool)
2012 JS_RemoveGCThingRoot(JSContext *cx, void **rp)
2014 CHECK_REQUEST(cx);
2015 return js_RemoveRoot(cx->runtime, (void *)rp);
2018 #ifdef DEBUG
2020 JS_PUBLIC_API(void)
2021 JS_DumpNamedRoots(JSRuntime *rt,
2022 void (*dump)(const char *name, void *rp, JSGCRootType type, void *data),
2023 void *data)
2025 js_DumpNamedRoots(rt, dump, data);
2028 #endif /* DEBUG */
2030 JS_PUBLIC_API(uint32)
2031 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
2033 return js_MapGCRoots(rt, map, data);
2036 JS_PUBLIC_API(JSBool)
2037 JS_LockGCThing(JSContext *cx, void *thing)
2039 JSBool ok;
2041 CHECK_REQUEST(cx);
2042 ok = js_LockGCThingRT(cx->runtime, thing);
2043 if (!ok)
2044 JS_ReportOutOfMemory(cx);
2045 return ok;
2048 JS_PUBLIC_API(JSBool)
2049 JS_LockGCThingRT(JSRuntime *rt, void *thing)
2051 return js_LockGCThingRT(rt, thing);
2054 JS_PUBLIC_API(JSBool)
2055 JS_UnlockGCThing(JSContext *cx, void *thing)
2057 CHECK_REQUEST(cx);
2058 js_UnlockGCThingRT(cx->runtime, thing);
2059 return true;
2062 JS_PUBLIC_API(JSBool)
2063 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
2065 js_UnlockGCThingRT(rt, thing);
2066 return true;
2069 JS_PUBLIC_API(void)
2070 JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
2072 rt->gcExtraRootsTraceOp = traceOp;
2073 rt->gcExtraRootsData = data;
2076 JS_PUBLIC_API(void)
2077 JS_TraceRuntime(JSTracer *trc)
2079 TraceRuntime(trc);
2082 JS_PUBLIC_API(void)
2083 JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
2085 JS_ASSERT(thing);
2086 Mark(trc, thing, kind);
2089 #ifdef DEBUG
2091 #ifdef HAVE_XPCONNECT
2092 #include "dump_xpc.h"
2093 #endif
2095 JS_PUBLIC_API(void)
2096 JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, uint32 kind,
2097 JSBool details)
2099 const char *name;
2100 size_t n;
2102 if (bufsize == 0)
2103 return;
2105 switch (kind) {
2106 case JSTRACE_OBJECT:
2108 JSObject *obj = (JSObject *)thing;
2109 Class *clasp = obj->getClass();
2111 name = clasp->name;
2112 #ifdef HAVE_XPCONNECT
2113 if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
2114 void *privateThing = obj->getPrivate();
2115 if (privateThing) {
2116 const char *xpcClassName = GetXPCObjectClassName(privateThing);
2117 if (xpcClassName)
2118 name = xpcClassName;
2121 #endif
2122 break;
2125 case JSTRACE_STRING:
2126 name = ((JSString *)thing)->isDependent()
2127 ? "substring"
2128 : "string";
2129 break;
2131 #if JS_HAS_XML_SUPPORT
2132 case JSTRACE_XML:
2133 name = "xml";
2134 break;
2135 #endif
2136 default:
2137 JS_ASSERT(0);
2138 return;
2139 break;
2142 n = strlen(name);
2143 if (n > bufsize - 1)
2144 n = bufsize - 1;
2145 memcpy(buf, name, n + 1);
2146 buf += n;
2147 bufsize -= n;
2149 if (details && bufsize > 2) {
2150 *buf++ = ' ';
2151 bufsize--;
2153 switch (kind) {
2154 case JSTRACE_OBJECT:
2156 JSObject *obj = (JSObject *)thing;
2157 Class *clasp = obj->getClass();
2158 if (clasp == &js_FunctionClass) {
2159 JSFunction *fun = GET_FUNCTION_PRIVATE(trc->context, obj);
2160 if (!fun) {
2161 JS_snprintf(buf, bufsize, "<newborn>");
2162 } else if (FUN_OBJECT(fun) != obj) {
2163 JS_snprintf(buf, bufsize, "%p", fun);
2164 } else {
2165 if (fun->atom)
2166 js_PutEscapedString(buf, bufsize, ATOM_TO_STRING(fun->atom), 0);
2168 } else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
2169 JS_snprintf(buf, bufsize, "%p", obj->getPrivate());
2170 } else {
2171 JS_snprintf(buf, bufsize, "<no private>");
2173 break;
2176 case JSTRACE_STRING:
2177 js_PutEscapedString(buf, bufsize, (JSString *)thing, 0);
2178 break;
2180 #if JS_HAS_XML_SUPPORT
2181 case JSTRACE_XML:
2183 extern const char *js_xml_class_str[];
2184 JSXML *xml = (JSXML *)thing;
2186 JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]);
2187 break;
2189 #endif
2190 default:
2191 JS_ASSERT(0);
2192 break;
2195 buf[bufsize - 1] = '\0';
2198 typedef struct JSHeapDumpNode JSHeapDumpNode;
2200 struct JSHeapDumpNode {
2201 void *thing;
2202 uint32 kind;
2203 JSHeapDumpNode *next; /* next sibling */
2204 JSHeapDumpNode *parent; /* node with the thing that refer to thing
2205 from this node */
2206 char edgeName[1]; /* name of the edge from parent->thing
2207 into thing */
2210 typedef struct JSDumpingTracer {
2211 JSTracer base;
2212 JSDHashTable visited;
2213 JSBool ok;
2214 void *startThing;
2215 void *thingToFind;
2216 void *thingToIgnore;
2217 JSHeapDumpNode *parentNode;
2218 JSHeapDumpNode **lastNodep;
2219 char buffer[200];
2220 } JSDumpingTracer;
2222 static void
2223 DumpNotify(JSTracer *trc, void *thing, uint32 kind)
2225 JSDumpingTracer *dtrc;
2226 JSContext *cx;
2227 JSDHashEntryStub *entry;
2228 JSHeapDumpNode *node;
2229 const char *edgeName;
2230 size_t edgeNameSize;
2232 JS_ASSERT(trc->callback == DumpNotify);
2233 dtrc = (JSDumpingTracer *)trc;
2235 if (!dtrc->ok || thing == dtrc->thingToIgnore)
2236 return;
2238 cx = trc->context;
2241 * Check if we have already seen thing unless it is thingToFind to include
2242 * it to the graph each time we reach it and print all live things that
2243 * refer to thingToFind.
2245 * This does not print all possible paths leading to thingToFind since
2246 * when a thing A refers directly or indirectly to thingToFind and A is
2247 * present several times in the graph, we will print only the first path
2248 * leading to A and thingToFind, other ways to reach A will be ignored.
2250 if (dtrc->thingToFind != thing) {
2252 * The startThing check allows to avoid putting startThing into the
2253 * hash table before tracing startThing in JS_DumpHeap.
2255 if (thing == dtrc->startThing)
2256 return;
2257 entry = (JSDHashEntryStub *)
2258 JS_DHashTableOperate(&dtrc->visited, thing, JS_DHASH_ADD);
2259 if (!entry) {
2260 JS_ReportOutOfMemory(cx);
2261 dtrc->ok = JS_FALSE;
2262 return;
2264 if (entry->key)
2265 return;
2266 entry->key = thing;
2269 if (dtrc->base.debugPrinter) {
2270 dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer));
2271 edgeName = dtrc->buffer;
2272 } else if (dtrc->base.debugPrintIndex != (size_t)-1) {
2273 JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]",
2274 (const char *)dtrc->base.debugPrintArg,
2275 dtrc->base.debugPrintIndex);
2276 edgeName = dtrc->buffer;
2277 } else {
2278 edgeName = (const char*)dtrc->base.debugPrintArg;
2281 edgeNameSize = strlen(edgeName) + 1;
2282 node = (JSHeapDumpNode *)
2283 cx->malloc(offsetof(JSHeapDumpNode, edgeName) + edgeNameSize);
2284 if (!node) {
2285 dtrc->ok = JS_FALSE;
2286 return;
2289 node->thing = thing;
2290 node->kind = kind;
2291 node->next = NULL;
2292 node->parent = dtrc->parentNode;
2293 memcpy(node->edgeName, edgeName, edgeNameSize);
2295 JS_ASSERT(!*dtrc->lastNodep);
2296 *dtrc->lastNodep = node;
2297 dtrc->lastNodep = &node->next;
2300 /* Dump node and the chain that leads to thing it contains. */
2301 static JSBool
2302 DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
2304 JSHeapDumpNode *prev, *following;
2305 size_t chainLimit;
2306 JSBool ok;
2307 enum { MAX_PARENTS_TO_PRINT = 10 };
2309 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2310 &dtrc->base, node->thing, node->kind, JS_TRUE);
2311 if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
2312 return JS_FALSE;
2315 * We need to print the parent chain in the reverse order. To do it in
2316 * O(N) time where N is the chain length we first reverse the chain while
2317 * searching for the top and then print each node while restoring the
2318 * chain order.
2320 chainLimit = MAX_PARENTS_TO_PRINT;
2321 prev = NULL;
2322 for (;;) {
2323 following = node->parent;
2324 node->parent = prev;
2325 prev = node;
2326 node = following;
2327 if (!node)
2328 break;
2329 if (chainLimit == 0) {
2330 if (fputs("...", fp) < 0)
2331 return JS_FALSE;
2332 break;
2334 --chainLimit;
2337 node = prev;
2338 prev = following;
2339 ok = JS_TRUE;
2340 do {
2341 /* Loop must continue even when !ok to restore the parent chain. */
2342 if (ok) {
2343 if (!prev) {
2344 /* Print edge from some runtime root or startThing. */
2345 if (fputs(node->edgeName, fp) < 0)
2346 ok = JS_FALSE;
2347 } else {
2348 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2349 &dtrc->base, prev->thing, prev->kind,
2350 JS_FALSE);
2351 if (fprintf(fp, "(%p %s).%s",
2352 prev->thing, dtrc->buffer, node->edgeName) < 0) {
2353 ok = JS_FALSE;
2357 following = node->parent;
2358 node->parent = prev;
2359 prev = node;
2360 node = following;
2361 } while (node);
2363 return ok && putc('\n', fp) >= 0;
2366 JS_PUBLIC_API(JSBool)
2367 JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind,
2368 void *thingToFind, size_t maxDepth, void *thingToIgnore)
2370 JSDumpingTracer dtrc;
2371 JSHeapDumpNode *node, *children, *next, *parent;
2372 size_t depth;
2373 JSBool thingToFindWasTraced;
2375 if (maxDepth == 0)
2376 return JS_TRUE;
2378 JS_TRACER_INIT(&dtrc.base, cx, DumpNotify);
2379 if (!JS_DHashTableInit(&dtrc.visited, JS_DHashGetStubOps(),
2380 NULL, sizeof(JSDHashEntryStub),
2381 JS_DHASH_DEFAULT_CAPACITY(100))) {
2382 JS_ReportOutOfMemory(cx);
2383 return JS_FALSE;
2385 dtrc.ok = JS_TRUE;
2386 dtrc.startThing = startThing;
2387 dtrc.thingToFind = thingToFind;
2388 dtrc.thingToIgnore = thingToIgnore;
2389 dtrc.parentNode = NULL;
2390 node = NULL;
2391 dtrc.lastNodep = &node;
2392 if (!startThing) {
2393 JS_ASSERT(startKind == 0);
2394 TraceRuntime(&dtrc.base);
2395 } else {
2396 JS_TraceChildren(&dtrc.base, startThing, startKind);
2399 depth = 1;
2400 if (!node)
2401 goto dump_out;
2403 thingToFindWasTraced = thingToFind && thingToFind == startThing;
2404 for (;;) {
2406 * Loop must continue even when !dtrc.ok to free all nodes allocated
2407 * so far.
2409 if (dtrc.ok) {
2410 if (thingToFind == NULL || thingToFind == node->thing)
2411 dtrc.ok = DumpNode(&dtrc, fp, node);
2413 /* Descend into children. */
2414 if (dtrc.ok &&
2415 depth < maxDepth &&
2416 (thingToFind != node->thing || !thingToFindWasTraced)) {
2417 dtrc.parentNode = node;
2418 children = NULL;
2419 dtrc.lastNodep = &children;
2420 JS_TraceChildren(&dtrc.base, node->thing, node->kind);
2421 if (thingToFind == node->thing)
2422 thingToFindWasTraced = JS_TRUE;
2423 if (children != NULL) {
2424 ++depth;
2425 node = children;
2426 continue;
2431 /* Move to next or parents next and free the node. */
2432 for (;;) {
2433 next = node->next;
2434 parent = node->parent;
2435 cx->free(node);
2436 node = next;
2437 if (node)
2438 break;
2439 if (!parent)
2440 goto dump_out;
2441 JS_ASSERT(depth > 1);
2442 --depth;
2443 node = parent;
2447 dump_out:
2448 JS_ASSERT(depth == 1);
2449 JS_DHashTableFinish(&dtrc.visited);
2450 return dtrc.ok;
2453 #endif /* DEBUG */
2455 JS_PUBLIC_API(void)
2456 JS_MarkGCThing(JSContext *cx, jsval v, const char *name, void *arg)
2458 JSTracer *trc;
2460 trc = (JSTracer *)arg;
2461 if (!trc)
2462 trc = cx->runtime->gcMarkingTracer;
2463 else
2464 JS_ASSERT(trc == cx->runtime->gcMarkingTracer);
2466 #ifdef JS_THREADSAFE
2467 JS_ASSERT(cx->runtime->gcThread == trc->context->thread);
2468 #endif
2469 MarkValue(trc, Valueify(v), name ? name : "unknown");
2472 extern JS_PUBLIC_API(JSBool)
2473 JS_IsGCMarkingTracer(JSTracer *trc)
2475 return IS_GC_MARKING_TRACER(trc);
2478 JS_PUBLIC_API(void)
2479 JS_GC(JSContext *cx)
2481 LeaveTrace(cx);
2483 /* Don't nuke active arenas if executing or compiling. */
2484 if (cx->tempPool.current == &cx->tempPool.first)
2485 JS_FinishArenaPool(&cx->tempPool);
2486 js_GC(cx, GC_NORMAL);
2489 JS_PUBLIC_API(void)
2490 JS_MaybeGC(JSContext *cx)
2492 JSRuntime *rt;
2493 uint32 bytes, lastBytes;
2495 rt = cx->runtime;
2497 #ifdef JS_GC_ZEAL
2498 if (rt->gcZeal > 0) {
2499 JS_GC(cx);
2500 return;
2502 #endif
2504 bytes = rt->gcBytes;
2505 lastBytes = rt->gcLastBytes;
2508 * We run the GC if we used all available free GC cells and had to
2509 * allocate extra 1/3 of GC arenas since the last run of GC, or if
2510 * we have malloc'd more bytes through JS_malloc than we were told
2511 * to allocate by JS_NewRuntime.
2513 * The reason for
2514 * bytes > 4/3 lastBytes
2515 * condition is the following. Bug 312238 changed bytes and lastBytes
2516 * to mean the total amount of memory that the GC uses now and right
2517 * after the last GC.
2519 * Before the bug the variables meant the size of allocated GC things
2520 * now and right after the last GC. That size did not include the
2521 * memory taken by free GC cells and the condition was
2522 * bytes > 3/2 lastBytes.
2523 * That is, we run the GC if we have half again as many bytes of
2524 * GC-things as the last time we GC'd. To be compatible we need to
2525 * express that condition through the new meaning of bytes and
2526 * lastBytes.
2528 * We write the original condition as
2529 * B*(1-F) > 3/2 Bl*(1-Fl)
2530 * where B is the total memory size allocated by GC and F is the free
2531 * cell density currently and Sl and Fl are the size and the density
2532 * right after GC. The density by definition is memory taken by free
2533 * cells divided by total amount of memory. In other words, B and Bl
2534 * are bytes and lastBytes with the new meaning and B*(1-F) and
2535 * Bl*(1-Fl) are bytes and lastBytes with the original meaning.
2537 * Our task is to exclude F and Fl from the last statement. According
2538 * to the stats from bug 331966 comment 23, Fl is about 10-25% for a
2539 * typical run of the browser. It means that the original condition
2540 * implied that we did not run GC unless we exhausted the pool of
2541 * free cells. Indeed if we still have free cells, then B == Bl since
2542 * we did not yet allocated any new arenas and the condition means
2543 * 1 - F > 3/2 (1-Fl) or 3/2Fl > 1/2 + F
2544 * That implies 3/2 Fl > 1/2 or Fl > 1/3. That cannot be fulfilled
2545 * for the state described by the stats. So we can write the original
2546 * condition as:
2547 * F == 0 && B > 3/2 Bl(1-Fl)
2548 * Again using the stats we see that Fl is about 11% when the browser
2549 * starts up and when we are far from hitting rt->gcMaxBytes. With
2550 * this F we have
2551 * F == 0 && B > 3/2 Bl(1-0.11)
2552 * or approximately F == 0 && B > 4/3 Bl.
2554 if ((bytes > 8192 && bytes > lastBytes + lastBytes / 3) ||
2555 rt->isGCMallocLimitReached()) {
2556 JS_GC(cx);
2560 JS_PUBLIC_API(JSGCCallback)
2561 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
2563 CHECK_REQUEST(cx);
2564 return JS_SetGCCallbackRT(cx->runtime, cb);
2567 JS_PUBLIC_API(JSGCCallback)
2568 JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
2570 JSGCCallback oldcb;
2572 oldcb = rt->gcCallback;
2573 rt->gcCallback = cb;
2574 return oldcb;
2577 JS_PUBLIC_API(JSBool)
2578 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
2580 JS_ASSERT(thing);
2581 JS_ASSERT(!cx->runtime->gcMarkingTracer);
2582 return js_IsAboutToBeFinalized(thing);
2585 JS_PUBLIC_API(void)
2586 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
2588 switch (key) {
2589 case JSGC_MAX_BYTES:
2590 rt->gcMaxBytes = value;
2591 break;
2592 case JSGC_MAX_MALLOC_BYTES:
2593 rt->setGCMaxMallocBytes(value);
2594 break;
2595 case JSGC_STACKPOOL_LIFESPAN:
2596 rt->gcEmptyArenaPoolLifespan = value;
2597 break;
2598 default:
2599 JS_ASSERT(key == JSGC_TRIGGER_FACTOR);
2600 JS_ASSERT(value >= 100);
2601 rt->setGCTriggerFactor(value);
2602 return;
2606 JS_PUBLIC_API(uint32)
2607 JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
2609 switch (key) {
2610 case JSGC_MAX_BYTES:
2611 return rt->gcMaxBytes;
2612 case JSGC_MAX_MALLOC_BYTES:
2613 return rt->gcMaxMallocBytes;
2614 case JSGC_STACKPOOL_LIFESPAN:
2615 return rt->gcEmptyArenaPoolLifespan;
2616 case JSGC_TRIGGER_FACTOR:
2617 return rt->gcTriggerFactor;
2618 case JSGC_BYTES:
2619 return rt->gcBytes;
2620 default:
2621 JS_ASSERT(key == JSGC_NUMBER);
2622 return rt->gcNumber;
2626 JS_PUBLIC_API(void)
2627 JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32 value)
2629 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2630 #ifdef JS_TRACER
2631 SetMaxCodeCacheBytes(cx, value);
2632 #endif
2635 JS_PUBLIC_API(uint32)
2636 JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key)
2638 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2639 #ifdef JS_TRACER
2640 return JS_THREAD_DATA(cx)->traceMonitor.maxCodeCacheBytes;
2641 #else
2642 return 0;
2643 #endif
2646 JS_PUBLIC_API(void)
2647 JS_FlushCaches(JSContext *cx)
2649 #ifdef JS_TRACER
2650 FlushJITCache(cx);
2651 #endif
2654 JS_PUBLIC_API(intN)
2655 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
2657 return js_ChangeExternalStringFinalizer(NULL, finalizer);
2660 JS_PUBLIC_API(intN)
2661 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
2663 return js_ChangeExternalStringFinalizer(finalizer, NULL);
2666 JS_PUBLIC_API(JSString *)
2667 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
2669 CHECK_REQUEST(cx);
2670 JS_ASSERT(uintN(type) < JS_EXTERNAL_STRING_LIMIT);
2672 JSString *str = js_NewGCExternalString(cx, uintN(type));
2673 if (!str)
2674 return NULL;
2675 str->initFlat(chars, length);
2676 cx->runtime->updateMallocCounter((length + 1) * sizeof(jschar));
2677 return str;
2680 JS_PUBLIC_API(intN)
2681 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
2684 * No need to test this in js_GetExternalStringGCType, which asserts its
2685 * inverse instead of wasting cycles on testing a condition we can ensure
2686 * by auditing in-VM calls to the js_... helper.
2688 if (JSString::isStatic(str))
2689 return -1;
2691 return js_GetExternalStringGCType(str);
2694 JS_PUBLIC_API(void)
2695 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
2697 #if JS_STACK_GROWTH_DIRECTION > 0
2698 if (limitAddr == 0)
2699 limitAddr = jsuword(-1);
2700 #endif
2701 cx->stackLimit = limitAddr;
2704 JS_PUBLIC_API(void)
2705 JS_SetNativeStackQuota(JSContext *cx, size_t stackSize)
2707 #ifdef JS_THREADSAFE
2708 JS_ASSERT(cx->thread);
2709 #endif
2711 #if JS_STACK_GROWTH_DIRECTION > 0
2712 if (stackSize == 0) {
2713 cx->stackLimit = jsuword(-1);
2714 } else {
2715 jsuword stackBase = reinterpret_cast<jsuword>(JS_THREAD_DATA(cx)->nativeStackBase);
2716 JS_ASSERT(stackBase <= size_t(-1) - stackSize);
2717 cx->stackLimit = stackBase + stackSize - 1;
2719 #else
2720 if (stackSize == 0) {
2721 cx->stackLimit = 0;
2722 } else {
2723 jsuword stackBase = reinterpret_cast<jsuword>(JS_THREAD_DATA(cx)->nativeStackBase);
2724 JS_ASSERT(stackBase >= stackSize);
2725 cx->stackLimit = stackBase - (stackSize - 1);
2727 #endif
2730 JS_PUBLIC_API(void)
2731 JS_SetScriptStackQuota(JSContext *cx, size_t quota)
2733 cx->scriptStackQuota = quota;
2736 /************************************************************************/
2738 JS_PUBLIC_API(void)
2739 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
2741 cx->free(ida);
2744 JS_PUBLIC_API(JSBool)
2745 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
2747 CHECK_REQUEST(cx);
2748 assertSameCompartment(cx, v);
2749 return ValueToId(cx, Valueify(v), idp);
2752 JS_PUBLIC_API(JSBool)
2753 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
2755 CHECK_REQUEST(cx);
2756 *vp = IdToJsval(id);
2757 assertSameCompartment(cx, *vp);
2758 return JS_TRUE;
2761 JS_PUBLIC_API(JSBool)
2762 JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
2764 return JS_TRUE;
2767 JS_PUBLIC_API(JSBool)
2768 JS_EnumerateStub(JSContext *cx, JSObject *obj)
2770 return JS_TRUE;
2773 JS_PUBLIC_API(JSBool)
2774 JS_ResolveStub(JSContext *cx, JSObject *obj, jsid id)
2776 return JS_TRUE;
2779 JS_PUBLIC_API(JSBool)
2780 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
2782 JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION);
2783 return js_TryValueOf(cx, obj, type, Valueify(vp));
2786 JS_PUBLIC_API(void)
2787 JS_FinalizeStub(JSContext *cx, JSObject *obj)
2790 JS_PUBLIC_API(JSObject *)
2791 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
2792 JSClass *clasp, JSNative constructor, uintN nargs,
2793 JSPropertySpec *ps, JSFunctionSpec *fs,
2794 JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
2796 CHECK_REQUEST(cx);
2797 assertSameCompartment(cx, obj, parent_proto);
2798 return js_InitClass(cx, obj, parent_proto, Valueify(clasp),
2799 Valueify(constructor), nargs,
2800 ps, fs, static_ps, static_fs);
2803 #ifdef JS_THREADSAFE
2804 JS_PUBLIC_API(JSClass *)
2805 JS_GetClass(JSContext *cx, JSObject *obj)
2807 return Jsvalify(obj->getClass());
2809 #else
2810 JS_PUBLIC_API(JSClass *)
2811 JS_GetClass(JSObject *obj)
2813 return Jsvalify(obj->getClass());
2815 #endif
2817 JS_PUBLIC_API(JSBool)
2818 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2820 CHECK_REQUEST(cx);
2821 assertSameCompartment(cx, obj);
2822 return InstanceOf(cx, obj, Valueify(clasp), Valueify(argv));
2825 JS_PUBLIC_API(JSBool)
2826 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
2828 assertSameCompartment(cx, obj, v);
2829 return HasInstance(cx, obj, Valueify(&v), bp);
2832 JS_PUBLIC_API(void *)
2833 JS_GetPrivate(JSContext *cx, JSObject *obj)
2835 assertSameCompartment(cx, obj);
2836 return obj->getPrivate();
2839 JS_PUBLIC_API(JSBool)
2840 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2842 assertSameCompartment(cx, obj);
2843 obj->setPrivate(data);
2844 return true;
2847 JS_PUBLIC_API(void *)
2848 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2850 if (!InstanceOf(cx, obj, Valueify(clasp), Valueify(argv)))
2851 return NULL;
2852 return obj->getPrivate();
2855 JS_PUBLIC_API(JSObject *)
2856 JS_GetPrototype(JSContext *cx, JSObject *obj)
2858 JSObject *proto;
2860 CHECK_REQUEST(cx);
2861 assertSameCompartment(cx, obj);
2862 proto = obj->getProto();
2864 /* Beware ref to dead object (we may be called from obj's finalizer). */
2865 return proto && proto->map ? proto : NULL;
2868 JS_PUBLIC_API(JSBool)
2869 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
2871 CHECK_REQUEST(cx);
2872 assertSameCompartment(cx, obj, proto);
2873 return SetProto(cx, obj, proto, JS_FALSE);
2876 JS_PUBLIC_API(JSObject *)
2877 JS_GetParent(JSContext *cx, JSObject *obj)
2879 assertSameCompartment(cx, obj);
2880 JSObject *parent = obj->getParent();
2882 /* Beware ref to dead object (we may be called from obj's finalizer). */
2883 return parent && parent->map ? parent : NULL;
2886 JS_PUBLIC_API(JSBool)
2887 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
2889 CHECK_REQUEST(cx);
2890 JS_ASSERT(parent || !obj->getParent());
2891 assertSameCompartment(cx, obj, parent);
2892 obj->setParent(parent);
2893 return true;
2896 JS_PUBLIC_API(JSObject *)
2897 JS_GetConstructor(JSContext *cx, JSObject *proto)
2899 Value cval;
2901 CHECK_REQUEST(cx);
2902 assertSameCompartment(cx, proto);
2904 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
2906 if (!proto->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), &cval))
2907 return NULL;
2909 JSObject *funobj;
2910 if (!IsFunctionObject(cval, &funobj)) {
2911 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
2912 proto->getClass()->name);
2913 return NULL;
2915 return &cval.toObject();
2918 JS_PUBLIC_API(JSBool)
2919 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
2921 assertSameCompartment(cx, obj);
2922 *idp = OBJECT_TO_JSID(obj);
2923 return JS_TRUE;
2926 JS_PUBLIC_API(JSObject *)
2927 JS_NewGlobalObject(JSContext *cx, JSClass *clasp)
2929 CHECK_REQUEST(cx);
2930 JS_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
2931 JSObject *obj = NewNonFunction<WithProto::Given>(cx, Valueify(clasp), NULL, NULL);
2932 if (!obj ||
2933 !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_COMPARTMENT,
2934 PrivateValue(cx->compartment))) {
2935 return NULL;
2938 /* FIXME: comment. */
2939 JSObject *res = regexp_statics_construct(cx);
2940 if (!res ||
2941 !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_REGEXP_STATICS,
2942 ObjectValue(*res))) {
2943 return NULL;
2946 return obj;
2949 JS_PUBLIC_API(JSObject *)
2950 JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals)
2952 CHECK_REQUEST(cx);
2953 JSCompartment *compartment = NewCompartment(cx, principals);
2954 if (!compartment)
2955 return NULL;
2957 JSCompartment *saved = cx->compartment;
2958 cx->compartment = compartment;
2959 JSObject *obj = JS_NewGlobalObject(cx, clasp);
2960 cx->compartment = saved;
2962 return obj;
2965 JS_PUBLIC_API(JSObject *)
2966 JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
2968 CHECK_REQUEST(cx);
2969 assertSameCompartment(cx, proto, parent);
2971 Class *clasp = Valueify(jsclasp);
2972 if (!clasp)
2973 clasp = &js_ObjectClass; /* default class is Object */
2975 JS_ASSERT(clasp != &js_FunctionClass);
2976 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
2978 JSObject *obj = NewNonFunction<WithProto::Class>(cx, clasp, proto, parent);
2980 JS_ASSERT_IF(obj, obj->getParent());
2981 return obj;
2984 JS_PUBLIC_API(JSObject *)
2985 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
2987 CHECK_REQUEST(cx);
2988 assertSameCompartment(cx, proto, parent);
2990 Class *clasp = Valueify(jsclasp);
2991 if (!clasp)
2992 clasp = &js_ObjectClass; /* default class is Object */
2994 JS_ASSERT(clasp != &js_FunctionClass);
2995 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
2997 return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
3000 JS_PUBLIC_API(JSObject *)
3001 JS_NewObjectForConstructor(JSContext *cx, const jsval *vp)
3003 CHECK_REQUEST(cx);
3004 assertSameCompartment(cx, *vp);
3006 return js_NewInstance(cx, JSVAL_TO_OBJECT(*vp));
3009 JS_PUBLIC_API(JSBool)
3010 JS_IsExtensible(JSObject *obj)
3012 return obj->isExtensible();
3015 JS_PUBLIC_API(JSBool)
3016 JS_FreezeObject(JSContext *cx, JSObject *obj)
3018 CHECK_REQUEST(cx);
3019 assertSameCompartment(cx, obj);
3021 return obj->freeze(cx);
3024 JS_PUBLIC_API(JSBool)
3025 JS_DeepFreezeObject(JSContext *cx, JSObject *obj)
3027 CHECK_REQUEST(cx);
3028 assertSameCompartment(cx, obj);
3030 /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */
3031 if (obj->isExtensible())
3032 return true;
3034 if (!obj->freeze(cx))
3035 return false;
3037 /* Walk slots in obj and if any value is a non-null object, seal it. */
3038 for (uint32 i = 0, n = obj->slotSpan(); i < n; ++i) {
3039 const Value &v = obj->getSlot(i);
3040 if (i == JSSLOT_PRIVATE && (obj->getClass()->flags & JSCLASS_HAS_PRIVATE))
3041 continue;
3042 if (v.isPrimitive())
3043 continue;
3044 if (!JS_DeepFreezeObject(cx, &v.toObject()))
3045 return false;
3048 return true;
3051 JS_PUBLIC_API(JSObject *)
3052 JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
3054 CHECK_REQUEST(cx);
3055 assertSameCompartment(cx, proto, parent);
3056 Class *clasp = Valueify(jsclasp);
3057 if (!clasp)
3058 clasp = &js_ObjectClass; /* default class is Object */
3059 return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
3062 JS_PUBLIC_API(JSObject *)
3063 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *proto,
3064 JSObject *parent, uintN argc, jsval *argv)
3066 CHECK_REQUEST(cx);
3067 assertSameCompartment(cx, proto, parent, JSValueArray(argv, argc));
3068 Class *clasp = Valueify(jsclasp);
3069 if (!clasp)
3070 clasp = &js_ObjectClass; /* default class is Object */
3071 return js_ConstructObject(cx, clasp, proto, parent, argc, Valueify(argv));
3074 static JSBool
3075 LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3076 JSObject **objp, JSProperty **propp)
3078 CHECK_REQUEST(cx);
3079 assertSameCompartment(cx, obj, id);
3081 JSAutoResolveFlags rf(cx, flags);
3082 id = js_CheckForStringIndex(id);
3083 return obj->lookupProperty(cx, id, objp, propp);
3086 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
3088 static JSBool
3089 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, jsid id,
3090 JSProperty *prop, Value *vp)
3092 if (!prop) {
3093 /* XXX bad API: no way to tell "not defined" from "void value" */
3094 vp->setUndefined();
3095 return JS_TRUE;
3098 if (obj2->isNative()) {
3099 Shape *shape = (Shape *) prop;
3101 if (shape->isMethod()) {
3102 AutoShapeRooter root(cx, shape);
3103 JS_UNLOCK_OBJ(cx, obj2);
3104 vp->setObject(shape->methodObject());
3105 return obj2->methodReadBarrier(cx, *shape, vp);
3108 /* Peek at the native property's slot value, without doing a Get. */
3109 if (obj2->containsSlot(shape->slot))
3110 *vp = obj2->lockedGetSlot(shape->slot);
3111 else
3112 vp->setBoolean(true);
3113 JS_UNLOCK_OBJ(cx, obj2);
3114 } else if (obj2->isDenseArray()) {
3115 return js_GetDenseArrayElementValue(cx, obj2, id, vp);
3116 } else {
3117 /* XXX bad API: no way to return "defined but value unknown" */
3118 vp->setBoolean(true);
3120 return true;
3123 JS_PUBLIC_API(JSBool)
3124 JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3126 JSObject *obj2;
3127 JSProperty *prop;
3128 return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) &&
3129 LookupResult(cx, obj, obj2, id, prop, Valueify(vp));
3132 JS_PUBLIC_API(JSBool)
3133 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3135 return JS_LookupPropertyById(cx, obj, INT_TO_JSID(index), vp);
3138 JS_PUBLIC_API(JSBool)
3139 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3141 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3142 return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3145 JS_PUBLIC_API(JSBool)
3146 JS_LookupUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3148 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3149 return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3152 JS_PUBLIC_API(JSBool)
3153 JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3154 JSObject **objp, jsval *vp)
3156 JSBool ok;
3157 JSProperty *prop;
3159 CHECK_REQUEST(cx);
3160 assertSameCompartment(cx, obj, id);
3161 ok = obj->isNative()
3162 ? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0
3163 : obj->lookupProperty(cx, id, objp, &prop);
3164 return ok && LookupResult(cx, obj, *objp, id, prop, Valueify(vp));
3167 JS_PUBLIC_API(JSBool)
3168 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, uintN flags, jsval *vp)
3170 JSObject *obj2;
3171 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3172 return atom && JS_LookupPropertyWithFlagsById(cx, obj, ATOM_TO_JSID(atom), flags, &obj2, vp);
3175 static JSBool
3176 HasPropertyResult(JSContext *cx, JSObject *obj2, JSProperty *prop, JSBool *foundp)
3178 *foundp = (prop != NULL);
3179 if (prop)
3180 obj2->dropProperty(cx, prop);
3181 return true;
3184 JS_PUBLIC_API(JSBool)
3185 JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3187 JSObject *obj2;
3188 JSProperty *prop;
3189 return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3190 &obj2, &prop) &&
3191 HasPropertyResult(cx, obj2, prop, foundp);
3194 JS_PUBLIC_API(JSBool)
3195 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3197 return JS_HasPropertyById(cx, obj, INT_TO_JSID(index), foundp);
3200 JS_PUBLIC_API(JSBool)
3201 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3203 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3204 return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3207 JS_PUBLIC_API(JSBool)
3208 JS_HasUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, JSBool *foundp)
3210 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3211 return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3214 JS_PUBLIC_API(JSBool)
3215 JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3217 CHECK_REQUEST(cx);
3218 assertSameCompartment(cx, obj, id);
3220 if (!obj->isNative()) {
3221 JSObject *obj2;
3222 JSProperty *prop;
3224 if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3225 &obj2, &prop)) {
3226 return JS_FALSE;
3228 *foundp = (obj == obj2);
3229 if (prop)
3230 obj2->dropProperty(cx, prop);
3231 return JS_TRUE;
3234 JS_LOCK_OBJ(cx, obj);
3235 *foundp = obj->nativeContains(id);
3236 JS_UNLOCK_OBJ(cx, obj);
3237 return JS_TRUE;
3240 JS_PUBLIC_API(JSBool)
3241 JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3243 return JS_AlreadyHasOwnPropertyById(cx, obj, INT_TO_JSID(index), foundp);
3246 JS_PUBLIC_API(JSBool)
3247 JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3249 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3250 return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3253 JS_PUBLIC_API(JSBool)
3254 JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3255 JSBool *foundp)
3257 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3258 return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3261 static JSBool
3262 DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value,
3263 PropertyOp getter, PropertyOp setter, uintN attrs,
3264 uintN flags, intN tinyid)
3266 CHECK_REQUEST(cx);
3267 assertSameCompartment(cx, obj, id, value,
3268 (attrs & JSPROP_GETTER)
3269 ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
3270 : NULL,
3271 (attrs & JSPROP_SETTER)
3272 ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
3273 : NULL);
3275 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
3276 if (flags != 0 && obj->isNative()) {
3277 return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter,
3278 attrs, flags, tinyid, NULL);
3280 return obj->defineProperty(cx, id, value, getter, setter, attrs);
3283 JS_PUBLIC_API(JSBool)
3284 JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
3285 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3287 return DefinePropertyById(cx, obj, id, Valueify(value), Valueify(getter),
3288 Valueify(setter), attrs, 0, 0);
3291 JS_PUBLIC_API(JSBool)
3292 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
3293 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3295 return DefinePropertyById(cx, obj, INT_TO_JSID(index), Valueify(value),
3296 Valueify(getter), Valueify(setter), attrs, 0, 0);
3299 static JSBool
3300 DefineProperty(JSContext *cx, JSObject *obj, const char *name, const Value &value,
3301 PropertyOp getter, PropertyOp setter, uintN attrs,
3302 uintN flags, intN tinyid)
3304 jsid id;
3305 JSAtom *atom;
3307 if (attrs & JSPROP_INDEX) {
3308 id = INT_TO_JSID(intptr_t(name));
3309 atom = NULL;
3310 attrs &= ~JSPROP_INDEX;
3311 } else {
3312 atom = js_Atomize(cx, name, strlen(name), 0);
3313 if (!atom)
3314 return JS_FALSE;
3315 id = ATOM_TO_JSID(atom);
3317 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid);
3320 JS_PUBLIC_API(JSBool)
3321 JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
3322 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3324 return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter),
3325 Valueify(setter), attrs, 0, 0);
3328 JS_PUBLIC_API(JSBool)
3329 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, int8 tinyid,
3330 jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3332 return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter),
3333 Valueify(setter), attrs, Shape::HAS_SHORTID, tinyid);
3336 static JSBool
3337 DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3338 const Value &value, PropertyOp getter, PropertyOp setter, uintN attrs,
3339 uintN flags, intN tinyid)
3341 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3342 return atom && DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs,
3343 flags, tinyid);
3346 JS_PUBLIC_API(JSBool)
3347 JS_DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3348 jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3350 return DefineUCProperty(cx, obj, name, namelen, Valueify(value),
3351 Valueify(getter), Valueify(setter), attrs, 0, 0);
3354 JS_PUBLIC_API(JSBool)
3355 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3356 int8 tinyid, jsval value, JSPropertyOp getter, JSPropertyOp setter,
3357 uintN attrs)
3359 return DefineUCProperty(cx, obj, name, namelen, Valueify(value), Valueify(getter),
3360 Valueify(setter), attrs, Shape::HAS_SHORTID, tinyid);
3363 JS_PUBLIC_API(JSBool)
3364 JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp)
3366 CHECK_REQUEST(cx);
3367 assertSameCompartment(cx, obj, id, descriptor);
3368 return js_DefineOwnProperty(cx, obj, id, Valueify(descriptor), bp);
3371 JS_PUBLIC_API(JSObject *)
3372 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp,
3373 JSObject *proto, uintN attrs)
3375 CHECK_REQUEST(cx);
3376 assertSameCompartment(cx, obj, proto);
3378 Class *clasp = Valueify(jsclasp);
3379 if (!clasp)
3380 clasp = &js_ObjectClass; /* default class is Object */
3382 JSObject *nobj = NewObject<WithProto::Class>(cx, clasp, proto, obj);
3383 if (!nobj)
3384 return NULL;
3386 if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
3387 return NULL;
3389 return nobj;
3392 JS_PUBLIC_API(JSBool)
3393 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
3395 JSBool ok;
3396 uintN attrs;
3398 CHECK_REQUEST(cx);
3399 for (ok = JS_TRUE; cds->name; cds++) {
3400 Value value = DoubleValue(cds->dval);
3401 attrs = cds->flags;
3402 if (!attrs)
3403 attrs = JSPROP_READONLY | JSPROP_PERMANENT;
3404 ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
3405 if (!ok)
3406 break;
3408 return ok;
3411 JS_PUBLIC_API(JSBool)
3412 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
3414 JSBool ok;
3416 for (ok = true; ps->name; ps++) {
3417 ok = DefineProperty(cx, obj, ps->name, UndefinedValue(),
3418 Valueify(ps->getter), Valueify(ps->setter),
3419 ps->flags, Shape::HAS_SHORTID, ps->tinyid);
3420 if (!ok)
3421 break;
3423 return ok;
3426 JS_PUBLIC_API(JSBool)
3427 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *alias)
3429 JSObject *obj2;
3430 JSProperty *prop;
3431 JSBool ok;
3432 Shape *shape;
3434 CHECK_REQUEST(cx);
3435 assertSameCompartment(cx, obj);
3437 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3438 if (!atom)
3439 return JS_FALSE;
3440 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
3441 return JS_FALSE;
3442 if (!prop) {
3443 js_ReportIsNotDefined(cx, name);
3444 return JS_FALSE;
3446 if (obj2 != obj || !obj->isNative()) {
3447 obj2->dropProperty(cx, prop);
3448 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3449 alias, name, obj2->getClass()->name);
3450 return JS_FALSE;
3452 atom = js_Atomize(cx, alias, strlen(alias), 0);
3453 if (!atom) {
3454 ok = JS_FALSE;
3455 } else {
3456 shape = (Shape *)prop;
3457 ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
3458 shape->getter(), shape->setter(), shape->slot,
3459 shape->attributes(), shape->getFlags() | Shape::ALIAS,
3460 shape->shortid)
3461 != NULL);
3463 JS_UNLOCK_OBJ(cx, obj);
3464 return ok;
3467 JS_PUBLIC_API(JSBool)
3468 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
3470 JSObject *obj2;
3471 JSProperty *prop;
3472 Shape *shape;
3473 JSBool ok;
3475 CHECK_REQUEST(cx);
3476 assertSameCompartment(cx, obj);
3478 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3479 if (!atom)
3480 return JS_FALSE;
3481 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
3482 return JS_FALSE;
3483 if (!prop) {
3484 js_ReportIsNotDefined(cx, name);
3485 return JS_FALSE;
3487 if (obj2 != obj || !obj->isNative()) {
3488 char numBuf[12];
3489 obj2->dropProperty(cx, prop);
3490 JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
3491 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3492 numBuf, name, obj2->getClass()->name);
3493 return JS_FALSE;
3495 shape = (Shape *)prop;
3496 ok = (js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
3497 shape->getter(), shape->setter(), shape->slot,
3498 shape->attributes(), shape->getFlags() | Shape::ALIAS,
3499 shape->shortid)
3500 != NULL);
3501 JS_UNLOCK_OBJ(cx, obj);
3502 return ok;
3505 static JSBool
3506 GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3507 JSBool own, PropertyDescriptor *desc)
3509 JSObject *obj2;
3510 JSProperty *prop;
3512 if (!LookupPropertyById(cx, obj, id, flags, &obj2, &prop))
3513 return JS_FALSE;
3515 if (!prop || (own && obj != obj2)) {
3516 desc->obj = NULL;
3517 desc->attrs = 0;
3518 desc->getter = NULL;
3519 desc->setter = NULL;
3520 desc->value.setUndefined();
3521 if (prop)
3522 obj2->dropProperty(cx, prop);
3523 return JS_TRUE;
3526 desc->obj = obj2;
3527 if (obj2->isNative()) {
3528 Shape *shape = (Shape *) prop;
3529 desc->attrs = shape->attributes();
3531 if (shape->isMethod()) {
3532 desc->getter = desc->setter = PropertyStub;
3533 desc->value.setObject(shape->methodObject());
3534 } else {
3535 desc->getter = shape->getter();
3536 desc->setter = shape->setter();
3537 if (obj2->containsSlot(shape->slot))
3538 desc->value = obj2->lockedGetSlot(shape->slot);
3539 else
3540 desc->value.setUndefined();
3542 JS_UNLOCK_OBJ(cx, obj2);
3543 } else {
3544 if (obj2->isProxy()) {
3545 JSAutoResolveFlags rf(cx, flags);
3546 return own
3547 ? JSProxy::getOwnPropertyDescriptor(cx, obj2, id, desc)
3548 : JSProxy::getPropertyDescriptor(cx, obj2, id, desc);
3550 if (!obj2->getAttributes(cx, id, &desc->attrs))
3551 return false;
3552 desc->getter = NULL;
3553 desc->setter = NULL;
3554 desc->value.setUndefined();
3556 return true;
3559 JS_PUBLIC_API(JSBool)
3560 JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3561 JSPropertyDescriptor *desc)
3563 return GetPropertyDescriptorById(cx, obj, id, flags, JS_FALSE, Valueify(desc));
3566 JS_PUBLIC_API(JSBool)
3567 JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *obj, jsid id,
3568 uintN *attrsp, JSBool *foundp,
3569 JSPropertyOp *getterp, JSPropertyOp *setterp)
3571 PropertyDescriptor desc;
3572 if (!GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, JS_FALSE, &desc))
3573 return false;
3575 *attrsp = desc.attrs;
3576 *foundp = (desc.obj != NULL);
3577 if (getterp)
3578 *getterp = Jsvalify(desc.getter);
3579 if (setterp)
3580 *setterp = Jsvalify(desc.setter);
3581 return true;
3584 JS_PUBLIC_API(JSBool)
3585 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3586 uintN *attrsp, JSBool *foundp)
3588 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3589 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3590 attrsp, foundp, NULL, NULL);
3593 JS_PUBLIC_API(JSBool)
3594 JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3595 uintN *attrsp, JSBool *foundp)
3597 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3598 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3599 attrsp, foundp, NULL, NULL);
3602 JS_PUBLIC_API(JSBool)
3603 JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, const char *name,
3604 uintN *attrsp, JSBool *foundp,
3605 JSPropertyOp *getterp, JSPropertyOp *setterp)
3607 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3608 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3609 attrsp, foundp, getterp, setterp);
3612 JS_PUBLIC_API(JSBool)
3613 JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
3614 const jschar *name, size_t namelen,
3615 uintN *attrsp, JSBool *foundp,
3616 JSPropertyOp *getterp, JSPropertyOp *setterp)
3618 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3619 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3620 attrsp, foundp, getterp, setterp);
3623 JS_PUBLIC_API(JSBool)
3624 JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3626 CHECK_REQUEST(cx);
3627 return js_GetOwnPropertyDescriptor(cx, obj, id, Valueify(vp));
3630 static JSBool
3631 SetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, uintN attrs, JSBool *foundp)
3633 JSObject *obj2;
3634 JSProperty *prop;
3636 if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
3637 return false;
3638 if (!prop || obj != obj2) {
3639 *foundp = false;
3640 if (prop)
3641 obj2->dropProperty(cx, prop);
3642 return true;
3644 JSBool ok = obj->isNative()
3645 ? js_SetNativeAttributes(cx, obj, (Shape *) prop, attrs)
3646 : obj->setAttributes(cx, id, &attrs);
3647 if (ok)
3648 *foundp = true;
3649 return ok;
3652 JS_PUBLIC_API(JSBool)
3653 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3654 uintN attrs, JSBool *foundp)
3656 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3657 return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
3660 JS_PUBLIC_API(JSBool)
3661 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3662 uintN attrs, JSBool *foundp)
3664 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3665 return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
3668 JS_PUBLIC_API(JSBool)
3669 JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3671 CHECK_REQUEST(cx);
3672 assertSameCompartment(cx, obj, id);
3673 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3674 return obj->getProperty(cx, id, Valueify(vp));
3677 JS_PUBLIC_API(JSBool)
3678 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3680 return JS_GetPropertyById(cx, obj, INT_TO_JSID(index), vp);
3683 JS_PUBLIC_API(JSBool)
3684 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3686 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3687 return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3690 JS_PUBLIC_API(JSBool)
3691 JS_GetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3693 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3694 return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3697 JS_PUBLIC_API(JSBool)
3698 JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval *vp)
3700 CHECK_REQUEST(cx);
3701 assertSameCompartment(cx, obj, id);
3702 if (!js_GetMethod(cx, obj, id, JSGET_METHOD_BARRIER, Valueify(vp)))
3703 return JS_FALSE;
3704 if (objp)
3705 *objp = obj;
3706 return JS_TRUE;
3709 JS_PUBLIC_API(JSBool)
3710 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, jsval *vp)
3712 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3713 return atom && JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), objp, vp);
3716 JS_PUBLIC_API(JSBool)
3717 JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3719 CHECK_REQUEST(cx);
3720 assertSameCompartment(cx, obj, id);
3721 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
3722 return obj->setProperty(cx, id, Valueify(vp), false);
3725 JS_PUBLIC_API(JSBool)
3726 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3728 return JS_SetPropertyById(cx, obj, INT_TO_JSID(index), vp);
3731 JS_PUBLIC_API(JSBool)
3732 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3734 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3735 return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3738 JS_PUBLIC_API(JSBool)
3739 JS_SetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3741 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3742 return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3745 JS_PUBLIC_API(JSBool)
3746 JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
3748 CHECK_REQUEST(cx);
3749 assertSameCompartment(cx, obj, id);
3750 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3751 return obj->deleteProperty(cx, id, Valueify(rval), false);
3754 JS_PUBLIC_API(JSBool)
3755 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
3757 return JS_DeletePropertyById2(cx, obj, INT_TO_JSID(index), rval);
3760 JS_PUBLIC_API(JSBool)
3761 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name, jsval *rval)
3763 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3764 return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
3767 JS_PUBLIC_API(JSBool)
3768 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *rval)
3770 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3771 return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
3774 JS_PUBLIC_API(JSBool)
3775 JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id)
3777 jsval junk;
3778 return JS_DeletePropertyById2(cx, obj, id, &junk);
3781 JS_PUBLIC_API(JSBool)
3782 JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
3784 jsval junk;
3785 return JS_DeleteElement2(cx, obj, index, &junk);
3788 JS_PUBLIC_API(JSBool)
3789 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
3791 jsval junk;
3792 return JS_DeleteProperty2(cx, obj, name, &junk);
3795 JS_PUBLIC_API(void)
3796 JS_ClearScope(JSContext *cx, JSObject *obj)
3798 CHECK_REQUEST(cx);
3799 assertSameCompartment(cx, obj);
3801 JSFinalizeOp clearOp = obj->getOps()->clear;
3802 if (clearOp)
3803 clearOp(cx, obj);
3805 if (obj->isNative())
3806 js_ClearNative(cx, obj);
3808 /* Clear cached class objects on the global object. */
3809 if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) {
3810 int key;
3812 for (key = JSProto_Null; key < JSProto_LIMIT * 3; key++)
3813 JS_SetReservedSlot(cx, obj, key, JSVAL_VOID);
3816 js_InitRandom(cx);
3819 JS_PUBLIC_API(JSIdArray *)
3820 JS_Enumerate(JSContext *cx, JSObject *obj)
3822 CHECK_REQUEST(cx);
3823 assertSameCompartment(cx, obj);
3825 AutoIdVector props(cx);
3826 JSIdArray *ida;
3827 if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida))
3828 return false;
3829 for (size_t n = 0; n < size_t(ida->length); ++n)
3830 JS_ASSERT(js_CheckForStringIndex(ida->vector[n]) == ida->vector[n]);
3831 return ida;
3835 * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
3836 * prop_iterator_class somehow...
3837 * + preserve the obj->enumerate API while optimizing the native object case
3838 * + native case here uses a Shape *, but that iterates in reverse!
3839 * + so we make non-native match, by reverse-iterating after JS_Enumerating
3841 const uint32 JSSLOT_ITER_INDEX = JSSLOT_PRIVATE + 1;
3842 JS_STATIC_ASSERT(JSSLOT_ITER_INDEX < JS_INITIAL_NSLOTS);
3844 static void
3845 prop_iter_finalize(JSContext *cx, JSObject *obj)
3847 void *pdata = obj->getPrivate();
3848 if (!pdata)
3849 return;
3851 if (obj->fslots[JSSLOT_ITER_INDEX].toInt32() >= 0) {
3852 /* Non-native case: destroy the ida enumerated when obj was created. */
3853 JSIdArray *ida = (JSIdArray *) pdata;
3854 JS_DestroyIdArray(cx, ida);
3858 static void
3859 prop_iter_trace(JSTracer *trc, JSObject *obj)
3861 void *pdata = obj->getPrivate();
3862 if (!pdata)
3863 return;
3865 if (obj->fslots[JSSLOT_ITER_INDEX].toInt32() < 0) {
3866 /* Native case: just mark the next property to visit. */
3867 ((Shape *) pdata)->trace(trc);
3868 } else {
3869 /* Non-native case: mark each id in the JSIdArray private. */
3870 JSIdArray *ida = (JSIdArray *) pdata;
3871 MarkIdRange(trc, ida->length, ida->vector, "prop iter");
3875 static Class prop_iter_class = {
3876 "PropertyIterator",
3877 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
3878 JSCLASS_MARK_IS_TRACE,
3879 PropertyStub, /* addProperty */
3880 PropertyStub, /* delProperty */
3881 PropertyStub, /* getProperty */
3882 PropertyStub, /* setProperty */
3883 EnumerateStub,
3884 ResolveStub,
3885 ConvertStub,
3886 prop_iter_finalize,
3887 NULL, /* reserved0 */
3888 NULL, /* checkAccess */
3889 NULL, /* call */
3890 NULL, /* construct */
3891 NULL, /* xdrObject */
3892 NULL, /* hasInstance */
3893 JS_CLASS_TRACE(prop_iter_trace)
3896 JS_PUBLIC_API(JSObject *)
3897 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
3899 JSObject *iterobj;
3900 const void *pdata;
3901 jsint index;
3902 JSIdArray *ida;
3904 CHECK_REQUEST(cx);
3905 assertSameCompartment(cx, obj);
3906 iterobj = NewNonFunction<WithProto::Class>(cx, &prop_iter_class, NULL, obj);
3907 if (!iterobj)
3908 return NULL;
3910 if (obj->isNative()) {
3911 /* Native case: start with the last property in obj. */
3912 pdata = obj->lastProperty();
3913 index = -1;
3914 } else {
3916 * Non-native case: enumerate a JSIdArray and keep it via private.
3918 * Note: we have to make sure that we root obj around the call to
3919 * JS_Enumerate to protect against multiple allocations under it.
3921 AutoObjectRooter tvr(cx, iterobj);
3922 ida = JS_Enumerate(cx, obj);
3923 if (!ida)
3924 return NULL;
3925 pdata = ida;
3926 index = ida->length;
3929 /* iterobj cannot escape to other threads here. */
3930 iterobj->setPrivate(const_cast<void *>(pdata));
3931 iterobj->fslots[JSSLOT_ITER_INDEX].setInt32(index);
3932 return iterobj;
3935 JS_PUBLIC_API(JSBool)
3936 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
3938 jsint i;
3939 JSObject *obj;
3940 const Shape *shape;
3941 JSIdArray *ida;
3943 CHECK_REQUEST(cx);
3944 assertSameCompartment(cx, iterobj);
3945 i = iterobj->fslots[JSSLOT_ITER_INDEX].toInt32();
3946 if (i < 0) {
3947 /* Native case: private data is a property tree node pointer. */
3948 obj = iterobj->getParent();
3949 JS_ASSERT(obj->isNative());
3950 shape = (Shape *) iterobj->getPrivate();
3953 * If the next property mapped by obj in the property tree ancestor
3954 * line is not enumerable, or it's an alias, skip it and keep on trying
3955 * to find an enumerable property that is still in obj.
3957 while (shape->previous() && (!shape->enumerable() || shape->isAlias()))
3958 shape = shape->previous();
3960 if (!shape->previous()) {
3961 JS_ASSERT(JSID_IS_EMPTY(shape->id));
3962 *idp = JSID_VOID;
3963 } else {
3964 iterobj->setPrivate(const_cast<Shape *>(shape->previous()));
3965 *idp = shape->id;
3967 } else {
3968 /* Non-native case: use the ida enumerated when iterobj was created. */
3969 ida = (JSIdArray *) iterobj->getPrivate();
3970 JS_ASSERT(i <= ida->length);
3971 if (i == 0) {
3972 *idp = JSID_VOID;
3973 } else {
3974 *idp = ida->vector[--i];
3975 iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i));
3978 return JS_TRUE;
3981 JS_PUBLIC_API(JSBool)
3982 JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
3984 CHECK_REQUEST(cx);
3985 assertSameCompartment(cx, obj);
3986 return js_GetReservedSlot(cx, obj, index, Valueify(vp));
3989 JS_PUBLIC_API(JSBool)
3990 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
3992 CHECK_REQUEST(cx);
3993 assertSameCompartment(cx, obj, v);
3994 return js_SetReservedSlot(cx, obj, index, Valueify(v));
3997 JS_PUBLIC_API(JSObject *)
3998 JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
4000 CHECK_REQUEST(cx);
4001 /* NB: jsuint cast does ToUint32. */
4002 assertSameCompartment(cx, JSValueArray(vector, vector ? (jsuint)length : 0));
4003 return js_NewArrayObject(cx, (jsuint)length, Valueify(vector));
4006 JS_PUBLIC_API(JSBool)
4007 JS_IsArrayObject(JSContext *cx, JSObject *obj)
4009 assertSameCompartment(cx, obj);
4010 return obj->wrappedObject(cx)->isArray();
4013 JS_PUBLIC_API(JSBool)
4014 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
4016 CHECK_REQUEST(cx);
4017 assertSameCompartment(cx, obj);
4018 return js_GetLengthProperty(cx, obj, lengthp);
4021 JS_PUBLIC_API(JSBool)
4022 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
4024 CHECK_REQUEST(cx);
4025 assertSameCompartment(cx, obj);
4026 return js_SetLengthProperty(cx, obj, length);
4029 JS_PUBLIC_API(JSBool)
4030 JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
4032 CHECK_REQUEST(cx);
4033 assertSameCompartment(cx, obj);
4034 return js_HasLengthProperty(cx, obj, lengthp);
4037 JS_PUBLIC_API(JSBool)
4038 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
4039 jsval *vp, uintN *attrsp)
4041 CHECK_REQUEST(cx);
4042 assertSameCompartment(cx, obj, id);
4043 return CheckAccess(cx, obj, id, mode, Valueify(vp), attrsp);
4046 #ifdef JS_THREADSAFE
4047 JS_PUBLIC_API(jsrefcount)
4048 JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
4050 return JS_ATOMIC_INCREMENT(&principals->refcount);
4053 JS_PUBLIC_API(jsrefcount)
4054 JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
4056 jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
4057 if (rc == 0)
4058 principals->destroy(cx, principals);
4059 return rc;
4061 #endif
4063 JS_PUBLIC_API(JSSecurityCallbacks *)
4064 JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks)
4066 JSSecurityCallbacks *oldcallbacks;
4068 oldcallbacks = rt->securityCallbacks;
4069 rt->securityCallbacks = callbacks;
4070 return oldcallbacks;
4073 JS_PUBLIC_API(JSSecurityCallbacks *)
4074 JS_GetRuntimeSecurityCallbacks(JSRuntime *rt)
4076 return rt->securityCallbacks;
4079 JS_PUBLIC_API(JSSecurityCallbacks *)
4080 JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks)
4082 JSSecurityCallbacks *oldcallbacks;
4084 oldcallbacks = cx->securityCallbacks;
4085 cx->securityCallbacks = callbacks;
4086 return oldcallbacks;
4089 JS_PUBLIC_API(JSSecurityCallbacks *)
4090 JS_GetSecurityCallbacks(JSContext *cx)
4092 return cx->securityCallbacks
4093 ? cx->securityCallbacks
4094 : cx->runtime->securityCallbacks;
4097 JS_PUBLIC_API(JSFunction *)
4098 JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
4099 JSObject *parent, const char *name)
4101 JSAtom *atom;
4103 CHECK_REQUEST(cx);
4104 assertSameCompartment(cx, parent);
4106 if (!name) {
4107 atom = NULL;
4108 } else {
4109 atom = js_Atomize(cx, name, strlen(name), 0);
4110 if (!atom)
4111 return NULL;
4113 return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, atom);
4116 JS_PUBLIC_API(JSObject *)
4117 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
4119 CHECK_REQUEST(cx);
4120 assertSameCompartment(cx, parent); // XXX no funobj for now
4121 if (!parent) {
4122 if (cx->hasfp())
4123 parent = js_GetScopeChain(cx, cx->fp());
4124 if (!parent)
4125 parent = cx->globalObject;
4126 JS_ASSERT(parent);
4129 if (funobj->getClass() != &js_FunctionClass) {
4131 * We cannot clone this object, so fail (we used to return funobj, bad
4132 * idea, but we changed incompatibly to teach any abusers a lesson!).
4134 Value v = ObjectValue(*funobj);
4135 js_ReportIsNotFunction(cx, &v, 0);
4136 return NULL;
4139 JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
4140 if (!FUN_FLAT_CLOSURE(fun))
4141 return CloneFunctionObject(cx, fun, parent);
4144 * A flat closure carries its own environment, so why clone it? In case
4145 * someone wants to mutate its fixed slots or add ad-hoc properties. API
4146 * compatibility suggests we not return funobj and let callers mutate the
4147 * returned object at will.
4149 * But it's worse than that: API compatibility according to the test for
4150 * bug 300079 requires we get "upvars" from parent and its ancestors! So
4151 * we do that (grudgingly!). The scope chain ancestors are searched as if
4152 * they were activations, respecting the skip field in each upvar's cookie
4153 * but looking up the property by name instead of frame slot.
4155 JSObject *clone = js_AllocFlatClosure(cx, fun, parent);
4156 if (!clone)
4157 return NULL;
4159 JSUpvarArray *uva = fun->u.i.script->upvars();
4160 uint32 i = uva->length;
4161 JS_ASSERT(i != 0);
4163 for (Shape::Range r(fun->lastUpvar()); i-- != 0; r.popFront()) {
4164 JSObject *obj = parent;
4165 int skip = uva->vector[i].level();
4166 while (--skip > 0) {
4167 if (!obj) {
4168 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4169 JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
4170 return NULL;
4172 obj = obj->getParent();
4175 if (!obj->getProperty(cx, r.front().id, clone->getFlatClosureUpvars() + i))
4176 return NULL;
4179 return clone;
4182 JS_PUBLIC_API(JSObject *)
4183 JS_GetFunctionObject(JSFunction *fun)
4185 return FUN_OBJECT(fun);
4188 JS_PUBLIC_API(const char *)
4189 JS_GetFunctionName(JSFunction *fun)
4191 return fun->atom
4192 ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
4193 : js_anonymous_str;
4196 JS_PUBLIC_API(JSString *)
4197 JS_GetFunctionId(JSFunction *fun)
4199 return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
4202 JS_PUBLIC_API(uintN)
4203 JS_GetFunctionFlags(JSFunction *fun)
4205 return fun->flags;
4208 JS_PUBLIC_API(uint16)
4209 JS_GetFunctionArity(JSFunction *fun)
4211 return fun->nargs;
4214 JS_PUBLIC_API(JSBool)
4215 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
4217 return obj->getClass() == &js_FunctionClass;
4220 static JSBool
4221 js_generic_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp)
4223 JSFunctionSpec *fs;
4224 JSObject *tmp;
4225 Native native;
4227 fs = (JSFunctionSpec *) vp->toObject().getReservedSlot(0).toPrivate();
4228 JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
4230 if (argc < 1) {
4231 js_ReportMissingArg(cx, *vp, 0);
4232 return JS_FALSE;
4235 if (vp[2].isPrimitive()) {
4237 * Make sure that this is an object or null, as required by the generic
4238 * functions.
4240 if (!js_ValueToObjectOrNull(cx, vp[2], &tmp))
4241 return JS_FALSE;
4242 vp[2].setObjectOrNull(tmp);
4246 * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
4247 * which is almost always the class constructor object, e.g. Array. Then
4248 * call the corresponding prototype native method with our first argument
4249 * passed as |this|.
4251 memmove(vp + 1, vp + 2, argc * sizeof(jsval));
4254 * Follow Function.prototype.apply and .call by using the global object as
4255 * the 'this' param if no args.
4257 if (!ComputeThisFromArgv(cx, vp + 2))
4258 return JS_FALSE;
4260 /* Clear the last parameter in case too few arguments were passed. */
4261 vp[2 + --argc].setUndefined();
4263 native =
4264 #ifdef JS_TRACER
4265 (fs->flags & JSFUN_TRCINFO)
4266 ? JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native
4268 #endif
4269 Valueify(fs->call);
4270 return native(cx, argc, vp);
4273 JS_PUBLIC_API(JSBool)
4274 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
4276 uintN flags;
4277 JSObject *ctor;
4278 JSFunction *fun;
4280 CHECK_REQUEST(cx);
4281 assertSameCompartment(cx, obj);
4282 ctor = NULL;
4283 for (; fs->name; fs++) {
4284 flags = fs->flags;
4287 * Define a generic arity N+1 static method for the arity N prototype
4288 * method if flags contains JSFUN_GENERIC_NATIVE.
4290 if (flags & JSFUN_GENERIC_NATIVE) {
4291 if (!ctor) {
4292 ctor = JS_GetConstructor(cx, obj);
4293 if (!ctor)
4294 return JS_FALSE;
4297 flags &= ~JSFUN_GENERIC_NATIVE;
4298 fun = JS_DefineFunction(cx, ctor, fs->name,
4299 Jsvalify(js_generic_native_method_dispatcher),
4300 fs->nargs + 1,
4301 flags & ~JSFUN_TRCINFO);
4302 if (!fun)
4303 return JS_FALSE;
4306 * As jsapi.h notes, fs must point to storage that lives as long
4307 * as fun->object lives.
4309 Value priv = PrivateValue(fs);
4310 if (!js_SetReservedSlot(cx, FUN_OBJECT(fun), 0, priv))
4311 return JS_FALSE;
4314 fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
4315 if (!fun)
4316 return JS_FALSE;
4318 return JS_TRUE;
4321 JS_PUBLIC_API(JSFunction *)
4322 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
4323 uintN nargs, uintN attrs)
4325 CHECK_REQUEST(cx);
4326 assertSameCompartment(cx, obj);
4327 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
4328 return atom ? js_DefineFunction(cx, obj, atom, Valueify(call), nargs, attrs) : NULL;
4331 JS_PUBLIC_API(JSFunction *)
4332 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
4333 const jschar *name, size_t namelen, JSNative call,
4334 uintN nargs, uintN attrs)
4336 CHECK_REQUEST(cx);
4337 assertSameCompartment(cx, obj);
4338 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
4339 return atom ? js_DefineFunction(cx, obj, atom, Valueify(call), nargs, attrs) : NULL;
4342 inline static void
4343 LAST_FRAME_EXCEPTION_CHECK(JSContext *cx, bool result)
4345 if (!result && !(cx->options & JSOPTION_DONT_REPORT_UNCAUGHT))
4346 js_ReportUncaughtException(cx);
4349 inline static void
4350 LAST_FRAME_CHECKS(JSContext *cx, bool result)
4352 if (!JS_IsRunning(cx)) {
4353 LAST_FRAME_EXCEPTION_CHECK(cx, result);
4357 inline static uint32
4358 JS_OPTIONS_TO_TCFLAGS(JSContext *cx)
4360 return ((cx->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) |
4361 ((cx->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0);
4364 extern JS_PUBLIC_API(JSScript *)
4365 JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4366 JSPrincipals *principals,
4367 const jschar *chars, size_t length,
4368 const char *filename, uintN lineno,
4369 JSVersion version)
4371 AutoVersionAPI avi(cx, version);
4372 return JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno);
4375 JS_PUBLIC_API(JSScript *)
4376 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4377 const jschar *chars, size_t length,
4378 const char *filename, uintN lineno)
4380 CHECK_REQUEST(cx);
4381 assertSameCompartment(cx, obj, principals);
4383 uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4384 JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
4385 chars, length, NULL, filename, lineno);
4386 if (script && !js_NewScriptObject(cx, script)) {
4387 js_DestroyScript(cx, script);
4388 script = NULL;
4390 LAST_FRAME_CHECKS(cx, script);
4391 return script;
4394 JS_PUBLIC_API(JSScript *)
4395 JS_CompileUCScript(JSContext *cx, JSObject *obj, const jschar *chars, size_t length,
4396 const char *filename, uintN lineno)
4398 return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno);
4401 JS_PUBLIC_API(JSScript *)
4402 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
4403 JSPrincipals *principals,
4404 const char *bytes, size_t length,
4405 const char *filename, uintN lineno)
4407 CHECK_REQUEST(cx);
4409 jschar *chars = js_InflateString(cx, bytes, &length);
4410 if (!chars)
4411 return NULL;
4412 JSScript *script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno);
4413 cx->free(chars);
4414 return script;
4417 JS_PUBLIC_API(JSScript *)
4418 JS_CompileScript(JSContext *cx, JSObject *obj, const char *bytes, size_t length,
4419 const char *filename, uintN lineno)
4421 return JS_CompileScriptForPrincipals(cx, obj, NULL, bytes, length, filename, lineno);
4424 JS_PUBLIC_API(JSBool)
4425 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, const char *bytes, size_t length)
4427 jschar *chars;
4428 JSBool result;
4429 JSExceptionState *exnState;
4430 JSErrorReporter older;
4432 CHECK_REQUEST(cx);
4433 assertSameCompartment(cx, obj);
4434 chars = js_InflateString(cx, bytes, &length);
4435 if (!chars)
4436 return JS_TRUE;
4439 * Return true on any out-of-memory error, so our caller doesn't try to
4440 * collect more buffered source.
4442 result = JS_TRUE;
4443 exnState = JS_SaveExceptionState(cx);
4445 Parser parser(cx);
4446 if (parser.init(chars, length, NULL, NULL, 1)) {
4447 older = JS_SetErrorReporter(cx, NULL);
4448 if (!parser.parse(obj) &&
4449 parser.tokenStream.isUnexpectedEOF()) {
4451 * We ran into an error. If it was because we ran out of
4452 * source, we return false so our caller knows to try to
4453 * collect more buffered source.
4455 result = JS_FALSE;
4457 JS_SetErrorReporter(cx, older);
4460 cx->free(chars);
4461 JS_RestoreExceptionState(cx, exnState);
4462 return result;
4465 JS_PUBLIC_API(JSScript *)
4466 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
4468 FILE *fp;
4469 uint32 tcflags;
4470 JSScript *script;
4472 CHECK_REQUEST(cx);
4473 assertSameCompartment(cx, obj);
4474 if (!filename || strcmp(filename, "-") == 0) {
4475 fp = stdin;
4476 } else {
4477 fp = fopen(filename, "r");
4478 if (!fp) {
4479 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
4480 filename, "No such file or directory");
4481 return NULL;
4485 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4486 script = Compiler::compileScript(cx, obj, NULL, NULL, tcflags,
4487 NULL, 0, fp, filename, 1);
4488 if (fp != stdin)
4489 fclose(fp);
4490 if (script && !js_NewScriptObject(cx, script)) {
4491 js_DestroyScript(cx, script);
4492 script = NULL;
4494 LAST_FRAME_CHECKS(cx, script);
4495 return script;
4498 JS_PUBLIC_API(JSScript *)
4499 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *filename, FILE *file,
4500 JSPrincipals *principals)
4502 uint32 tcflags;
4503 JSScript *script;
4505 CHECK_REQUEST(cx);
4506 assertSameCompartment(cx, obj, principals);
4507 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4508 script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
4509 NULL, 0, file, filename, 1);
4510 if (script && !js_NewScriptObject(cx, script)) {
4511 js_DestroyScript(cx, script);
4512 script = NULL;
4514 LAST_FRAME_CHECKS(cx, script);
4515 return script;
4518 JS_PUBLIC_API(JSScript *)
4519 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *file)
4521 return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
4524 JS_PUBLIC_API(JSObject *)
4525 JS_NewScriptObject(JSContext *cx, JSScript *script)
4527 CHECK_REQUEST(cx);
4528 assertSameCompartment(cx, script);
4529 if (!script)
4530 return NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
4533 * This function should only ever be applied to JSScripts that had
4534 * script objects allocated for them when they were created, as
4535 * described in the comment for JSScript::u.object.
4537 JS_ASSERT(script->u.object);
4538 return script->u.object;
4541 JS_PUBLIC_API(JSObject *)
4542 JS_GetScriptObject(JSScript *script)
4545 * This function should only ever be applied to JSScripts that had
4546 * script objects allocated for them when they were created, as
4547 * described in the comment for JSScript::u.object.
4549 JS_ASSERT(script->u.object);
4550 return script->u.object;
4553 JS_PUBLIC_API(void)
4554 JS_DestroyScript(JSContext *cx, JSScript *script)
4556 CHECK_REQUEST(cx);
4559 * Originally, JSScript lifetimes were managed explicitly, and this function
4560 * was used to free a JSScript. Now, this function does nothing, and the
4561 * garbage collector manages JSScripts; you must root the JSScript's script
4562 * object (obtained via JS_GetScriptObject) to keep it alive.
4564 * However, since the script objects have taken over this responsibility, it
4565 * follows that every script passed here must have a script object.
4567 JS_ASSERT(script->u.object);
4570 JS_PUBLIC_API(JSFunction *)
4571 JS_CompileUCFunctionForPrincipalsVersion(JSContext *cx, JSObject *obj,
4572 JSPrincipals *principals, const char *name,
4573 uintN nargs, const char **argnames,
4574 const jschar *chars, size_t length,
4575 const char *filename, uintN lineno,
4576 JSVersion version)
4578 AutoVersionAPI avi(cx, version);
4579 return JS_CompileUCFunctionForPrincipals(cx, obj, principals, name, nargs, argnames, chars,
4580 length, filename, lineno);
4583 JS_PUBLIC_API(JSFunction *)
4584 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
4585 JSPrincipals *principals, const char *name,
4586 uintN nargs, const char **argnames,
4587 const jschar *chars, size_t length,
4588 const char *filename, uintN lineno)
4590 JSFunction *fun;
4591 JSAtom *funAtom, *argAtom;
4592 uintN i;
4594 CHECK_REQUEST(cx);
4595 assertSameCompartment(cx, obj, principals);
4596 if (!name) {
4597 funAtom = NULL;
4598 } else {
4599 funAtom = js_Atomize(cx, name, strlen(name), 0);
4600 if (!funAtom) {
4601 fun = NULL;
4602 goto out2;
4605 fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
4606 if (!fun)
4607 goto out2;
4610 AutoObjectRooter tvr(cx, FUN_OBJECT(fun));
4611 MUST_FLOW_THROUGH("out");
4613 for (i = 0; i < nargs; i++) {
4614 argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
4615 if (!argAtom) {
4616 fun = NULL;
4617 goto out2;
4619 if (!fun->addLocal(cx, argAtom, JSLOCAL_ARG)) {
4620 fun = NULL;
4621 goto out2;
4625 if (!Compiler::compileFunctionBody(cx, fun, principals,
4626 chars, length, filename, lineno)) {
4627 fun = NULL;
4628 goto out2;
4631 if (obj && funAtom &&
4632 !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), ObjectValue(*fun),
4633 NULL, NULL, JSPROP_ENUMERATE)) {
4634 fun = NULL;
4637 #ifdef JS_SCOPE_DEPTH_METER
4638 if (fun && obj) {
4639 JSObject *pobj = obj;
4640 uintN depth = 1;
4642 while ((pobj = pobj->getParent()) != NULL)
4643 ++depth;
4644 JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
4646 #endif
4649 out2:
4650 LAST_FRAME_CHECKS(cx, fun);
4651 return fun;
4654 JS_PUBLIC_API(JSFunction *)
4655 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
4656 uintN nargs, const char **argnames,
4657 const jschar *chars, size_t length,
4658 const char *filename, uintN lineno)
4660 return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames,
4661 chars, length, filename, lineno);
4664 JS_PUBLIC_API(JSFunction *)
4665 JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
4666 JSPrincipals *principals, const char *name,
4667 uintN nargs, const char **argnames,
4668 const char *bytes, size_t length,
4669 const char *filename, uintN lineno)
4671 jschar *chars = js_InflateString(cx, bytes, &length);
4672 if (!chars)
4673 return NULL;
4674 JSFunction *fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
4675 nargs, argnames, chars, length,
4676 filename, lineno);
4677 cx->free(chars);
4678 return fun;
4681 JS_PUBLIC_API(JSFunction *)
4682 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
4683 uintN nargs, const char **argnames,
4684 const char *bytes, size_t length,
4685 const char *filename, uintN lineno)
4687 return JS_CompileFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames, bytes, length,
4688 filename, lineno);
4691 JS_PUBLIC_API(JSString *)
4692 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, uintN indent)
4694 JSPrinter *jp;
4695 JSString *str;
4697 CHECK_REQUEST(cx);
4698 assertSameCompartment(cx, script);
4699 jp = js_NewPrinter(cx, name, NULL,
4700 indent & ~JS_DONT_PRETTY_PRINT,
4701 !(indent & JS_DONT_PRETTY_PRINT),
4702 false, false);
4703 if (!jp)
4704 return NULL;
4705 if (js_DecompileScript(jp, script))
4706 str = js_GetPrinterOutput(jp);
4707 else
4708 str = NULL;
4709 js_DestroyPrinter(jp);
4710 return str;
4713 JS_PUBLIC_API(JSString *)
4714 JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
4716 CHECK_REQUEST(cx);
4717 assertSameCompartment(cx, fun);
4718 return js_DecompileToString(cx, "JS_DecompileFunction", fun,
4719 indent & ~JS_DONT_PRETTY_PRINT,
4720 !(indent & JS_DONT_PRETTY_PRINT),
4721 false, false, js_DecompileFunction);
4724 JS_PUBLIC_API(JSString *)
4725 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
4727 CHECK_REQUEST(cx);
4728 assertSameCompartment(cx, fun);
4729 return js_DecompileToString(cx, "JS_DecompileFunctionBody", fun,
4730 indent & ~JS_DONT_PRETTY_PRINT,
4731 !(indent & JS_DONT_PRETTY_PRINT),
4732 false, false, js_DecompileFunctionBody);
4735 JS_PUBLIC_API(JSBool)
4736 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
4738 JSBool ok;
4740 CHECK_REQUEST(cx);
4741 assertSameCompartment(cx, obj, script);
4742 /* This should receive only scripts handed out via the JSAPI. */
4743 JS_ASSERT(script == JSScript::emptyScript() || script->u.object);
4744 ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
4745 LAST_FRAME_CHECKS(cx, ok);
4746 return ok;
4749 JS_PUBLIC_API(JSBool)
4750 JS_EvaluateUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4751 JSPrincipals *principals,
4752 const jschar *chars, uintN length,
4753 const char *filename, uintN lineno,
4754 jsval *rval, JSVersion version)
4756 AutoVersionAPI avi(cx, version);
4757 return JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno,
4758 rval);
4761 JS_PUBLIC_API(JSBool)
4762 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
4763 JSPrincipals *principals,
4764 const jschar *chars, uintN length,
4765 const char *filename, uintN lineno,
4766 jsval *rval)
4768 JSScript *script;
4769 JSBool ok;
4771 CHECK_REQUEST(cx);
4772 script = Compiler::compileScript(cx, obj, NULL, principals,
4773 !rval
4774 ? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
4775 : TCF_COMPILE_N_GO,
4776 chars, length, NULL, filename, lineno);
4777 if (!script) {
4778 LAST_FRAME_CHECKS(cx, script);
4779 return JS_FALSE;
4781 ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
4782 LAST_FRAME_CHECKS(cx, ok);
4783 js_DestroyScript(cx, script);
4784 return ok;
4787 JS_PUBLIC_API(JSBool)
4788 JS_EvaluateUCScript(JSContext *cx, JSObject *obj, const jschar *chars, uintN length,
4789 const char *filename, uintN lineno, jsval *rval)
4791 return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno, rval);
4794 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
4795 JS_PUBLIC_API(JSBool)
4796 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4797 const char *bytes, uintN nbytes,
4798 const char *filename, uintN lineno, jsval *rval)
4800 size_t length = nbytes;
4801 jschar *chars = js_InflateString(cx, bytes, &length);
4802 if (!chars)
4803 return JS_FALSE;
4804 JSBool ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
4805 filename, lineno, rval);
4806 cx->free(chars);
4807 return ok;
4810 JS_PUBLIC_API(JSBool)
4811 JS_EvaluateScript(JSContext *cx, JSObject *obj, const char *bytes, uintN nbytes,
4812 const char *filename, uintN lineno, jsval *rval)
4814 return JS_EvaluateScriptForPrincipals(cx, obj, NULL, bytes, nbytes, filename, lineno, rval);
4817 JS_PUBLIC_API(JSBool)
4818 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, jsval *argv,
4819 jsval *rval)
4821 JSBool ok;
4823 CHECK_REQUEST(cx);
4824 assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc));
4825 ok = ExternalInvoke(cx, obj, ObjectValue(*fun), argc, Valueify(argv), Valueify(rval));
4826 LAST_FRAME_CHECKS(cx, ok);
4827 return ok;
4830 JS_PUBLIC_API(JSBool)
4831 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, jsval *argv,
4832 jsval *rval)
4834 CHECK_REQUEST(cx);
4835 assertSameCompartment(cx, obj, JSValueArray(argv, argc));
4837 AutoValueRooter tvr(cx);
4838 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
4839 JSBool ok = atom &&
4840 js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, tvr.addr()) &&
4841 ExternalInvoke(cx, obj, tvr.value(), argc, Valueify(argv), Valueify(rval));
4842 LAST_FRAME_CHECKS(cx, ok);
4843 return ok;
4846 JS_PUBLIC_API(JSBool)
4847 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, jsval *argv,
4848 jsval *rval)
4850 JSBool ok;
4852 CHECK_REQUEST(cx);
4853 assertSameCompartment(cx, obj, fval, JSValueArray(argv, argc));
4854 ok = ExternalInvoke(cx, obj, Valueify(fval), argc, Valueify(argv), Valueify(rval));
4855 LAST_FRAME_CHECKS(cx, ok);
4856 return ok;
4859 JS_PUBLIC_API(JSObject *)
4860 JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv)
4862 CHECK_REQUEST(cx);
4863 assertSameCompartment(cx, ctor, JSValueArray(argv, argc));
4865 // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
4866 // is not a simple variation of JSOP_CALL. We have to determine what class
4867 // of object to create, create it, and clamp the return value to an object,
4868 // among other details. js_InvokeConstructor does the hard work.
4869 InvokeArgsGuard args;
4870 if (!cx->stack().pushInvokeArgs(cx, argc, &args))
4871 return NULL;
4873 args.callee().setObject(*ctor);
4874 args.thisv().setNull();
4875 memcpy(args.argv(), argv, argc * sizeof(jsval));
4877 bool ok = InvokeConstructor(cx, args);
4878 JSObject *obj = (ok && args.rval().isObject())
4879 ? &args.rval().toObject()
4880 : NULL;
4882 LAST_FRAME_CHECKS(cx, ok);
4883 return obj;
4886 JS_PUBLIC_API(JSOperationCallback)
4887 JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback)
4889 #ifdef JS_THREADSAFE
4890 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
4891 #endif
4892 JSOperationCallback old = cx->operationCallback;
4893 cx->operationCallback = callback;
4894 return old;
4897 JS_PUBLIC_API(JSOperationCallback)
4898 JS_GetOperationCallback(JSContext *cx)
4900 return cx->operationCallback;
4903 JS_PUBLIC_API(void)
4904 JS_TriggerOperationCallback(JSContext *cx)
4906 #ifdef JS_THREADSAFE
4907 AutoLockGC lock(cx->runtime);
4908 #endif
4909 TriggerOperationCallback(cx);
4912 JS_PUBLIC_API(void)
4913 JS_TriggerAllOperationCallbacks(JSRuntime *rt)
4915 #ifdef JS_THREADSAFE
4916 AutoLockGC lock(rt);
4917 #endif
4918 TriggerAllOperationCallbacks(rt);
4921 JS_PUBLIC_API(JSBool)
4922 JS_IsRunning(JSContext *cx)
4925 * The use of cx->fp below is safe. Rationale: Here we don't care if the
4926 * interpreter state is stale. We just want to know if there *is* any
4927 * interpreter state.
4929 VOUCH_DOES_NOT_REQUIRE_STACK();
4931 #ifdef JS_TRACER
4932 JS_ASSERT_IF(JS_TRACE_MONITOR(cx).tracecx == cx, cx->hasfp());
4933 #endif
4934 JSStackFrame *fp = cx->maybefp();
4935 while (fp && fp->isDummyFrame())
4936 fp = fp->prev();
4937 return fp != NULL;
4940 JS_PUBLIC_API(JSStackFrame *)
4941 JS_SaveFrameChain(JSContext *cx)
4943 CHECK_REQUEST(cx);
4944 JSStackFrame *fp = js_GetTopStackFrame(cx);
4945 if (!fp)
4946 return NULL;
4947 cx->saveActiveSegment();
4948 return fp;
4951 JS_PUBLIC_API(void)
4952 JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
4954 CHECK_REQUEST(cx);
4955 JS_ASSERT_NOT_ON_TRACE(cx);
4956 JS_ASSERT(!cx->hasfp());
4957 if (!fp)
4958 return;
4959 cx->restoreSegment();
4962 /************************************************************************/
4964 JS_PUBLIC_API(JSString *)
4965 JS_NewString(JSContext *cx, char *bytes, size_t nbytes)
4967 size_t length = nbytes;
4968 jschar *chars;
4969 JSString *str;
4971 CHECK_REQUEST(cx);
4973 /* Make a UTF-16 vector from the 8-bit char codes in bytes. */
4974 chars = js_InflateString(cx, bytes, &length);
4975 if (!chars)
4976 return NULL;
4978 /* Free chars (but not bytes, which caller frees on error) if we fail. */
4979 str = js_NewString(cx, chars, length);
4980 if (!str) {
4981 cx->free(chars);
4982 return NULL;
4985 /* Hand off bytes to the deflated string cache, if possible. */
4986 if (!cx->runtime->deflatedStringCache->setBytes(cx, str, bytes))
4987 cx->free(bytes);
4988 return str;
4991 JS_PUBLIC_API(JSString *)
4992 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
4994 jschar *js;
4995 JSString *str;
4997 CHECK_REQUEST(cx);
4998 js = js_InflateString(cx, s, &n);
4999 if (!js)
5000 return NULL;
5001 str = js_NewString(cx, js, n);
5002 if (!str)
5003 cx->free(js);
5004 return str;
5007 JS_PUBLIC_API(JSString *)
5008 JS_NewStringCopyZ(JSContext *cx, const char *s)
5010 size_t n;
5011 jschar *js;
5012 JSString *str;
5014 CHECK_REQUEST(cx);
5015 if (!s)
5016 return cx->runtime->emptyString;
5017 n = strlen(s);
5018 js = js_InflateString(cx, s, &n);
5019 if (!js)
5020 return NULL;
5021 str = js_NewString(cx, js, n);
5022 if (!str)
5023 cx->free(js);
5024 return str;
5027 JS_PUBLIC_API(JSBool)
5028 JS_StringHasBeenInterned(JSString *str)
5030 return str->isAtomized();
5033 JS_PUBLIC_API(JSString *)
5034 JS_InternString(JSContext *cx, const char *s)
5036 JSAtom *atom;
5038 CHECK_REQUEST(cx);
5039 atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
5040 if (!atom)
5041 return NULL;
5042 return ATOM_TO_STRING(atom);
5045 JS_PUBLIC_API(JSString *)
5046 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
5048 CHECK_REQUEST(cx);
5049 return js_NewString(cx, chars, length);
5052 JS_PUBLIC_API(JSString *)
5053 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
5055 CHECK_REQUEST(cx);
5056 return js_NewStringCopyN(cx, s, n);
5059 JS_PUBLIC_API(JSString *)
5060 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
5062 CHECK_REQUEST(cx);
5063 if (!s)
5064 return cx->runtime->emptyString;
5065 return js_NewStringCopyZ(cx, s);
5068 JS_PUBLIC_API(JSString *)
5069 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
5071 JSAtom *atom;
5073 CHECK_REQUEST(cx);
5074 atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
5075 if (!atom)
5076 return NULL;
5077 return ATOM_TO_STRING(atom);
5080 JS_PUBLIC_API(JSString *)
5081 JS_InternUCString(JSContext *cx, const jschar *s)
5083 return JS_InternUCStringN(cx, s, js_strlen(s));
5086 JS_PUBLIC_API(char *)
5087 JS_GetStringBytes(JSString *str)
5089 const char *bytes;
5091 bytes = js_GetStringBytes(NULL, str);
5092 return (char *)(bytes ? bytes : "");
5095 JS_PUBLIC_API(jschar *)
5096 JS_GetStringChars(JSString *str)
5098 size_t n, size;
5099 jschar *s;
5101 str->ensureNotRope();
5104 * API botch (again, shades of JS_GetStringBytes): we have no cx to report
5105 * out-of-memory when undepending strings, so we replace JSString::undepend
5106 * with explicit malloc call and ignore its errors.
5108 * If we fail to convert a dependent string into an independent one, our
5109 * caller will not be guaranteed a \u0000 terminator as a backstop. This
5110 * may break some clients who already misbehave on embedded NULs.
5112 * The gain of dependent strings, which cure quadratic and cubic growth
5113 * rate bugs in string concatenation, is worth this slight loss in API
5114 * compatibility.
5116 if (str->isDependent()) {
5117 n = str->dependentLength();
5118 size = (n + 1) * sizeof(jschar);
5119 s = (jschar *) js_malloc(size);
5120 if (s) {
5121 memcpy(s, str->dependentChars(), n * sizeof *s);
5122 s[n] = 0;
5123 str->initFlat(s, n);
5124 } else {
5125 s = str->dependentChars();
5127 } else {
5128 str->flatClearMutable();
5129 s = str->flatChars();
5131 return s;
5134 JS_PUBLIC_API(size_t)
5135 JS_GetStringLength(JSString *str)
5137 return str->length();
5140 JS_PUBLIC_API(const char *)
5141 JS_GetStringBytesZ(JSContext *cx, JSString *str)
5143 assertSameCompartment(cx, str);
5144 return js_GetStringBytes(cx, str);
5147 JS_PUBLIC_API(const jschar *)
5148 JS_GetStringCharsZ(JSContext *cx, JSString *str)
5150 assertSameCompartment(cx, str);
5151 return str->undepend(cx);
5154 JS_PUBLIC_API(intN)
5155 JS_CompareStrings(JSString *str1, JSString *str2)
5157 return js_CompareStrings(str1, str2);
5160 JS_PUBLIC_API(JSString *)
5161 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
5163 CHECK_REQUEST(cx);
5164 return js_NewString(cx, chars, length);
5167 JS_PUBLIC_API(JSString *)
5168 JS_NewDependentString(JSContext *cx, JSString *str, size_t start, size_t length)
5170 CHECK_REQUEST(cx);
5171 return js_NewDependentString(cx, str, start, length);
5174 JS_PUBLIC_API(JSString *)
5175 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
5177 CHECK_REQUEST(cx);
5178 return js_ConcatStrings(cx, left, right);
5181 JS_PUBLIC_API(const jschar *)
5182 JS_UndependString(JSContext *cx, JSString *str)
5184 CHECK_REQUEST(cx);
5185 return str->undepend(cx);
5188 JS_PUBLIC_API(JSBool)
5189 JS_MakeStringImmutable(JSContext *cx, JSString *str)
5191 CHECK_REQUEST(cx);
5192 return js_MakeStringImmutable(cx, str);
5195 JS_PUBLIC_API(JSBool)
5196 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, size_t *dstlenp)
5198 size_t n;
5200 if (!dst) {
5201 n = js_GetDeflatedStringLength(cx, src, srclen);
5202 if (n == (size_t)-1) {
5203 *dstlenp = 0;
5204 return JS_FALSE;
5206 *dstlenp = n;
5207 return JS_TRUE;
5210 return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5213 JS_PUBLIC_API(JSBool)
5214 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp)
5216 return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5219 JS_PUBLIC_API(char *)
5220 JS_EncodeString(JSContext *cx, JSString *str)
5222 return js_DeflateString(cx, str->chars(), str->length());
5225 JS_PUBLIC_API(JSBool)
5226 JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
5227 JSONWriteCallback callback, void *data)
5229 CHECK_REQUEST(cx);
5230 assertSameCompartment(cx, replacer, space);
5231 JSCharBuffer cb(cx);
5232 if (!js_Stringify(cx, Valueify(vp), replacer, Valueify(space), cb))
5233 return false;
5234 return callback(cb.begin(), cb.length(), data);
5237 JS_PUBLIC_API(JSBool)
5238 JS_TryJSON(JSContext *cx, jsval *vp)
5240 CHECK_REQUEST(cx);
5241 assertSameCompartment(cx, *vp);
5242 return js_TryJSON(cx, Valueify(vp));
5245 JS_PUBLIC_API(JSONParser *)
5246 JS_BeginJSONParse(JSContext *cx, jsval *vp)
5248 CHECK_REQUEST(cx);
5249 return js_BeginJSONParse(cx, Valueify(vp));
5252 JS_PUBLIC_API(JSBool)
5253 JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len)
5255 CHECK_REQUEST(cx);
5256 return js_ConsumeJSONText(cx, jp, data, len);
5259 JS_PUBLIC_API(JSBool)
5260 JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver)
5262 CHECK_REQUEST(cx);
5263 assertSameCompartment(cx, reviver);
5264 return js_FinishJSONParse(cx, jp, Valueify(reviver));
5268 * The following determines whether C Strings are to be treated as UTF-8
5269 * or ISO-8859-1. For correct operation, it must be set prior to the
5270 * first call to JS_NewRuntime.
5272 #ifndef JS_C_STRINGS_ARE_UTF8
5273 JSBool js_CStringsAreUTF8 = JS_FALSE;
5274 #endif
5276 JS_PUBLIC_API(JSBool)
5277 JS_CStringsAreUTF8()
5279 return js_CStringsAreUTF8;
5282 JS_PUBLIC_API(void)
5283 JS_SetCStringsAreUTF8()
5285 JS_ASSERT(!js_NewRuntimeWasCalled);
5287 #ifndef JS_C_STRINGS_ARE_UTF8
5288 js_CStringsAreUTF8 = JS_TRUE;
5289 #endif
5292 /************************************************************************/
5294 JS_PUBLIC_API(void)
5295 JS_ReportError(JSContext *cx, const char *format, ...)
5297 va_list ap;
5299 va_start(ap, format);
5300 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
5301 va_end(ap);
5304 JS_PUBLIC_API(void)
5305 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
5306 void *userRef, const uintN errorNumber, ...)
5308 va_list ap;
5310 va_start(ap, errorNumber);
5311 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5312 errorNumber, JS_TRUE, ap);
5313 va_end(ap);
5316 JS_PUBLIC_API(void)
5317 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
5318 void *userRef, const uintN errorNumber, ...)
5320 va_list ap;
5322 va_start(ap, errorNumber);
5323 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5324 errorNumber, JS_FALSE, ap);
5325 va_end(ap);
5328 JS_PUBLIC_API(JSBool)
5329 JS_ReportWarning(JSContext *cx, const char *format, ...)
5331 va_list ap;
5332 JSBool ok;
5334 va_start(ap, format);
5335 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
5336 va_end(ap);
5337 return ok;
5340 JS_PUBLIC_API(JSBool)
5341 JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
5342 JSErrorCallback errorCallback, void *userRef,
5343 const uintN errorNumber, ...)
5345 va_list ap;
5346 JSBool ok;
5348 va_start(ap, errorNumber);
5349 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5350 errorNumber, JS_TRUE, ap);
5351 va_end(ap);
5352 return ok;
5355 JS_PUBLIC_API(JSBool)
5356 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
5357 JSErrorCallback errorCallback, void *userRef,
5358 const uintN errorNumber, ...)
5360 va_list ap;
5361 JSBool ok;
5363 va_start(ap, errorNumber);
5364 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5365 errorNumber, JS_FALSE, ap);
5366 va_end(ap);
5367 return ok;
5370 JS_PUBLIC_API(void)
5371 JS_ReportOutOfMemory(JSContext *cx)
5373 js_ReportOutOfMemory(cx);
5376 JS_PUBLIC_API(void)
5377 JS_ReportAllocationOverflow(JSContext *cx)
5379 js_ReportAllocationOverflow(cx);
5382 JS_PUBLIC_API(JSErrorReporter)
5383 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
5385 JSErrorReporter older;
5387 older = cx->errorReporter;
5388 cx->errorReporter = er;
5389 return older;
5392 /************************************************************************/
5395 * Regular Expressions.
5397 JS_PUBLIC_API(JSObject *)
5398 JS_NewRegExpObject(JSContext *cx, JSObject *obj, char *bytes, size_t length, uintN flags)
5400 CHECK_REQUEST(cx);
5401 jschar *chars = js_InflateString(cx, bytes, &length);
5402 if (!chars)
5403 return NULL;
5404 RegExpStatics *res = RegExpStatics::extractFrom(obj);
5405 JSObject *reobj = RegExp::createObject(cx, res, chars, length, flags);
5406 cx->free(chars);
5407 return reobj;
5410 JS_PUBLIC_API(JSObject *)
5411 JS_NewUCRegExpObject(JSContext *cx, JSObject *obj, jschar *chars, size_t length, uintN flags)
5413 CHECK_REQUEST(cx);
5414 RegExpStatics *res = RegExpStatics::extractFrom(obj);
5415 return RegExp::createObject(cx, res, chars, length, flags);
5418 JS_PUBLIC_API(void)
5419 JS_SetRegExpInput(JSContext *cx, JSObject *obj, JSString *input, JSBool multiline)
5421 CHECK_REQUEST(cx);
5422 assertSameCompartment(cx, input);
5424 RegExpStatics::extractFrom(obj)->reset(input, !!multiline);
5427 JS_PUBLIC_API(void)
5428 JS_ClearRegExpStatics(JSContext *cx, JSObject *obj)
5430 CHECK_REQUEST(cx);
5431 JS_ASSERT(obj);
5433 RegExpStatics::extractFrom(obj)->clear();
5436 JS_PUBLIC_API(JSBool)
5437 JS_ExecuteRegExp(JSContext *cx, JSObject *obj, JSObject *reobj, jschar *chars, size_t length,
5438 size_t *indexp, JSBool test, jsval *rval)
5440 CHECK_REQUEST(cx);
5442 RegExp *re = RegExp::extractFrom(reobj);
5443 if (!re)
5444 return false;
5446 JSString *str = js_NewStringCopyN(cx, chars, length);
5447 if (!str)
5448 return false;
5450 return re->execute(cx, RegExpStatics::extractFrom(obj), str, indexp, test, Valueify(rval));
5453 JS_PUBLIC_API(JSObject *)
5454 JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, uintN flags)
5456 CHECK_REQUEST(cx);
5457 jschar *chars = js_InflateString(cx, bytes, &length);
5458 if (!chars)
5459 return NULL;
5460 JSObject *obj = RegExp::createObjectNoStatics(cx, chars, length, flags);
5461 cx->free(chars);
5462 return obj;
5465 JS_PUBLIC_API(JSObject *)
5466 JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, uintN flags)
5468 CHECK_REQUEST(cx);
5469 return RegExp::createObjectNoStatics(cx, chars, length, flags);
5472 JS_PUBLIC_API(JSBool)
5473 JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *obj, jschar *chars, size_t length,
5474 size_t *indexp, JSBool test, jsval *rval)
5476 CHECK_REQUEST(cx);
5478 RegExp *re = RegExp::extractFrom(obj);
5479 if (!re)
5480 return false;
5482 JSString *str = js_NewStringCopyN(cx, chars, length);
5483 if (!str)
5484 return false;
5486 return re->executeNoStatics(cx, str, indexp, test, Valueify(rval));
5489 /************************************************************************/
5491 JS_PUBLIC_API(void)
5492 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
5494 cx->localeCallbacks = callbacks;
5497 JS_PUBLIC_API(JSLocaleCallbacks *)
5498 JS_GetLocaleCallbacks(JSContext *cx)
5500 return cx->localeCallbacks;
5503 /************************************************************************/
5505 JS_PUBLIC_API(JSBool)
5506 JS_IsExceptionPending(JSContext *cx)
5508 return (JSBool) cx->throwing;
5511 JS_PUBLIC_API(JSBool)
5512 JS_GetPendingException(JSContext *cx, jsval *vp)
5514 CHECK_REQUEST(cx);
5515 if (!cx->throwing)
5516 return JS_FALSE;
5517 Valueify(*vp) = cx->exception;
5518 return JS_TRUE;
5521 JS_PUBLIC_API(void)
5522 JS_SetPendingException(JSContext *cx, jsval v)
5524 CHECK_REQUEST(cx);
5525 assertSameCompartment(cx, v);
5526 SetPendingException(cx, Valueify(v));
5529 JS_PUBLIC_API(void)
5530 JS_ClearPendingException(JSContext *cx)
5532 cx->throwing = JS_FALSE;
5533 cx->exception.setUndefined();
5536 JS_PUBLIC_API(JSBool)
5537 JS_ReportPendingException(JSContext *cx)
5539 JSBool ok;
5540 JSPackedBool save;
5542 CHECK_REQUEST(cx);
5545 * Set cx->generatingError to suppress the standard error-to-exception
5546 * conversion done by all {js,JS}_Report* functions except for OOM. The
5547 * cx->generatingError flag was added to suppress recursive divergence
5548 * under js_ErrorToException, but it serves for our purposes here too.
5550 save = cx->generatingError;
5551 cx->generatingError = JS_TRUE;
5552 ok = js_ReportUncaughtException(cx);
5553 cx->generatingError = save;
5554 return ok;
5557 struct JSExceptionState {
5558 JSBool throwing;
5559 jsval exception;
5562 JS_PUBLIC_API(JSExceptionState *)
5563 JS_SaveExceptionState(JSContext *cx)
5565 JSExceptionState *state;
5567 CHECK_REQUEST(cx);
5568 state = (JSExceptionState *) cx->malloc(sizeof(JSExceptionState));
5569 if (state) {
5570 state->throwing = JS_GetPendingException(cx, &state->exception);
5571 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
5572 js_AddRoot(cx, Valueify(&state->exception), "JSExceptionState.exception");
5574 return state;
5577 JS_PUBLIC_API(void)
5578 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
5580 CHECK_REQUEST(cx);
5581 if (state) {
5582 if (state->throwing)
5583 JS_SetPendingException(cx, state->exception);
5584 else
5585 JS_ClearPendingException(cx);
5586 JS_DropExceptionState(cx, state);
5590 JS_PUBLIC_API(void)
5591 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
5593 CHECK_REQUEST(cx);
5594 if (state) {
5595 if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
5596 assertSameCompartment(cx, state->exception);
5597 JS_RemoveValueRoot(cx, &state->exception);
5599 cx->free(state);
5603 JS_PUBLIC_API(JSErrorReport *)
5604 JS_ErrorFromException(JSContext *cx, jsval v)
5606 CHECK_REQUEST(cx);
5607 assertSameCompartment(cx, v);
5608 return js_ErrorFromException(cx, v);
5611 JS_PUBLIC_API(JSBool)
5612 JS_ThrowReportedError(JSContext *cx, const char *message,
5613 JSErrorReport *reportp)
5615 return JS_IsRunning(cx) &&
5616 js_ErrorToException(cx, message, reportp, NULL, NULL);
5619 JS_PUBLIC_API(JSBool)
5620 JS_ThrowStopIteration(JSContext *cx)
5622 return js_ThrowStopIteration(cx);
5626 * Get the owning thread id of a context. Returns 0 if the context is not
5627 * owned by any thread.
5629 JS_PUBLIC_API(jsword)
5630 JS_GetContextThread(JSContext *cx)
5632 #ifdef JS_THREADSAFE
5633 return reinterpret_cast<jsword>(JS_THREAD_ID(cx));
5634 #else
5635 return 0;
5636 #endif
5640 * Set the current thread as the owning thread of a context. Returns the
5641 * old owning thread id, or -1 if the operation failed.
5643 JS_PUBLIC_API(jsword)
5644 JS_SetContextThread(JSContext *cx)
5646 #ifdef JS_THREADSAFE
5647 JS_ASSERT(!cx->outstandingRequests);
5648 if (cx->thread) {
5649 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
5650 return reinterpret_cast<jsword>(cx->thread->id);
5653 if (!js_InitContextThread(cx)) {
5654 js_ReportOutOfMemory(cx);
5655 return -1;
5658 /* Here the GC lock is still held after js_InitContextThread took it. */
5659 JS_UNLOCK_GC(cx->runtime);
5660 #endif
5661 return 0;
5664 JS_PUBLIC_API(jsword)
5665 JS_ClearContextThread(JSContext *cx)
5667 #ifdef JS_THREADSAFE
5669 * cx must have exited all requests it entered and, if cx is associated
5670 * with a thread, this must be called only from that thread. If not, this
5671 * is a harmless no-op.
5673 JS_ASSERT(cx->outstandingRequests == 0);
5674 JSThread *t = cx->thread;
5675 if (!t)
5676 return 0;
5677 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
5680 * We must not race with a GC that accesses cx->thread for all threads,
5681 * see bug 476934.
5683 JSRuntime *rt = cx->runtime;
5684 AutoLockGC lock(rt);
5685 js_WaitForGC(rt);
5686 js_ClearContextThread(cx);
5687 JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth);
5690 * We can access t->id as long as the GC lock is held and we cannot race
5691 * with the GC that may delete t.
5693 return reinterpret_cast<jsword>(t->id);
5694 #else
5695 return 0;
5696 #endif
5699 #ifdef MOZ_TRACE_JSCALLS
5700 JS_PUBLIC_API(void)
5701 JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb)
5703 cx->functionCallback = fcb;
5706 JS_PUBLIC_API(JSFunctionCallback)
5707 JS_GetFunctionCallback(JSContext *cx)
5709 return cx->functionCallback;
5711 #endif
5713 #ifdef JS_GC_ZEAL
5714 JS_PUBLIC_API(void)
5715 JS_SetGCZeal(JSContext *cx, uint8 zeal)
5717 cx->runtime->gcZeal = zeal;
5719 #endif
5721 /************************************************************************/
5723 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN) && !defined (WINCE)
5725 #include "jswin.h"
5728 * Initialization routine for the JS DLL.
5730 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
5732 return TRUE;
5735 #endif