Bug 588735 - Mirror glass caption buttons for rtl windows. r=roc, a=blocking-betaN.
[mozilla-central.git] / js / src / jsapi.cpp
blobbbaa2e54fd148f0b88acdf051c14c39fa37c1522
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 "jsdtoa.h"
64 #include "jsemit.h"
65 #include "jsexn.h"
66 #include "jsfun.h"
67 #include "jsgc.h"
68 #include "jsinterp.h"
69 #include "jsiter.h"
70 #include "jslock.h"
71 #include "jsmath.h"
72 #include "jsnum.h"
73 #include "json.h"
74 #include "jsobj.h"
75 #include "jsopcode.h"
76 #include "jsparse.h"
77 #include "jsproxy.h"
78 #include "jsregexp.h"
79 #include "jsscan.h"
80 #include "jsscope.h"
81 #include "jsscript.h"
82 #include "jsstr.h"
83 #include "jstask.h"
84 #include "jstracer.h"
85 #include "jsdbgapi.h"
86 #include "prmjtime.h"
87 #include "jsstaticcheck.h"
88 #include "jsvector.h"
89 #include "jswrapper.h"
90 #include "jstypedarray.h"
92 #include "jsatominlines.h"
93 #include "jscntxtinlines.h"
94 #include "jsobjinlines.h"
95 #include "jsscopeinlines.h"
96 #include "jscntxtinlines.h"
97 #include "jsregexpinlines.h"
98 #include "assembler/wtf/Platform.h"
100 #if ENABLE_YARR_JIT
101 #include "assembler/jit/ExecutableAllocator.h"
102 #include "methodjit/Logging.h"
103 #endif
105 #if JS_HAS_XML_SUPPORT
106 #include "jsxml.h"
107 #endif
109 using namespace js;
111 #ifdef HAVE_VA_LIST_AS_ARRAY
112 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
113 #else
114 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
115 #endif
117 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
118 JS_PUBLIC_DATA(jsid) JS_DEFAULT_XML_NAMESPACE_ID = { (size_t)JSID_TYPE_DEFAULT_XML_NAMESPACE };
119 JS_PUBLIC_DATA(jsid) JSID_VOID = { (size_t)JSID_TYPE_VOID };
120 #endif
122 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
123 JS_PUBLIC_DATA(jsval) JSVAL_NULL = { BUILD_JSVAL(JSVAL_TAG_NULL, 0) };
124 JS_PUBLIC_DATA(jsval) JSVAL_ZERO = { BUILD_JSVAL(JSVAL_TAG_INT32, 0) };
125 JS_PUBLIC_DATA(jsval) JSVAL_ONE = { BUILD_JSVAL(JSVAL_TAG_INT32, 1) };
126 JS_PUBLIC_DATA(jsval) JSVAL_FALSE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_FALSE) };
127 JS_PUBLIC_DATA(jsval) JSVAL_TRUE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_TRUE) };
128 JS_PUBLIC_DATA(jsval) JSVAL_VOID = { BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0) };
129 #endif
131 /* Make sure that jschar is two bytes unsigned integer */
132 JS_STATIC_ASSERT((jschar)-1 > 0);
133 JS_STATIC_ASSERT(sizeof(jschar) == 2);
135 JS_PUBLIC_API(int64)
136 JS_Now()
138 return PRMJ_Now();
141 JS_PUBLIC_API(jsval)
142 JS_GetNaNValue(JSContext *cx)
144 return Jsvalify(cx->runtime->NaNValue);
147 JS_PUBLIC_API(jsval)
148 JS_GetNegativeInfinityValue(JSContext *cx)
150 return Jsvalify(cx->runtime->negativeInfinityValue);
153 JS_PUBLIC_API(jsval)
154 JS_GetPositiveInfinityValue(JSContext *cx)
156 return Jsvalify(cx->runtime->positiveInfinityValue);
159 JS_PUBLIC_API(jsval)
160 JS_GetEmptyStringValue(JSContext *cx)
162 return STRING_TO_JSVAL(cx->runtime->emptyString);
165 static JSBool
166 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, jsval **vpp, va_list *app)
168 const char *format;
169 JSArgumentFormatMap *map;
171 format = *formatp;
172 for (map = cx->argumentFormatMap; map; map = map->next) {
173 if (!strncmp(format, map->format, map->length)) {
174 *formatp = format + map->length;
175 return map->formatter(cx, format, fromJS, vpp, app);
178 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
179 return JS_FALSE;
182 JS_PUBLIC_API(JSBool)
183 JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format, ...)
185 va_list ap;
186 JSBool ok;
188 va_start(ap, format);
189 ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
190 va_end(ap);
191 return ok;
194 JS_PUBLIC_API(JSBool)
195 JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format, va_list ap)
197 jsval *sp;
198 JSBool required;
199 char c;
200 JSFunction *fun;
201 jsdouble d;
202 JSString *str;
203 JSObject *obj;
205 CHECK_REQUEST(cx);
206 assertSameCompartment(cx, JSValueArray(argv - 2, argc + 2));
207 sp = argv;
208 required = JS_TRUE;
209 while ((c = *format++) != '\0') {
210 if (isspace(c))
211 continue;
212 if (c == '/') {
213 required = JS_FALSE;
214 continue;
216 if (sp == argv + argc) {
217 if (required) {
218 fun = js_ValueToFunction(cx, Valueify(&argv[-2]), 0);
219 if (fun) {
220 char numBuf[12];
221 JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
222 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
223 JSMSG_MORE_ARGS_NEEDED,
224 JS_GetFunctionName(fun), numBuf,
225 (argc == 1) ? "" : "s");
227 return JS_FALSE;
229 break;
231 switch (c) {
232 case 'b':
233 *va_arg(ap, JSBool *) = js_ValueToBoolean(Valueify(*sp));
234 break;
235 case 'c':
236 if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
237 return JS_FALSE;
238 break;
239 case 'i':
240 if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
241 return JS_FALSE;
242 break;
243 case 'u':
244 if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
245 return JS_FALSE;
246 break;
247 case 'j':
248 if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
249 return JS_FALSE;
250 break;
251 case 'd':
252 if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
253 return JS_FALSE;
254 break;
255 case 'I':
256 if (!JS_ValueToNumber(cx, *sp, &d))
257 return JS_FALSE;
258 *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
259 break;
260 case 's':
261 case 'S':
262 case 'W':
263 str = js_ValueToString(cx, Valueify(*sp));
264 if (!str)
265 return JS_FALSE;
266 *sp = STRING_TO_JSVAL(str);
267 if (c == 's') {
268 const char *bytes = js_GetStringBytes(cx, str);
269 if (!bytes)
270 return JS_FALSE;
271 *va_arg(ap, const char **) = bytes;
272 } else if (c == 'W') {
273 const jschar *chars = js_GetStringChars(cx, str);
274 if (!chars)
275 return JS_FALSE;
276 *va_arg(ap, const jschar **) = chars;
277 } else {
278 *va_arg(ap, JSString **) = str;
280 break;
281 case 'o':
282 if (!js_ValueToObjectOrNull(cx, Valueify(*sp), &obj))
283 return JS_FALSE;
284 *sp = OBJECT_TO_JSVAL(obj);
285 *va_arg(ap, JSObject **) = obj;
286 break;
287 case 'f':
288 obj = js_ValueToFunctionObject(cx, Valueify(sp), 0);
289 if (!obj)
290 return JS_FALSE;
291 *sp = OBJECT_TO_JSVAL(obj);
292 *va_arg(ap, JSFunction **) = GET_FUNCTION_PRIVATE(cx, obj);
293 break;
294 case 'v':
295 *va_arg(ap, jsval *) = *sp;
296 break;
297 case '*':
298 break;
299 default:
300 format--;
301 if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
302 JS_ADDRESSOF_VA_LIST(ap))) {
303 return JS_FALSE;
305 /* NB: the formatter already updated sp, so we continue here. */
306 continue;
308 sp++;
310 return JS_TRUE;
313 JS_PUBLIC_API(JSBool)
314 JS_AddArgumentFormatter(JSContext *cx, const char *format, JSArgumentFormatter formatter)
316 size_t length;
317 JSArgumentFormatMap **mpp, *map;
319 length = strlen(format);
320 mpp = &cx->argumentFormatMap;
321 while ((map = *mpp) != NULL) {
322 /* Insert before any shorter string to match before prefixes. */
323 if (map->length < length)
324 break;
325 if (map->length == length && !strcmp(map->format, format))
326 goto out;
327 mpp = &map->next;
329 map = (JSArgumentFormatMap *) cx->malloc(sizeof *map);
330 if (!map)
331 return JS_FALSE;
332 map->format = format;
333 map->length = length;
334 map->next = *mpp;
335 *mpp = map;
336 out:
337 map->formatter = formatter;
338 return JS_TRUE;
341 JS_PUBLIC_API(void)
342 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
344 size_t length;
345 JSArgumentFormatMap **mpp, *map;
347 length = strlen(format);
348 mpp = &cx->argumentFormatMap;
349 while ((map = *mpp) != NULL) {
350 if (map->length == length && !strcmp(map->format, format)) {
351 *mpp = map->next;
352 cx->free(map);
353 return;
355 mpp = &map->next;
359 JS_PUBLIC_API(JSBool)
360 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
362 JSBool ok;
363 JSObject *obj;
364 JSString *str;
365 jsdouble d;
367 CHECK_REQUEST(cx);
368 assertSameCompartment(cx, v);
369 switch (type) {
370 case JSTYPE_VOID:
371 *vp = JSVAL_VOID;
372 ok = JS_TRUE;
373 break;
374 case JSTYPE_OBJECT:
375 ok = js_ValueToObjectOrNull(cx, Valueify(v), &obj);
376 if (ok)
377 *vp = OBJECT_TO_JSVAL(obj);
378 break;
379 case JSTYPE_FUNCTION:
380 *vp = v;
381 obj = js_ValueToFunctionObject(cx, Valueify(vp), JSV2F_SEARCH_STACK);
382 ok = (obj != NULL);
383 break;
384 case JSTYPE_STRING:
385 str = js_ValueToString(cx, Valueify(v));
386 ok = (str != NULL);
387 if (ok)
388 *vp = STRING_TO_JSVAL(str);
389 break;
390 case JSTYPE_NUMBER:
391 ok = JS_ValueToNumber(cx, v, &d);
392 if (ok)
393 *vp = DOUBLE_TO_JSVAL(d);
394 break;
395 case JSTYPE_BOOLEAN:
396 *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(Valueify(v)));
397 return JS_TRUE;
398 default: {
399 char numBuf[12];
400 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
401 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE, numBuf);
402 ok = JS_FALSE;
403 break;
406 return ok;
409 JS_PUBLIC_API(JSBool)
410 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
412 CHECK_REQUEST(cx);
413 assertSameCompartment(cx, v);
414 return js_ValueToObjectOrNull(cx, Valueify(v), objp);
417 JS_PUBLIC_API(JSFunction *)
418 JS_ValueToFunction(JSContext *cx, jsval v)
420 CHECK_REQUEST(cx);
421 assertSameCompartment(cx, v);
422 return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
425 JS_PUBLIC_API(JSFunction *)
426 JS_ValueToConstructor(JSContext *cx, jsval v)
428 CHECK_REQUEST(cx);
429 assertSameCompartment(cx, v);
430 return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
433 JS_PUBLIC_API(JSString *)
434 JS_ValueToString(JSContext *cx, jsval v)
436 CHECK_REQUEST(cx);
437 assertSameCompartment(cx, v);
438 return js_ValueToString(cx, Valueify(v));
441 JS_PUBLIC_API(JSString *)
442 JS_ValueToSource(JSContext *cx, jsval v)
444 CHECK_REQUEST(cx);
445 assertSameCompartment(cx, v);
446 return js_ValueToSource(cx, Valueify(v));
449 JS_PUBLIC_API(JSBool)
450 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
452 CHECK_REQUEST(cx);
453 assertSameCompartment(cx, v);
455 AutoValueRooter tvr(cx, Valueify(v));
456 return ValueToNumber(cx, tvr.value(), dp);
459 JS_PUBLIC_API(JSBool)
460 JS_DoubleIsInt32(jsdouble d, jsint *ip)
462 return JSDOUBLE_IS_INT32(d, (int32_t *)ip);
465 JS_PUBLIC_API(JSBool)
466 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
468 CHECK_REQUEST(cx);
469 assertSameCompartment(cx, v);
471 AutoValueRooter tvr(cx, Valueify(v));
472 return ValueToECMAInt32(cx, tvr.value(), (int32_t *)ip);
475 JS_PUBLIC_API(JSBool)
476 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
478 CHECK_REQUEST(cx);
479 assertSameCompartment(cx, v);
481 AutoValueRooter tvr(cx, Valueify(v));
482 return ValueToECMAUint32(cx, tvr.value(), (uint32_t *)ip);
485 JS_PUBLIC_API(JSBool)
486 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
488 CHECK_REQUEST(cx);
489 assertSameCompartment(cx, v);
491 AutoValueRooter tvr(cx, Valueify(v));
492 return ValueToInt32(cx, tvr.value(), (int32_t *)ip);
495 JS_PUBLIC_API(JSBool)
496 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
498 CHECK_REQUEST(cx);
499 assertSameCompartment(cx, v);
501 AutoValueRooter tvr(cx, Valueify(v));
502 return ValueToUint16(cx, tvr.value(), (uint16_t *)ip);
505 JS_PUBLIC_API(JSBool)
506 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
508 CHECK_REQUEST(cx);
509 assertSameCompartment(cx, v);
510 *bp = js_ValueToBoolean(Valueify(v));
511 return JS_TRUE;
514 JS_PUBLIC_API(JSType)
515 JS_TypeOfValue(JSContext *cx, jsval v)
517 CHECK_REQUEST(cx);
518 assertSameCompartment(cx, v);
519 return TypeOfValue(cx, Valueify(v));
522 JS_PUBLIC_API(const char *)
523 JS_GetTypeName(JSContext *cx, JSType type)
525 if ((uintN)type >= (uintN)JSTYPE_LIMIT)
526 return NULL;
527 return JS_TYPE_STR(type);
530 JS_PUBLIC_API(JSBool)
531 JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2)
533 assertSameCompartment(cx, v1, v2);
534 return StrictlyEqual(cx, Valueify(v1), Valueify(v2));
537 JS_PUBLIC_API(JSBool)
538 JS_SameValue(JSContext *cx, jsval v1, jsval v2)
540 assertSameCompartment(cx, v1, v2);
541 return SameValue(Valueify(v1), Valueify(v2), cx);
544 /************************************************************************/
547 * Has a new runtime ever been created? This flag is used to detect unsafe
548 * changes to js_CStringsAreUTF8 after a runtime has been created, and to
549 * ensure that "first checks" on runtime creation are run only once.
551 #ifdef DEBUG
552 static JSBool js_NewRuntimeWasCalled = JS_FALSE;
553 #endif
555 JSRuntime::JSRuntime()
556 : gcChunkAllocator(&defaultGCChunkAllocator)
558 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
559 JS_INIT_CLIST(&contextList);
560 JS_INIT_CLIST(&trapList);
561 JS_INIT_CLIST(&watchPointList);
564 bool
565 JSRuntime::init(uint32 maxbytes)
567 #ifdef JS_METHODJIT_SPEW
568 JMCheckLogging();
569 #endif
571 #ifdef DEBUG
572 functionMeterFilename = getenv("JS_FUNCTION_STATFILE");
573 if (functionMeterFilename) {
574 if (!methodReadBarrierCountMap.init())
575 return false;
576 if (!unjoinedFunctionCountMap.init())
577 return false;
579 #endif
581 if (!(defaultCompartment = new JSCompartment(this)) ||
582 !defaultCompartment->init() ||
583 !compartments.append(defaultCompartment)) {
584 return false;
587 if (!js_InitGC(this, maxbytes) || !js_InitAtomState(this))
588 return false;
590 #if ENABLE_YARR_JIT
591 regExpAllocator = new JSC::ExecutableAllocator();
592 if (!regExpAllocator)
593 return false;
594 #endif
596 deflatedStringCache = new js::DeflatedStringCache();
597 if (!deflatedStringCache || !deflatedStringCache->init())
598 return false;
600 wrapObjectCallback = js::TransparentObjectWrapper;
602 #ifdef JS_THREADSAFE
603 gcLock = JS_NEW_LOCK();
604 if (!gcLock)
605 return false;
606 gcDone = JS_NEW_CONDVAR(gcLock);
607 if (!gcDone)
608 return false;
609 requestDone = JS_NEW_CONDVAR(gcLock);
610 if (!requestDone)
611 return false;
612 /* this is asymmetric with JS_ShutDown: */
613 if (!js_SetupLocks(8, 16))
614 return false;
615 rtLock = JS_NEW_LOCK();
616 if (!rtLock)
617 return false;
618 stateChange = JS_NEW_CONDVAR(gcLock);
619 if (!stateChange)
620 return false;
621 titleSharingDone = JS_NEW_CONDVAR(gcLock);
622 if (!titleSharingDone)
623 return false;
624 titleSharingTodo = NO_TITLE_SHARING_TODO;
625 debuggerLock = JS_NEW_LOCK();
626 if (!debuggerLock)
627 return false;
628 #endif
629 return propertyTree.init() && js_InitThreads(this);
632 JSRuntime::~JSRuntime()
634 #ifdef DEBUG
635 /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
636 if (!JS_CLIST_IS_EMPTY(&contextList)) {
637 JSContext *cx, *iter = NULL;
638 uintN cxcount = 0;
639 while ((cx = js_ContextIterator(this, JS_TRUE, &iter)) != NULL) {
640 fprintf(stderr,
641 "JS API usage error: found live context at %p\n",
642 (void *) cx);
643 cxcount++;
645 fprintf(stderr,
646 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
647 cxcount, (cxcount == 1) ? "" : "s");
649 #endif
651 js_FinishThreads(this);
652 js_FreeRuntimeScriptState(this);
653 js_FinishAtomState(this);
656 * Finish the deflated string cache after the last GC and after
657 * calling js_FinishAtomState, which finalizes strings.
659 delete deflatedStringCache;
660 #if ENABLE_YARR_JIT
661 delete regExpAllocator;
662 #endif
663 js_FinishGC(this);
664 #ifdef JS_THREADSAFE
665 if (gcLock)
666 JS_DESTROY_LOCK(gcLock);
667 if (gcDone)
668 JS_DESTROY_CONDVAR(gcDone);
669 if (requestDone)
670 JS_DESTROY_CONDVAR(requestDone);
671 if (rtLock)
672 JS_DESTROY_LOCK(rtLock);
673 if (stateChange)
674 JS_DESTROY_CONDVAR(stateChange);
675 if (titleSharingDone)
676 JS_DESTROY_CONDVAR(titleSharingDone);
677 if (debuggerLock)
678 JS_DESTROY_LOCK(debuggerLock);
679 #endif
680 propertyTree.finish();
681 /* Delete all remaining Compartments. Ideally only the defaultCompartment should be left. */
682 for (JSCompartment **c = compartments.begin(); c != compartments.end(); ++c)
683 delete *c;
684 compartments.clear();
687 JS_PUBLIC_API(JSRuntime *)
688 JS_NewRuntime(uint32 maxbytes)
690 #ifdef DEBUG
691 if (!js_NewRuntimeWasCalled) {
693 * This code asserts that the numbers associated with the error names
694 * in jsmsg.def are monotonically increasing. It uses values for the
695 * error names enumerated in jscntxt.c. It's not a compile-time check
696 * but it's better than nothing.
698 int errorNumber = 0;
699 #define MSG_DEF(name, number, count, exception, format) \
700 JS_ASSERT(name == errorNumber++);
701 #include "js.msg"
702 #undef MSG_DEF
704 #define MSG_DEF(name, number, count, exception, format) \
705 JS_BEGIN_MACRO \
706 uintN numfmtspecs = 0; \
707 const char *fmt; \
708 for (fmt = format; *fmt != '\0'; fmt++) { \
709 if (*fmt == '{' && isdigit(fmt[1])) \
710 ++numfmtspecs; \
712 JS_ASSERT(count == numfmtspecs); \
713 JS_END_MACRO;
714 #include "js.msg"
715 #undef MSG_DEF
717 js_NewRuntimeWasCalled = JS_TRUE;
719 #endif /* DEBUG */
721 void *mem = js_calloc(sizeof(JSRuntime));
722 if (!mem)
723 return NULL;
725 JSRuntime *rt = new (mem) JSRuntime();
726 if (!rt->init(maxbytes)) {
727 JS_DestroyRuntime(rt);
728 return NULL;
731 return rt;
734 JS_PUBLIC_API(void)
735 JS_CommenceRuntimeShutDown(JSRuntime *rt)
737 rt->gcFlushCodeCaches = true;
740 JS_PUBLIC_API(void)
741 JS_DestroyRuntime(JSRuntime *rt)
743 rt->~JSRuntime();
745 js_free(rt);
748 #ifdef JS_REPRMETER
749 namespace reprmeter {
750 extern void js_DumpReprMeter();
752 #endif
754 JS_PUBLIC_API(void)
755 JS_ShutDown(void)
757 #ifdef MOZ_TRACEVIS
758 StopTraceVis();
759 #endif
761 #ifdef JS_OPMETER
762 extern void js_DumpOpMeters();
763 js_DumpOpMeters();
764 #endif
766 #ifdef JS_REPRMETER
767 reprmeter::js_DumpReprMeter();
768 #endif
770 #ifdef JS_THREADSAFE
771 js_CleanupLocks();
772 #endif
773 PRMJ_NowShutdown();
776 JS_PUBLIC_API(void *)
777 JS_GetRuntimePrivate(JSRuntime *rt)
779 return rt->data;
782 JS_PUBLIC_API(void)
783 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
785 rt->data = data;
788 JS_PUBLIC_API(void)
789 JS_BeginRequest(JSContext *cx)
791 #ifdef JS_THREADSAFE
792 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
793 JS_ASSERT(cx->requestDepth <= cx->outstandingRequests);
794 if (cx->requestDepth) {
795 JS_ASSERT(cx->thread->requestContext == cx);
796 cx->requestDepth++;
797 cx->outstandingRequests++;
798 } else if (JSContext *old = cx->thread->requestContext) {
799 JS_ASSERT(!cx->prevRequestContext);
800 JS_ASSERT(cx->prevRequestDepth == 0);
801 JS_ASSERT(old != cx);
802 JS_ASSERT(old->requestDepth != 0);
803 JS_ASSERT(old->requestDepth <= old->outstandingRequests);
805 /* Serialize access to JSContext::requestDepth from other threads. */
806 AutoLockGC lock(cx->runtime);
807 cx->prevRequestContext = old;
808 cx->prevRequestDepth = old->requestDepth;
809 cx->requestDepth = 1;
810 cx->outstandingRequests++;
811 old->requestDepth = 0;
812 cx->thread->requestContext = cx;
813 } else {
814 JSRuntime *rt = cx->runtime;
815 AutoLockGC lock(rt);
817 /* Wait until the GC is finished. */
818 if (rt->gcThread != cx->thread) {
819 while (rt->gcThread)
820 JS_AWAIT_GC_DONE(rt);
823 /* Indicate that a request is running. */
824 cx->requestDepth = 1;
825 cx->outstandingRequests++;
826 cx->thread->requestContext = cx;
827 rt->requestCount++;
829 if (rt->requestCount == 1 && rt->activityCallback)
830 rt->activityCallback(rt->activityCallbackArg, true);
832 #endif
835 #ifdef JS_THREADSAFE
836 static void
837 StopRequest(JSContext *cx)
839 JSRuntime *rt;
841 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
842 JS_ASSERT(cx->requestDepth > 0);
843 JS_ASSERT(cx->outstandingRequests >= cx->requestDepth);
844 JS_ASSERT(cx->thread->requestContext == cx);
845 if (cx->requestDepth >= 2) {
846 cx->requestDepth--;
847 cx->outstandingRequests--;
848 } else if (JSContext *old = cx->prevRequestContext) {
849 JS_ASSERT(cx != old);
850 JS_ASSERT(old->requestDepth == 0);
851 JS_ASSERT(old->outstandingRequests >= cx->prevRequestDepth);
853 /* Serialize access to JSContext::requestDepth from other threads. */
854 AutoLockGC lock(cx->runtime);
856 cx->outstandingRequests--;
857 cx->requestDepth = 0;
858 old->requestDepth = cx->prevRequestDepth;
859 cx->prevRequestContext = NULL;
860 cx->prevRequestDepth = 0;
861 cx->thread->requestContext = old;
862 } else {
863 JS_ASSERT(cx->prevRequestDepth == 0);
864 LeaveTrace(cx); /* for GC safety */
866 /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
867 rt = cx->runtime;
868 AutoLockGC lock(rt);
870 cx->requestDepth = 0;
871 cx->outstandingRequests--;
872 cx->thread->requestContext = NULL;
874 js_ShareWaitingTitles(cx);
876 /* Give the GC a chance to run if this was the last request running. */
877 JS_ASSERT(rt->requestCount > 0);
878 rt->requestCount--;
879 if (rt->requestCount == 0) {
880 JS_NOTIFY_REQUEST_DONE(rt);
881 if (rt->activityCallback)
882 rt->activityCallback(rt->activityCallbackArg, false);
886 #endif
888 JS_PUBLIC_API(void)
889 JS_EndRequest(JSContext *cx)
891 #ifdef JS_THREADSAFE
893 * We do not allow to use JS_EndRequest to exit the request when there are
894 * native frames on the stack that insist that the request must be on. But
895 * we do allow to call the API if the request was suspended.
897 JS_ASSERT_IF(cx->requestDepth == 1 && cx->outstandingRequests == 1,
898 cx->checkRequestDepth == 0);
899 StopRequest(cx);
900 #endif
903 /* Yield to pending GC operations, regardless of request depth */
904 JS_PUBLIC_API(void)
905 JS_YieldRequest(JSContext *cx)
907 #ifdef JS_THREADSAFE
908 JS_ASSERT(cx->thread);
909 CHECK_REQUEST(cx);
910 cx = cx->thread->requestContext;
911 if (!cx)
912 return;
913 JS_ResumeRequest(cx, JS_SuspendRequest(cx));
914 #endif
917 JS_PUBLIC_API(jsrefcount)
918 JS_SuspendRequest(JSContext *cx)
920 #ifdef JS_THREADSAFE
921 jsrefcount saveDepth = cx->requestDepth;
922 if (saveDepth == 0)
923 return 0;
925 JS_THREAD_DATA(cx)->conservativeGC.enable();
926 do {
927 cx->outstandingRequests++; /* compensate for StopRequest */
928 StopRequest(cx);
929 } while (cx->requestDepth);
931 return saveDepth;
932 #else
933 return 0;
934 #endif
937 JS_PUBLIC_API(void)
938 JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
940 #ifdef JS_THREADSAFE
941 if (saveDepth == 0)
942 return;
944 JS_ASSERT(cx->outstandingRequests != 0);
945 do {
946 JS_BeginRequest(cx);
947 cx->outstandingRequests--; /* compensate for JS_BeginRequest */
948 } while (--saveDepth != 0);
949 JS_THREAD_DATA(cx)->conservativeGC.disable();
950 #endif
953 JS_PUBLIC_API(void)
954 JS_Lock(JSRuntime *rt)
956 JS_LOCK_RUNTIME(rt);
959 JS_PUBLIC_API(void)
960 JS_Unlock(JSRuntime *rt)
962 JS_UNLOCK_RUNTIME(rt);
965 JS_PUBLIC_API(JSContextCallback)
966 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
968 JSContextCallback old;
970 old = rt->cxCallback;
971 rt->cxCallback = cxCallback;
972 return old;
975 JS_PUBLIC_API(JSContext *)
976 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
978 return js_NewContext(rt, stackChunkSize);
981 JS_PUBLIC_API(void)
982 JS_DestroyContext(JSContext *cx)
984 js_DestroyContext(cx, JSDCM_FORCE_GC);
987 JS_PUBLIC_API(void)
988 JS_DestroyContextNoGC(JSContext *cx)
990 js_DestroyContext(cx, JSDCM_NO_GC);
993 JS_PUBLIC_API(void)
994 JS_DestroyContextMaybeGC(JSContext *cx)
996 js_DestroyContext(cx, JSDCM_MAYBE_GC);
999 JS_PUBLIC_API(void *)
1000 JS_GetContextPrivate(JSContext *cx)
1002 return cx->data;
1005 JS_PUBLIC_API(void)
1006 JS_SetContextPrivate(JSContext *cx, void *data)
1008 cx->data = data;
1011 JS_PUBLIC_API(JSRuntime *)
1012 JS_GetRuntime(JSContext *cx)
1014 return cx->runtime;
1017 JS_PUBLIC_API(JSContext *)
1018 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
1020 return js_ContextIterator(rt, JS_TRUE, iterp);
1023 JS_PUBLIC_API(JSVersion)
1024 JS_GetVersion(JSContext *cx)
1026 return JSVERSION_NUMBER(cx);
1029 JS_PUBLIC_API(JSVersion)
1030 JS_SetVersion(JSContext *cx, JSVersion version)
1032 JSVersion oldVersion;
1034 JS_ASSERT(version != JSVERSION_UNKNOWN);
1035 JS_ASSERT((version & ~JSVERSION_MASK) == 0);
1037 oldVersion = JSVERSION_NUMBER(cx);
1038 if (version == oldVersion)
1039 return oldVersion;
1041 /* We no longer support 1.4 or below. */
1042 if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4)
1043 return oldVersion;
1045 cx->version = (cx->version & ~JSVERSION_MASK) | version;
1046 js_OnVersionChange(cx);
1047 return oldVersion;
1050 static struct v2smap {
1051 JSVersion version;
1052 const char *string;
1053 } v2smap[] = {
1054 {JSVERSION_1_0, "1.0"},
1055 {JSVERSION_1_1, "1.1"},
1056 {JSVERSION_1_2, "1.2"},
1057 {JSVERSION_1_3, "1.3"},
1058 {JSVERSION_1_4, "1.4"},
1059 {JSVERSION_ECMA_3, "ECMAv3"},
1060 {JSVERSION_1_5, "1.5"},
1061 {JSVERSION_1_6, "1.6"},
1062 {JSVERSION_1_7, "1.7"},
1063 {JSVERSION_1_8, "1.8"},
1064 {JSVERSION_ECMA_5, "ECMAv5"},
1065 {JSVERSION_DEFAULT, js_default_str},
1066 {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
1069 JS_PUBLIC_API(const char *)
1070 JS_VersionToString(JSVersion version)
1072 int i;
1074 for (i = 0; v2smap[i].string; i++)
1075 if (v2smap[i].version == version)
1076 return v2smap[i].string;
1077 return "unknown";
1080 JS_PUBLIC_API(JSVersion)
1081 JS_StringToVersion(const char *string)
1083 int i;
1085 for (i = 0; v2smap[i].string; i++)
1086 if (strcmp(v2smap[i].string, string) == 0)
1087 return v2smap[i].version;
1088 return JSVERSION_UNKNOWN;
1091 JS_PUBLIC_API(uint32)
1092 JS_GetOptions(JSContext *cx)
1094 return cx->options;
1097 JS_PUBLIC_API(uint32)
1098 JS_SetOptions(JSContext *cx, uint32 options)
1100 AutoLockGC lock(cx->runtime);
1101 uint32 oldopts = cx->options;
1102 cx->options = options;
1103 js_SyncOptionsToVersion(cx);
1104 cx->updateJITEnabled();
1105 return oldopts;
1108 JS_PUBLIC_API(uint32)
1109 JS_ToggleOptions(JSContext *cx, uint32 options)
1111 AutoLockGC lock(cx->runtime);
1112 uint32 oldopts = cx->options;
1113 cx->options ^= options;
1114 js_SyncOptionsToVersion(cx);
1115 cx->updateJITEnabled();
1116 return oldopts;
1119 JS_PUBLIC_API(const char *)
1120 JS_GetImplementationVersion(void)
1122 return "JavaScript-C 1.8.0 pre-release 1 2007-10-03";
1125 JS_PUBLIC_API(JSCompartmentCallback)
1126 JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback)
1128 JSCompartmentCallback old = rt->compartmentCallback;
1129 rt->compartmentCallback = callback;
1130 return old;
1133 JS_PUBLIC_API(JSWrapObjectCallback)
1134 JS_SetWrapObjectCallback(JSContext *cx, JSWrapObjectCallback callback)
1136 JSRuntime *rt = cx->runtime;
1137 JSWrapObjectCallback old = rt->wrapObjectCallback;
1138 rt->wrapObjectCallback = callback;
1139 return old;
1142 JS_PUBLIC_API(JSCrossCompartmentCall *)
1143 JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
1145 CHECK_REQUEST(cx);
1147 JS_ASSERT(target);
1148 AutoCompartment *call = new AutoCompartment(cx, target);
1149 if (!call)
1150 return NULL;
1151 if (!call->enter()) {
1152 delete call;
1153 return NULL;
1155 return reinterpret_cast<JSCrossCompartmentCall *>(call);
1158 JS_PUBLIC_API(void)
1159 JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
1161 AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
1162 CHECK_REQUEST(realcall->context);
1163 realcall->leave();
1164 delete realcall;
1167 bool
1168 JSAutoCrossCompartmentCall::enter(JSContext *cx, JSObject *target)
1170 JS_ASSERT(!call);
1171 if (cx->compartment == target->getCompartment(cx))
1172 return true;
1173 call = JS_EnterCrossCompartmentCall(cx, target);
1174 return call != NULL;
1177 JSAutoEnterCompartment::JSAutoEnterCompartment(JSContext *cx,
1178 JSCompartment *newCompartment)
1179 : cx(cx), compartment(cx->compartment)
1181 cx->compartment = newCompartment;
1184 JSAutoEnterCompartment::JSAutoEnterCompartment(JSContext *cx, JSObject *target)
1185 : cx(cx), compartment(cx->compartment)
1187 cx->compartment = target->getCompartment(cx);
1190 JSAutoEnterCompartment::~JSAutoEnterCompartment()
1192 cx->compartment = compartment;
1195 JS_PUBLIC_API(void *)
1196 JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data)
1198 CHECK_REQUEST(cx);
1199 void *old = compartment->data;
1200 compartment->data = data;
1201 return old;
1204 JS_PUBLIC_API(void *)
1205 JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment)
1207 CHECK_REQUEST(cx);
1208 return compartment->data;
1211 JS_PUBLIC_API(JSBool)
1212 JS_WrapObject(JSContext *cx, JSObject **objp)
1214 CHECK_REQUEST(cx);
1215 return cx->compartment->wrap(cx, objp);
1218 JS_PUBLIC_API(JSBool)
1219 JS_WrapValue(JSContext *cx, jsval *vp)
1221 CHECK_REQUEST(cx);
1222 return cx->compartment->wrap(cx, Valueify(vp));
1225 JS_PUBLIC_API(JSObject *)
1226 JS_GetGlobalObject(JSContext *cx)
1228 return cx->globalObject;
1231 JS_PUBLIC_API(void)
1232 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1234 CHECK_REQUEST(cx);
1236 cx->globalObject = obj;
1237 cx->compartment = obj ? obj->getCompartment(cx) : cx->runtime->defaultCompartment;
1240 class AutoResolvingEntry {
1241 public:
1242 AutoResolvingEntry() : entry(NULL) {}
1245 * Returns false on error. But N.B. if obj[id] was already being resolved,
1246 * this is a no-op, and we silently treat that as success.
1248 bool start(JSContext *cx, JSObject *obj, jsid id, uint32 flag) {
1249 JS_ASSERT(!entry);
1250 this->cx = cx;
1251 key.obj = obj;
1252 key.id = id;
1253 this->flag = flag;
1254 bool ok = !!js_StartResolving(cx, &key, flag, &entry);
1255 JS_ASSERT_IF(!ok, !entry);
1256 return ok;
1259 ~AutoResolvingEntry() {
1260 if (entry)
1261 js_StopResolving(cx, &key, flag, NULL, 0);
1264 private:
1265 JSContext *cx;
1266 JSResolvingKey key;
1267 uint32 flag;
1268 JSResolvingEntry *entry;
1271 JSObject *
1272 js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1274 JSObject *fun_proto, *obj_proto;
1276 /* If cx has no global object, use obj so prototypes can be found. */
1277 if (!cx->globalObject)
1278 JS_SetGlobalObject(cx, obj);
1280 /* Record Function and Object in cx->resolvingTable. */
1281 AutoResolvingEntry e1, e2;
1282 JSAtom **classAtoms = cx->runtime->atomState.classAtoms;
1283 if (!e1.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Function]), JSRESFLAG_LOOKUP) ||
1284 !e2.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Object]), JSRESFLAG_LOOKUP)) {
1285 return NULL;
1288 /* Initialize the function class first so constructors can be made. */
1289 if (!js_GetClassPrototype(cx, obj, JSProto_Function, &fun_proto))
1290 return NULL;
1291 if (!fun_proto) {
1292 fun_proto = js_InitFunctionClass(cx, obj);
1293 if (!fun_proto)
1294 return NULL;
1295 } else {
1296 JSObject *ctor;
1298 ctor = JS_GetConstructor(cx, fun_proto);
1299 if (!ctor)
1300 return NULL;
1301 obj->defineProperty(cx, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
1302 ObjectValue(*ctor), 0, 0, 0);
1305 /* Initialize the object class next so Object.prototype works. */
1306 if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto))
1307 return NULL;
1308 if (!obj_proto)
1309 obj_proto = js_InitObjectClass(cx, obj);
1310 if (!obj_proto)
1311 return NULL;
1313 /* Function.prototype and the global object delegate to Object.prototype. */
1314 fun_proto->setProto(obj_proto);
1315 if (!obj->getProto())
1316 obj->setProto(obj_proto);
1318 return fun_proto;
1321 JS_PUBLIC_API(JSBool)
1322 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1324 CHECK_REQUEST(cx);
1326 if (cx->globalObject)
1327 assertSameCompartment(cx, obj);
1328 else
1329 JS_SetGlobalObject(cx, obj);
1331 /* Define a top-level property 'undefined' with the undefined value. */
1332 JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1333 if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1334 PropertyStub, PropertyStub,
1335 JSPROP_PERMANENT | JSPROP_READONLY)) {
1336 return JS_FALSE;
1339 /* Function and Object require cooperative bootstrapping magic. */
1340 if (!js_InitFunctionAndObjectClasses(cx, obj))
1341 return JS_FALSE;
1343 /* Initialize the rest of the standard objects and functions. */
1344 return js_InitArrayClass(cx, obj) &&
1345 js_InitBooleanClass(cx, obj) &&
1346 js_InitExceptionClasses(cx, obj) &&
1347 js_InitMathClass(cx, obj) &&
1348 js_InitNumberClass(cx, obj) &&
1349 js_InitJSONClass(cx, obj) &&
1350 js_InitRegExpClass(cx, obj) &&
1351 js_InitStringClass(cx, obj) &&
1352 js_InitTypedArrayClasses(cx, obj) &&
1353 #if JS_HAS_XML_SUPPORT
1354 js_InitXMLClasses(cx, obj) &&
1355 #endif
1356 #if JS_HAS_GENERATORS
1357 js_InitIteratorClasses(cx, obj) &&
1358 #endif
1359 js_InitDateClass(cx, obj) &&
1360 js_InitProxyClass(cx, obj);
1363 #define CLASP(name) (&js_##name##Class)
1364 #define TYPED_ARRAY_CLASP(type) (&TypedArray::fastClasses[TypedArray::type])
1365 #define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
1366 #define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
1367 #define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
1368 #define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
1370 typedef struct JSStdName {
1371 JSObjectOp init;
1372 size_t atomOffset; /* offset of atom pointer in JSAtomState */
1373 const char *name; /* null if atom is pre-pinned, else name */
1374 Class *clasp;
1375 } JSStdName;
1377 static JSAtom *
1378 StdNameToAtom(JSContext *cx, JSStdName *stdn)
1380 size_t offset;
1381 JSAtom *atom;
1382 const char *name;
1384 offset = stdn->atomOffset;
1385 atom = OFFSET_TO_ATOM(cx->runtime, offset);
1386 if (!atom) {
1387 name = stdn->name;
1388 if (name) {
1389 atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1390 OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1393 return atom;
1397 * Table of class initializers and their atom offsets in rt->atomState.
1398 * If you add a "standard" class, remember to update this table.
1400 static JSStdName standard_class_atoms[] = {
1401 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Function)},
1402 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Object)},
1403 {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)},
1404 {js_InitBooleanClass, EAGER_ATOM_AND_CLASP(Boolean)},
1405 {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)},
1406 {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)},
1407 {js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)},
1408 {js_InitStringClass, EAGER_ATOM_AND_CLASP(String)},
1409 {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)},
1410 {js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)},
1411 #if JS_HAS_XML_SUPPORT
1412 {js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)},
1413 {js_InitNamespaceClass, EAGER_ATOM_AND_CLASP(Namespace)},
1414 {js_InitQNameClass, EAGER_ATOM_AND_CLASP(QName)},
1415 #endif
1416 #if JS_HAS_GENERATORS
1417 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
1418 #endif
1419 {js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
1420 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
1421 {NULL, 0, NULL, NULL}
1425 * Table of top-level function and constant names and their init functions.
1426 * If you add a "standard" global function or property, remember to update
1427 * this table.
1429 static JSStdName standard_class_names[] = {
1430 {js_InitObjectClass, EAGER_ATOM(eval), CLASP(Object)},
1432 /* Global properties and functions defined by the Number class. */
1433 {js_InitNumberClass, LAZY_ATOM(NaN), CLASP(Number)},
1434 {js_InitNumberClass, LAZY_ATOM(Infinity), CLASP(Number)},
1435 {js_InitNumberClass, LAZY_ATOM(isNaN), CLASP(Number)},
1436 {js_InitNumberClass, LAZY_ATOM(isFinite), CLASP(Number)},
1437 {js_InitNumberClass, LAZY_ATOM(parseFloat), CLASP(Number)},
1438 {js_InitNumberClass, LAZY_ATOM(parseInt), CLASP(Number)},
1440 /* String global functions. */
1441 {js_InitStringClass, LAZY_ATOM(escape), CLASP(String)},
1442 {js_InitStringClass, LAZY_ATOM(unescape), CLASP(String)},
1443 {js_InitStringClass, LAZY_ATOM(decodeURI), CLASP(String)},
1444 {js_InitStringClass, LAZY_ATOM(encodeURI), CLASP(String)},
1445 {js_InitStringClass, LAZY_ATOM(decodeURIComponent), CLASP(String)},
1446 {js_InitStringClass, LAZY_ATOM(encodeURIComponent), CLASP(String)},
1447 #if JS_HAS_UNEVAL
1448 {js_InitStringClass, LAZY_ATOM(uneval), CLASP(String)},
1449 #endif
1451 /* Exception constructors. */
1452 {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)},
1453 {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
1454 {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
1455 {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
1456 {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
1457 {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
1458 {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
1459 {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)},
1461 #if JS_HAS_XML_SUPPORT
1462 {js_InitAnyNameClass, EAGER_ATOM_AND_CLASP(AnyName)},
1463 {js_InitAttributeNameClass, EAGER_ATOM_AND_CLASP(AttributeName)},
1464 {js_InitXMLClass, LAZY_ATOM(XMLList), CLASP(XML)},
1465 {js_InitXMLClass, LAZY_ATOM(isXMLName), CLASP(XML)},
1466 #endif
1468 #if JS_HAS_GENERATORS
1469 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)},
1470 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Generator)},
1471 #endif
1473 /* Typed Arrays */
1474 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
1475 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int8Array), TYPED_ARRAY_CLASP(TYPE_INT8)},
1476 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8Array), TYPED_ARRAY_CLASP(TYPE_UINT8)},
1477 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int16Array), TYPED_ARRAY_CLASP(TYPE_INT16)},
1478 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint16Array), TYPED_ARRAY_CLASP(TYPE_UINT16)},
1479 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int32Array), TYPED_ARRAY_CLASP(TYPE_INT32)},
1480 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint32Array), TYPED_ARRAY_CLASP(TYPE_UINT32)},
1481 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float32Array), TYPED_ARRAY_CLASP(TYPE_FLOAT32)},
1482 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
1483 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8ClampedArray),
1484 TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
1486 {js_InitProxyClass, EAGER_ATOM_AND_CLASP(Proxy)},
1488 {NULL, 0, NULL, NULL}
1491 static JSStdName object_prototype_names[] = {
1492 /* Object.prototype properties (global delegates to Object.prototype). */
1493 {js_InitObjectClass, EAGER_ATOM(proto), CLASP(Object)},
1494 #if JS_HAS_TOSOURCE
1495 {js_InitObjectClass, EAGER_ATOM(toSource), CLASP(Object)},
1496 #endif
1497 {js_InitObjectClass, EAGER_ATOM(toString), CLASP(Object)},
1498 {js_InitObjectClass, EAGER_ATOM(toLocaleString), CLASP(Object)},
1499 {js_InitObjectClass, EAGER_ATOM(valueOf), CLASP(Object)},
1500 #if JS_HAS_OBJ_WATCHPOINT
1501 {js_InitObjectClass, LAZY_ATOM(watch), CLASP(Object)},
1502 {js_InitObjectClass, LAZY_ATOM(unwatch), CLASP(Object)},
1503 #endif
1504 {js_InitObjectClass, LAZY_ATOM(hasOwnProperty), CLASP(Object)},
1505 {js_InitObjectClass, LAZY_ATOM(isPrototypeOf), CLASP(Object)},
1506 {js_InitObjectClass, LAZY_ATOM(propertyIsEnumerable), CLASP(Object)},
1507 #if OLD_GETTER_SETTER_METHODS
1508 {js_InitObjectClass, LAZY_ATOM(defineGetter), CLASP(Object)},
1509 {js_InitObjectClass, LAZY_ATOM(defineSetter), CLASP(Object)},
1510 {js_InitObjectClass, LAZY_ATOM(lookupGetter), CLASP(Object)},
1511 {js_InitObjectClass, LAZY_ATOM(lookupSetter), CLASP(Object)},
1512 #endif
1514 {NULL, 0, NULL, NULL}
1517 JS_PUBLIC_API(JSBool)
1518 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
1520 JSString *idstr;
1521 JSRuntime *rt;
1522 JSAtom *atom;
1523 JSStdName *stdnm;
1524 uintN i;
1526 CHECK_REQUEST(cx);
1527 assertSameCompartment(cx, obj, id);
1528 *resolved = JS_FALSE;
1530 rt = cx->runtime;
1531 JS_ASSERT(rt->state != JSRTS_DOWN);
1532 if (rt->state == JSRTS_LANDING || !JSID_IS_ATOM(id))
1533 return JS_TRUE;
1535 idstr = JSID_TO_STRING(id);
1537 /* Check whether we're resolving 'undefined', and define it if so. */
1538 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1539 if (idstr == ATOM_TO_STRING(atom)) {
1540 *resolved = JS_TRUE;
1541 return obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1542 PropertyStub, PropertyStub,
1543 JSPROP_PERMANENT | JSPROP_READONLY);
1546 /* Try for class constructors/prototypes named by well-known atoms. */
1547 stdnm = NULL;
1548 for (i = 0; standard_class_atoms[i].init; i++) {
1549 JS_ASSERT(standard_class_atoms[i].clasp);
1550 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1551 if (idstr == ATOM_TO_STRING(atom)) {
1552 stdnm = &standard_class_atoms[i];
1553 break;
1557 if (!stdnm) {
1558 /* Try less frequently used top-level functions and constants. */
1559 for (i = 0; standard_class_names[i].init; i++) {
1560 JS_ASSERT(standard_class_names[i].clasp);
1561 atom = StdNameToAtom(cx, &standard_class_names[i]);
1562 if (!atom)
1563 return JS_FALSE;
1564 if (idstr == ATOM_TO_STRING(atom)) {
1565 stdnm = &standard_class_names[i];
1566 break;
1570 if (!stdnm && !obj->getProto()) {
1572 * Try even less frequently used names delegated from the global
1573 * object to Object.prototype, but only if the Object class hasn't
1574 * yet been initialized.
1576 for (i = 0; object_prototype_names[i].init; i++) {
1577 JS_ASSERT(object_prototype_names[i].clasp);
1578 atom = StdNameToAtom(cx, &object_prototype_names[i]);
1579 if (!atom)
1580 return JS_FALSE;
1581 if (idstr == ATOM_TO_STRING(atom)) {
1582 stdnm = &object_prototype_names[i];
1583 break;
1589 if (stdnm) {
1591 * If this standard class is anonymous, then we don't want to resolve
1592 * by name.
1594 JS_ASSERT(obj->getClass()->flags & JSCLASS_IS_GLOBAL);
1595 if (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)
1596 return JS_TRUE;
1598 JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(stdnm->clasp);
1599 if (obj->getReservedSlot(key).isObject())
1600 return JS_TRUE;
1602 if (!stdnm->init(cx, obj))
1603 return JS_FALSE;
1604 *resolved = JS_TRUE;
1606 return JS_TRUE;
1609 static JSBool
1610 AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom)
1612 JS_LOCK_OBJ(cx, obj);
1613 JSScope *scope = obj->scope();
1614 bool found = scope->hasProperty(ATOM_TO_JSID(atom));
1615 JS_UNLOCK_SCOPE(cx, scope);
1616 return found;
1619 JS_PUBLIC_API(JSBool)
1620 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1622 JSRuntime *rt;
1623 JSAtom *atom;
1624 uintN i;
1626 CHECK_REQUEST(cx);
1627 assertSameCompartment(cx, obj);
1628 rt = cx->runtime;
1630 /* Check whether we need to bind 'undefined' and define it if so. */
1631 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1632 if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1633 !obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1634 PropertyStub, PropertyStub,
1635 JSPROP_PERMANENT | JSPROP_READONLY)) {
1636 return JS_FALSE;
1639 /* Initialize any classes that have not been resolved yet. */
1640 for (i = 0; standard_class_atoms[i].init; i++) {
1641 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1642 if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1643 !standard_class_atoms[i].init(cx, obj)) {
1644 return JS_FALSE;
1648 return JS_TRUE;
1651 namespace js {
1653 JSIdArray *
1654 NewIdArray(JSContext *cx, jsint length)
1656 JSIdArray *ida;
1658 ida = (JSIdArray *)
1659 cx->calloc(offsetof(JSIdArray, vector) + length * sizeof(jsval));
1660 if (ida)
1661 ida->length = length;
1662 return ida;
1668 * Unlike realloc(3), this function frees ida on failure.
1670 static JSIdArray *
1671 SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
1673 JSIdArray *rida;
1675 rida = (JSIdArray *)
1676 JS_realloc(cx, ida,
1677 offsetof(JSIdArray, vector) + length * sizeof(jsval));
1678 if (!rida) {
1679 JS_DestroyIdArray(cx, ida);
1680 } else {
1681 rida->length = length;
1683 return rida;
1686 static JSIdArray *
1687 AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1689 jsint i, length;
1691 i = *ip;
1692 length = ida->length;
1693 if (i >= length) {
1694 ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
1695 if (!ida)
1696 return NULL;
1697 JS_ASSERT(i < ida->length);
1699 ida->vector[i] = ATOM_TO_JSID(atom);
1700 *ip = i + 1;
1701 return ida;
1704 static JSIdArray *
1705 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
1706 jsint *ip, JSBool *foundp)
1708 *foundp = AlreadyHasOwnProperty(cx, obj, atom);
1709 if (*foundp)
1710 ida = AddAtomToArray(cx, atom, ida, ip);
1711 return ida;
1714 JS_PUBLIC_API(JSIdArray *)
1715 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, JSIdArray *ida)
1717 JSRuntime *rt;
1718 jsint i, j, k;
1719 JSAtom *atom;
1720 JSBool found;
1721 JSObjectOp init;
1723 CHECK_REQUEST(cx);
1724 assertSameCompartment(cx, obj, ida);
1725 rt = cx->runtime;
1726 if (ida) {
1727 i = ida->length;
1728 } else {
1729 ida = NewIdArray(cx, 8);
1730 if (!ida)
1731 return NULL;
1732 i = 0;
1735 /* Check whether 'undefined' has been resolved and enumerate it if so. */
1736 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1737 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1738 if (!ida)
1739 return NULL;
1741 /* Enumerate only classes that *have* been resolved. */
1742 for (j = 0; standard_class_atoms[j].init; j++) {
1743 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
1744 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1745 if (!ida)
1746 return NULL;
1748 if (found) {
1749 init = standard_class_atoms[j].init;
1751 for (k = 0; standard_class_names[k].init; k++) {
1752 if (standard_class_names[k].init == init) {
1753 atom = StdNameToAtom(cx, &standard_class_names[k]);
1754 ida = AddAtomToArray(cx, atom, ida, &i);
1755 if (!ida)
1756 return NULL;
1760 if (init == js_InitObjectClass) {
1761 for (k = 0; object_prototype_names[k].init; k++) {
1762 atom = StdNameToAtom(cx, &object_prototype_names[k]);
1763 ida = AddAtomToArray(cx, atom, ida, &i);
1764 if (!ida)
1765 return NULL;
1771 /* Trim to exact length. */
1772 return SetIdArrayLength(cx, ida, i);
1775 #undef CLASP
1776 #undef EAGER_ATOM
1777 #undef EAGER_CLASS_ATOM
1778 #undef EAGER_ATOM_CLASP
1779 #undef LAZY_ATOM
1781 JS_PUBLIC_API(JSBool)
1782 JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp)
1784 CHECK_REQUEST(cx);
1785 assertSameCompartment(cx, obj);
1786 return js_GetClassObject(cx, obj, key, objp);
1789 JS_PUBLIC_API(JSObject *)
1790 JS_GetScopeChain(JSContext *cx)
1792 JSStackFrame *fp;
1794 CHECK_REQUEST(cx);
1795 fp = js_GetTopStackFrame(cx);
1796 if (!fp) {
1798 * There is no code active on this context. In place of an actual
1799 * scope chain, use the context's global object, which is set in
1800 * js_InitFunctionAndObjectClasses, and which represents the default
1801 * scope chain for the embedding. See also js_FindClassObject.
1803 * For embeddings that use the inner and outer object hooks, the inner
1804 * object represents the ultimate global object, with the outer object
1805 * acting as a stand-in.
1807 JSObject *obj = cx->globalObject;
1808 if (!obj) {
1809 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
1810 return NULL;
1813 OBJ_TO_INNER_OBJECT(cx, obj);
1814 return obj;
1816 return js_GetScopeChain(cx, fp);
1819 JS_PUBLIC_API(JSObject *)
1820 JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
1822 assertSameCompartment(cx, obj);
1823 return obj->getGlobal();
1826 JS_PUBLIC_API(JSObject *)
1827 JS_GetGlobalForScopeChain(JSContext *cx)
1830 * This is essentially JS_GetScopeChain(cx)->getGlobal(), but without
1831 * falling off trace.
1833 * This use of cx->fp, possibly on trace, is deliberate:
1834 * cx->fp->scopeChain->getGlobal() returns the same object whether we're on
1835 * trace or not, since we do not trace calls across global objects.
1837 VOUCH_DOES_NOT_REQUIRE_STACK();
1839 if (cx->hasfp())
1840 return cx->fp()->getScopeChain()->getGlobal();
1842 JSObject *scope = cx->globalObject;
1843 if (!scope) {
1844 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
1845 return NULL;
1847 OBJ_TO_INNER_OBJECT(cx, scope);
1848 return scope;
1851 JS_PUBLIC_API(jsval)
1852 JS_ComputeThis(JSContext *cx, jsval *vp)
1854 assertSameCompartment(cx, JSValueArray(vp, 2));
1855 if (!ComputeThisFromVp(cx, Valueify(vp)))
1856 return JSVAL_NULL;
1857 return vp[1];
1860 JS_PUBLIC_API(void *)
1861 JS_malloc(JSContext *cx, size_t nbytes)
1863 return cx->malloc(nbytes);
1866 JS_PUBLIC_API(void *)
1867 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1869 return cx->realloc(p, nbytes);
1872 JS_PUBLIC_API(void)
1873 JS_free(JSContext *cx, void *p)
1875 return cx->free(p);
1878 JS_PUBLIC_API(void)
1879 JS_updateMallocCounter(JSContext *cx, size_t nbytes)
1881 return cx->updateMallocCounter(nbytes);
1884 JS_PUBLIC_API(char *)
1885 JS_strdup(JSContext *cx, const char *s)
1887 size_t n;
1888 void *p;
1890 n = strlen(s) + 1;
1891 p = cx->malloc(n);
1892 if (!p)
1893 return NULL;
1894 return (char *)memcpy(p, s, n);
1897 JS_PUBLIC_API(JSBool)
1898 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
1900 d = JS_CANONICALIZE_NAN(d);
1901 Valueify(rval)->setNumber(d);
1902 return JS_TRUE;
1905 #undef JS_AddRoot
1907 JS_PUBLIC_API(JSBool)
1908 JS_AddValueRoot(JSContext *cx, jsval *vp)
1910 CHECK_REQUEST(cx);
1911 return js_AddRoot(cx, Valueify(vp), NULL);
1914 JS_PUBLIC_API(JSBool)
1915 JS_AddStringRoot(JSContext *cx, JSString **rp)
1917 CHECK_REQUEST(cx);
1918 return js_AddGCThingRoot(cx, (void **)rp, NULL);
1921 JS_PUBLIC_API(JSBool)
1922 JS_AddObjectRoot(JSContext *cx, JSObject **rp)
1924 CHECK_REQUEST(cx);
1925 return js_AddGCThingRoot(cx, (void **)rp, NULL);
1928 JS_PUBLIC_API(JSBool)
1929 JS_AddGCThingRoot(JSContext *cx, void **rp)
1931 CHECK_REQUEST(cx);
1932 return js_AddGCThingRoot(cx, (void **)rp, NULL);
1935 JS_PUBLIC_API(JSBool)
1936 JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name)
1938 CHECK_REQUEST(cx);
1939 return js_AddRoot(cx, Valueify(vp), name);
1942 JS_PUBLIC_API(JSBool)
1943 JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name)
1945 CHECK_REQUEST(cx);
1946 return js_AddGCThingRoot(cx, (void **)rp, name);
1949 JS_PUBLIC_API(JSBool)
1950 JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name)
1952 CHECK_REQUEST(cx);
1953 return js_AddGCThingRoot(cx, (void **)rp, name);
1956 JS_PUBLIC_API(JSBool)
1957 JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name)
1959 CHECK_REQUEST(cx);
1960 return js_AddGCThingRoot(cx, (void **)rp, name);
1963 JS_PUBLIC_API(JSBool)
1964 JS_RemoveValueRoot(JSContext *cx, jsval *vp)
1966 CHECK_REQUEST(cx);
1967 return js_RemoveRoot(cx->runtime, (void *)vp);
1970 JS_PUBLIC_API(JSBool)
1971 JS_RemoveStringRoot(JSContext *cx, JSString **rp)
1973 CHECK_REQUEST(cx);
1974 return js_RemoveRoot(cx->runtime, (void *)rp);
1977 JS_PUBLIC_API(JSBool)
1978 JS_RemoveObjectRoot(JSContext *cx, JSObject **rp)
1980 CHECK_REQUEST(cx);
1981 return js_RemoveRoot(cx->runtime, (void *)rp);
1984 JS_PUBLIC_API(JSBool)
1985 JS_RemoveGCThingRoot(JSContext *cx, void **rp)
1987 CHECK_REQUEST(cx);
1988 return js_RemoveRoot(cx->runtime, (void *)rp);
1991 #ifdef DEBUG
1993 JS_PUBLIC_API(void)
1994 JS_DumpNamedRoots(JSRuntime *rt,
1995 void (*dump)(const char *name, void *rp, JSGCRootType type, void *data),
1996 void *data)
1998 js_DumpNamedRoots(rt, dump, data);
2001 #endif /* DEBUG */
2003 JS_PUBLIC_API(uint32)
2004 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
2006 return js_MapGCRoots(rt, map, data);
2009 JS_PUBLIC_API(JSBool)
2010 JS_LockGCThing(JSContext *cx, void *thing)
2012 JSBool ok;
2014 CHECK_REQUEST(cx);
2015 ok = js_LockGCThingRT(cx->runtime, thing);
2016 if (!ok)
2017 JS_ReportOutOfMemory(cx);
2018 return ok;
2021 JS_PUBLIC_API(JSBool)
2022 JS_LockGCThingRT(JSRuntime *rt, void *thing)
2024 return js_LockGCThingRT(rt, thing);
2027 JS_PUBLIC_API(JSBool)
2028 JS_UnlockGCThing(JSContext *cx, void *thing)
2030 CHECK_REQUEST(cx);
2031 js_UnlockGCThingRT(cx->runtime, thing);
2032 return true;
2035 JS_PUBLIC_API(JSBool)
2036 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
2038 js_UnlockGCThingRT(rt, thing);
2039 return true;
2042 JS_PUBLIC_API(void)
2043 JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
2045 rt->gcExtraRootsTraceOp = traceOp;
2046 rt->gcExtraRootsData = data;
2049 JS_PUBLIC_API(void)
2050 JS_TraceRuntime(JSTracer *trc)
2052 LeaveTrace(trc->context);
2053 js_TraceRuntime(trc);
2056 JS_PUBLIC_API(void)
2057 JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
2059 JS_ASSERT(thing);
2060 Mark(trc, thing, kind);
2063 #ifdef DEBUG
2065 #ifdef HAVE_XPCONNECT
2066 #include "dump_xpc.h"
2067 #endif
2069 JS_PUBLIC_API(void)
2070 JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, uint32 kind,
2071 JSBool details)
2073 const char *name;
2074 size_t n;
2076 if (bufsize == 0)
2077 return;
2079 switch (kind) {
2080 case JSTRACE_OBJECT:
2082 JSObject *obj = (JSObject *)thing;
2083 Class *clasp = obj->getClass();
2085 name = clasp->name;
2086 #ifdef HAVE_XPCONNECT
2087 if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
2088 void *privateThing = obj->getPrivate();
2089 if (privateThing) {
2090 const char *xpcClassName = GetXPCObjectClassName(privateThing);
2091 if (xpcClassName)
2092 name = xpcClassName;
2095 #endif
2096 break;
2099 case JSTRACE_STRING:
2100 name = ((JSString *)thing)->isDependent()
2101 ? "substring"
2102 : "string";
2103 break;
2105 #if JS_HAS_XML_SUPPORT
2106 case JSTRACE_XML:
2107 name = "xml";
2108 break;
2109 #endif
2110 default:
2111 JS_ASSERT(0);
2112 return;
2113 break;
2116 n = strlen(name);
2117 if (n > bufsize - 1)
2118 n = bufsize - 1;
2119 memcpy(buf, name, n + 1);
2120 buf += n;
2121 bufsize -= n;
2123 if (details && bufsize > 2) {
2124 *buf++ = ' ';
2125 bufsize--;
2127 switch (kind) {
2128 case JSTRACE_OBJECT:
2130 JSObject *obj = (JSObject *)thing;
2131 Class *clasp = obj->getClass();
2132 if (clasp == &js_FunctionClass) {
2133 JSFunction *fun = GET_FUNCTION_PRIVATE(trc->context, obj);
2134 if (!fun) {
2135 JS_snprintf(buf, bufsize, "<newborn>");
2136 } else if (FUN_OBJECT(fun) != obj) {
2137 JS_snprintf(buf, bufsize, "%p", fun);
2138 } else {
2139 if (fun->atom)
2140 js_PutEscapedString(buf, bufsize,
2141 ATOM_TO_STRING(fun->atom), 0);
2143 } else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
2144 JS_snprintf(buf, bufsize, "%p", obj->getPrivate());
2145 } else {
2146 JS_snprintf(buf, bufsize, "<no private>");
2148 break;
2151 case JSTRACE_STRING:
2152 js_PutEscapedString(buf, bufsize, (JSString *)thing, 0);
2153 break;
2155 #if JS_HAS_XML_SUPPORT
2156 case JSTRACE_XML:
2158 extern const char *js_xml_class_str[];
2159 JSXML *xml = (JSXML *)thing;
2161 JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]);
2162 break;
2164 #endif
2165 default:
2166 JS_ASSERT(0);
2167 break;
2170 buf[bufsize - 1] = '\0';
2173 typedef struct JSHeapDumpNode JSHeapDumpNode;
2175 struct JSHeapDumpNode {
2176 void *thing;
2177 uint32 kind;
2178 JSHeapDumpNode *next; /* next sibling */
2179 JSHeapDumpNode *parent; /* node with the thing that refer to thing
2180 from this node */
2181 char edgeName[1]; /* name of the edge from parent->thing
2182 into thing */
2185 typedef struct JSDumpingTracer {
2186 JSTracer base;
2187 JSDHashTable visited;
2188 JSBool ok;
2189 void *startThing;
2190 void *thingToFind;
2191 void *thingToIgnore;
2192 JSHeapDumpNode *parentNode;
2193 JSHeapDumpNode **lastNodep;
2194 char buffer[200];
2195 } JSDumpingTracer;
2197 static void
2198 DumpNotify(JSTracer *trc, void *thing, uint32 kind)
2200 JSDumpingTracer *dtrc;
2201 JSContext *cx;
2202 JSDHashEntryStub *entry;
2203 JSHeapDumpNode *node;
2204 const char *edgeName;
2205 size_t edgeNameSize;
2207 JS_ASSERT(trc->callback == DumpNotify);
2208 dtrc = (JSDumpingTracer *)trc;
2210 if (!dtrc->ok || thing == dtrc->thingToIgnore)
2211 return;
2213 cx = trc->context;
2216 * Check if we have already seen thing unless it is thingToFind to include
2217 * it to the graph each time we reach it and print all live things that
2218 * refer to thingToFind.
2220 * This does not print all possible paths leading to thingToFind since
2221 * when a thing A refers directly or indirectly to thingToFind and A is
2222 * present several times in the graph, we will print only the first path
2223 * leading to A and thingToFind, other ways to reach A will be ignored.
2225 if (dtrc->thingToFind != thing) {
2227 * The startThing check allows to avoid putting startThing into the
2228 * hash table before tracing startThing in JS_DumpHeap.
2230 if (thing == dtrc->startThing)
2231 return;
2232 entry = (JSDHashEntryStub *)
2233 JS_DHashTableOperate(&dtrc->visited, thing, JS_DHASH_ADD);
2234 if (!entry) {
2235 JS_ReportOutOfMemory(cx);
2236 dtrc->ok = JS_FALSE;
2237 return;
2239 if (entry->key)
2240 return;
2241 entry->key = thing;
2244 if (dtrc->base.debugPrinter) {
2245 dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer));
2246 edgeName = dtrc->buffer;
2247 } else if (dtrc->base.debugPrintIndex != (size_t)-1) {
2248 JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]",
2249 (const char *)dtrc->base.debugPrintArg,
2250 dtrc->base.debugPrintIndex);
2251 edgeName = dtrc->buffer;
2252 } else {
2253 edgeName = (const char*)dtrc->base.debugPrintArg;
2256 edgeNameSize = strlen(edgeName) + 1;
2257 node = (JSHeapDumpNode *)
2258 cx->malloc(offsetof(JSHeapDumpNode, edgeName) + edgeNameSize);
2259 if (!node) {
2260 dtrc->ok = JS_FALSE;
2261 return;
2264 node->thing = thing;
2265 node->kind = kind;
2266 node->next = NULL;
2267 node->parent = dtrc->parentNode;
2268 memcpy(node->edgeName, edgeName, edgeNameSize);
2270 JS_ASSERT(!*dtrc->lastNodep);
2271 *dtrc->lastNodep = node;
2272 dtrc->lastNodep = &node->next;
2275 /* Dump node and the chain that leads to thing it contains. */
2276 static JSBool
2277 DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
2279 JSHeapDumpNode *prev, *following;
2280 size_t chainLimit;
2281 JSBool ok;
2282 enum { MAX_PARENTS_TO_PRINT = 10 };
2284 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2285 &dtrc->base, node->thing, node->kind, JS_TRUE);
2286 if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
2287 return JS_FALSE;
2290 * We need to print the parent chain in the reverse order. To do it in
2291 * O(N) time where N is the chain length we first reverse the chain while
2292 * searching for the top and then print each node while restoring the
2293 * chain order.
2295 chainLimit = MAX_PARENTS_TO_PRINT;
2296 prev = NULL;
2297 for (;;) {
2298 following = node->parent;
2299 node->parent = prev;
2300 prev = node;
2301 node = following;
2302 if (!node)
2303 break;
2304 if (chainLimit == 0) {
2305 if (fputs("...", fp) < 0)
2306 return JS_FALSE;
2307 break;
2309 --chainLimit;
2312 node = prev;
2313 prev = following;
2314 ok = JS_TRUE;
2315 do {
2316 /* Loop must continue even when !ok to restore the parent chain. */
2317 if (ok) {
2318 if (!prev) {
2319 /* Print edge from some runtime root or startThing. */
2320 if (fputs(node->edgeName, fp) < 0)
2321 ok = JS_FALSE;
2322 } else {
2323 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2324 &dtrc->base, prev->thing, prev->kind,
2325 JS_FALSE);
2326 if (fprintf(fp, "(%p %s).%s",
2327 prev->thing, dtrc->buffer, node->edgeName) < 0) {
2328 ok = JS_FALSE;
2332 following = node->parent;
2333 node->parent = prev;
2334 prev = node;
2335 node = following;
2336 } while (node);
2338 return ok && putc('\n', fp) >= 0;
2341 JS_PUBLIC_API(JSBool)
2342 JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind,
2343 void *thingToFind, size_t maxDepth, void *thingToIgnore)
2345 JSDumpingTracer dtrc;
2346 JSHeapDumpNode *node, *children, *next, *parent;
2347 size_t depth;
2348 JSBool thingToFindWasTraced;
2350 if (maxDepth == 0)
2351 return JS_TRUE;
2353 JS_TRACER_INIT(&dtrc.base, cx, DumpNotify);
2354 if (!JS_DHashTableInit(&dtrc.visited, JS_DHashGetStubOps(),
2355 NULL, sizeof(JSDHashEntryStub),
2356 JS_DHASH_DEFAULT_CAPACITY(100))) {
2357 JS_ReportOutOfMemory(cx);
2358 return JS_FALSE;
2360 dtrc.ok = JS_TRUE;
2361 dtrc.startThing = startThing;
2362 dtrc.thingToFind = thingToFind;
2363 dtrc.thingToIgnore = thingToIgnore;
2364 dtrc.parentNode = NULL;
2365 node = NULL;
2366 dtrc.lastNodep = &node;
2367 if (!startThing) {
2368 JS_ASSERT(startKind == 0);
2369 JS_TraceRuntime(&dtrc.base);
2370 } else {
2371 JS_TraceChildren(&dtrc.base, startThing, startKind);
2374 depth = 1;
2375 if (!node)
2376 goto dump_out;
2378 thingToFindWasTraced = thingToFind && thingToFind == startThing;
2379 for (;;) {
2381 * Loop must continue even when !dtrc.ok to free all nodes allocated
2382 * so far.
2384 if (dtrc.ok) {
2385 if (thingToFind == NULL || thingToFind == node->thing)
2386 dtrc.ok = DumpNode(&dtrc, fp, node);
2388 /* Descend into children. */
2389 if (dtrc.ok &&
2390 depth < maxDepth &&
2391 (thingToFind != node->thing || !thingToFindWasTraced)) {
2392 dtrc.parentNode = node;
2393 children = NULL;
2394 dtrc.lastNodep = &children;
2395 JS_TraceChildren(&dtrc.base, node->thing, node->kind);
2396 if (thingToFind == node->thing)
2397 thingToFindWasTraced = JS_TRUE;
2398 if (children != NULL) {
2399 ++depth;
2400 node = children;
2401 continue;
2406 /* Move to next or parents next and free the node. */
2407 for (;;) {
2408 next = node->next;
2409 parent = node->parent;
2410 cx->free(node);
2411 node = next;
2412 if (node)
2413 break;
2414 if (!parent)
2415 goto dump_out;
2416 JS_ASSERT(depth > 1);
2417 --depth;
2418 node = parent;
2422 dump_out:
2423 JS_ASSERT(depth == 1);
2424 JS_DHashTableFinish(&dtrc.visited);
2425 return dtrc.ok;
2428 #endif /* DEBUG */
2430 JS_PUBLIC_API(void)
2431 JS_MarkGCThing(JSContext *cx, jsval v, const char *name, void *arg)
2433 JSTracer *trc;
2435 trc = (JSTracer *)arg;
2436 if (!trc)
2437 trc = cx->runtime->gcMarkingTracer;
2438 else
2439 JS_ASSERT(trc == cx->runtime->gcMarkingTracer);
2441 #ifdef JS_THREADSAFE
2442 JS_ASSERT(cx->runtime->gcThread == trc->context->thread);
2443 #endif
2444 MarkValue(trc, Valueify(v), name ? name : "unknown");
2447 extern JS_PUBLIC_API(JSBool)
2448 JS_IsGCMarkingTracer(JSTracer *trc)
2450 return IS_GC_MARKING_TRACER(trc);
2453 JS_PUBLIC_API(void)
2454 JS_GC(JSContext *cx)
2456 LeaveTrace(cx);
2458 /* Don't nuke active arenas if executing or compiling. */
2459 if (cx->tempPool.current == &cx->tempPool.first)
2460 JS_FinishArenaPool(&cx->tempPool);
2461 js_GC(cx, GC_NORMAL);
2464 JS_PUBLIC_API(void)
2465 JS_MaybeGC(JSContext *cx)
2467 JSRuntime *rt;
2468 uint32 bytes, lastBytes;
2470 rt = cx->runtime;
2472 #ifdef JS_GC_ZEAL
2473 if (rt->gcZeal > 0) {
2474 JS_GC(cx);
2475 return;
2477 #endif
2479 bytes = rt->gcBytes;
2480 lastBytes = rt->gcLastBytes;
2483 * We run the GC if we used all available free GC cells and had to
2484 * allocate extra 1/3 of GC arenas since the last run of GC, or if
2485 * we have malloc'd more bytes through JS_malloc than we were told
2486 * to allocate by JS_NewRuntime.
2488 * The reason for
2489 * bytes > 4/3 lastBytes
2490 * condition is the following. Bug 312238 changed bytes and lastBytes
2491 * to mean the total amount of memory that the GC uses now and right
2492 * after the last GC.
2494 * Before the bug the variables meant the size of allocated GC things
2495 * now and right after the last GC. That size did not include the
2496 * memory taken by free GC cells and the condition was
2497 * bytes > 3/2 lastBytes.
2498 * That is, we run the GC if we have half again as many bytes of
2499 * GC-things as the last time we GC'd. To be compatible we need to
2500 * express that condition through the new meaning of bytes and
2501 * lastBytes.
2503 * We write the original condition as
2504 * B*(1-F) > 3/2 Bl*(1-Fl)
2505 * where B is the total memory size allocated by GC and F is the free
2506 * cell density currently and Sl and Fl are the size and the density
2507 * right after GC. The density by definition is memory taken by free
2508 * cells divided by total amount of memory. In other words, B and Bl
2509 * are bytes and lastBytes with the new meaning and B*(1-F) and
2510 * Bl*(1-Fl) are bytes and lastBytes with the original meaning.
2512 * Our task is to exclude F and Fl from the last statement. According
2513 * to the stats from bug 331966 comment 23, Fl is about 10-25% for a
2514 * typical run of the browser. It means that the original condition
2515 * implied that we did not run GC unless we exhausted the pool of
2516 * free cells. Indeed if we still have free cells, then B == Bl since
2517 * we did not yet allocated any new arenas and the condition means
2518 * 1 - F > 3/2 (1-Fl) or 3/2Fl > 1/2 + F
2519 * That implies 3/2 Fl > 1/2 or Fl > 1/3. That cannot be fulfilled
2520 * for the state described by the stats. So we can write the original
2521 * condition as:
2522 * F == 0 && B > 3/2 Bl(1-Fl)
2523 * Again using the stats we see that Fl is about 11% when the browser
2524 * starts up and when we are far from hitting rt->gcMaxBytes. With
2525 * this F we have
2526 * F == 0 && B > 3/2 Bl(1-0.11)
2527 * or approximately F == 0 && B > 4/3 Bl.
2529 if ((bytes > 8192 && bytes > lastBytes + lastBytes / 3) ||
2530 rt->isGCMallocLimitReached()) {
2531 JS_GC(cx);
2535 JS_PUBLIC_API(JSGCCallback)
2536 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
2538 CHECK_REQUEST(cx);
2539 return JS_SetGCCallbackRT(cx->runtime, cb);
2542 JS_PUBLIC_API(JSGCCallback)
2543 JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
2545 JSGCCallback oldcb;
2547 oldcb = rt->gcCallback;
2548 rt->gcCallback = cb;
2549 return oldcb;
2552 JS_PUBLIC_API(JSBool)
2553 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
2555 JS_ASSERT(thing);
2556 JS_ASSERT(!cx->runtime->gcMarkingTracer);
2557 return js_IsAboutToBeFinalized(thing);
2560 JS_PUBLIC_API(void)
2561 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
2563 switch (key) {
2564 case JSGC_MAX_BYTES:
2565 rt->gcMaxBytes = value;
2566 break;
2567 case JSGC_MAX_MALLOC_BYTES:
2568 rt->setGCMaxMallocBytes(value);
2569 break;
2570 case JSGC_STACKPOOL_LIFESPAN:
2571 rt->gcEmptyArenaPoolLifespan = value;
2572 break;
2573 default:
2574 JS_ASSERT(key == JSGC_TRIGGER_FACTOR);
2575 JS_ASSERT(value >= 100);
2576 rt->setGCTriggerFactor(value);
2577 return;
2581 JS_PUBLIC_API(uint32)
2582 JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
2584 switch (key) {
2585 case JSGC_MAX_BYTES:
2586 return rt->gcMaxBytes;
2587 case JSGC_MAX_MALLOC_BYTES:
2588 return rt->gcMaxMallocBytes;
2589 case JSGC_STACKPOOL_LIFESPAN:
2590 return rt->gcEmptyArenaPoolLifespan;
2591 case JSGC_TRIGGER_FACTOR:
2592 return rt->gcTriggerFactor;
2593 case JSGC_BYTES:
2594 return rt->gcBytes;
2595 default:
2596 JS_ASSERT(key == JSGC_NUMBER);
2597 return rt->gcNumber;
2601 JS_PUBLIC_API(void)
2602 JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32 value)
2604 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2605 #ifdef JS_TRACER
2606 SetMaxCodeCacheBytes(cx, value);
2607 #endif
2610 JS_PUBLIC_API(uint32)
2611 JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key)
2613 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2614 #ifdef JS_TRACER
2615 return JS_THREAD_DATA(cx)->traceMonitor.maxCodeCacheBytes;
2616 #else
2617 return 0;
2618 #endif
2621 JS_PUBLIC_API(void)
2622 JS_FlushCaches(JSContext *cx)
2624 #ifdef JS_TRACER
2625 FlushJITCache(cx);
2626 #endif
2629 JS_PUBLIC_API(intN)
2630 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
2632 return js_ChangeExternalStringFinalizer(NULL, finalizer);
2635 JS_PUBLIC_API(intN)
2636 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
2638 return js_ChangeExternalStringFinalizer(finalizer, NULL);
2641 JS_PUBLIC_API(JSString *)
2642 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
2644 CHECK_REQUEST(cx);
2645 JS_ASSERT(uintN(type) < JS_EXTERNAL_STRING_LIMIT);
2647 JSString *str = js_NewGCExternalString(cx, uintN(type));
2648 if (!str)
2649 return NULL;
2650 str->initFlat(chars, length);
2651 cx->updateMallocCounter((length + 1) * sizeof(jschar));
2652 return str;
2655 JS_PUBLIC_API(intN)
2656 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
2659 * No need to test this in js_GetExternalStringGCType, which asserts its
2660 * inverse instead of wasting cycles on testing a condition we can ensure
2661 * by auditing in-VM calls to the js_... helper.
2663 if (JSString::isStatic(str))
2664 return -1;
2666 return js_GetExternalStringGCType(str);
2669 JS_PUBLIC_API(void)
2670 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
2672 #if JS_STACK_GROWTH_DIRECTION > 0
2673 if (limitAddr == 0)
2674 limitAddr = jsuword(-1);
2675 #endif
2676 cx->stackLimit = limitAddr;
2679 JS_PUBLIC_API(void)
2680 JS_SetNativeStackQuota(JSContext *cx, size_t stackSize)
2682 #ifdef JS_THREADSAFE
2683 JS_ASSERT(cx->thread);
2684 #endif
2686 #if JS_STACK_GROWTH_DIRECTION > 0
2687 if (stackSize == 0) {
2688 cx->stackLimit = jsuword(-1);
2689 } else {
2690 jsuword stackBase = reinterpret_cast<jsuword>(JS_THREAD_DATA(cx)->nativeStackBase);
2691 JS_ASSERT(stackBase <= size_t(-1) - stackSize);
2692 cx->stackLimit = stackBase + stackSize - 1;
2694 #else
2695 if (stackSize == 0) {
2696 cx->stackLimit = 0;
2697 } else {
2698 jsuword stackBase = reinterpret_cast<jsuword>(JS_THREAD_DATA(cx)->nativeStackBase);
2699 JS_ASSERT(stackBase >= stackSize);
2700 cx->stackLimit = stackBase - (stackSize - 1);
2702 #endif
2705 JS_PUBLIC_API(void)
2706 JS_SetScriptStackQuota(JSContext *cx, size_t quota)
2708 cx->scriptStackQuota = quota;
2711 /************************************************************************/
2713 JS_PUBLIC_API(void)
2714 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
2716 cx->free(ida);
2719 JS_PUBLIC_API(JSBool)
2720 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
2722 CHECK_REQUEST(cx);
2723 assertSameCompartment(cx, v);
2724 return ValueToId(cx, Valueify(v), idp);
2727 JS_PUBLIC_API(JSBool)
2728 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
2730 CHECK_REQUEST(cx);
2731 *vp = IdToJsval(id);
2732 assertSameCompartment(cx, *vp);
2733 return JS_TRUE;
2736 JS_PUBLIC_API(JSBool)
2737 JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
2739 return JS_TRUE;
2742 JS_PUBLIC_API(JSBool)
2743 JS_EnumerateStub(JSContext *cx, JSObject *obj)
2745 return JS_TRUE;
2748 JS_PUBLIC_API(JSBool)
2749 JS_ResolveStub(JSContext *cx, JSObject *obj, jsid id)
2751 return JS_TRUE;
2754 JS_PUBLIC_API(JSBool)
2755 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
2757 JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION);
2758 return js_TryValueOf(cx, obj, type, Valueify(vp));
2761 JS_PUBLIC_API(void)
2762 JS_FinalizeStub(JSContext *cx, JSObject *obj)
2765 JS_PUBLIC_API(JSObject *)
2766 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
2767 JSClass *clasp, JSNative constructor, uintN nargs,
2768 JSPropertySpec *ps, JSFunctionSpec *fs,
2769 JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
2771 CHECK_REQUEST(cx);
2772 assertSameCompartment(cx, obj, parent_proto);
2773 return js_InitClass(cx, obj, parent_proto, Valueify(clasp),
2774 Valueify(constructor), nargs,
2775 ps, fs, static_ps, static_fs);
2778 #ifdef JS_THREADSAFE
2779 JS_PUBLIC_API(JSClass *)
2780 JS_GetClass(JSContext *cx, JSObject *obj)
2782 return Jsvalify(obj->getClass());
2784 #else
2785 JS_PUBLIC_API(JSClass *)
2786 JS_GetClass(JSObject *obj)
2788 return Jsvalify(obj->getClass());
2790 #endif
2792 JS_PUBLIC_API(JSBool)
2793 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2795 CHECK_REQUEST(cx);
2796 assertSameCompartment(cx, obj);
2797 return InstanceOf(cx, obj, Valueify(clasp), Valueify(argv));
2800 JS_PUBLIC_API(JSBool)
2801 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
2803 assertSameCompartment(cx, obj, v);
2804 return HasInstance(cx, obj, Valueify(&v), bp);
2807 JS_PUBLIC_API(void *)
2808 JS_GetPrivate(JSContext *cx, JSObject *obj)
2810 assertSameCompartment(cx, obj);
2811 return obj->getPrivate();
2814 JS_PUBLIC_API(JSBool)
2815 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2817 assertSameCompartment(cx, obj);
2818 obj->setPrivate(data);
2819 return true;
2822 JS_PUBLIC_API(void *)
2823 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2825 if (!InstanceOf(cx, obj, Valueify(clasp), Valueify(argv)))
2826 return NULL;
2827 return obj->getPrivate();
2830 JS_PUBLIC_API(JSObject *)
2831 JS_GetPrototype(JSContext *cx, JSObject *obj)
2833 JSObject *proto;
2835 CHECK_REQUEST(cx);
2836 assertSameCompartment(cx, obj);
2837 proto = obj->getProto();
2839 /* Beware ref to dead object (we may be called from obj's finalizer). */
2840 return proto && proto->map ? proto : NULL;
2843 JS_PUBLIC_API(JSBool)
2844 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
2846 CHECK_REQUEST(cx);
2847 assertSameCompartment(cx, obj, proto);
2848 return SetProto(cx, obj, proto, JS_FALSE);
2851 JS_PUBLIC_API(JSObject *)
2852 JS_GetParent(JSContext *cx, JSObject *obj)
2854 assertSameCompartment(cx, obj);
2855 JSObject *parent = obj->getParent();
2857 /* Beware ref to dead object (we may be called from obj's finalizer). */
2858 return parent && parent->map ? parent : NULL;
2861 JS_PUBLIC_API(JSBool)
2862 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
2864 CHECK_REQUEST(cx);
2865 JS_ASSERT(parent || !obj->getParent());
2866 assertSameCompartment(cx, obj, parent);
2867 obj->setParent(parent);
2868 return true;
2871 JS_PUBLIC_API(JSObject *)
2872 JS_GetConstructor(JSContext *cx, JSObject *proto)
2874 Value cval;
2876 CHECK_REQUEST(cx);
2877 assertSameCompartment(cx, proto);
2879 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
2881 if (!proto->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), &cval))
2882 return NULL;
2884 JSObject *funobj;
2885 if (!IsFunctionObject(cval, &funobj)) {
2886 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
2887 proto->getClass()->name);
2888 return NULL;
2890 return &cval.toObject();
2893 JS_PUBLIC_API(JSBool)
2894 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
2896 assertSameCompartment(cx, obj);
2897 *idp = OBJECT_TO_JSID(obj);
2898 return JS_TRUE;
2901 JS_PUBLIC_API(JSObject *)
2902 JS_NewGlobalObject(JSContext *cx, JSClass *clasp)
2904 CHECK_REQUEST(cx);
2905 JS_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
2906 JSObject *obj = NewNonFunction<WithProto::Given>(cx, Valueify(clasp), NULL, NULL);
2907 if (obj &&
2908 !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_COMPARTMENT,
2909 PrivateValue(cx->compartment))) {
2910 return false;
2912 return obj;
2915 JS_PUBLIC_API(JSObject *)
2916 JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals)
2918 CHECK_REQUEST(cx);
2919 JSCompartment *compartment = NewCompartment(cx, principals);
2920 if (!compartment)
2921 return NULL;
2923 JSCompartment *saved = cx->compartment;
2924 cx->compartment = compartment;
2925 JSObject *obj = JS_NewGlobalObject(cx, clasp);
2926 cx->compartment = saved;
2928 return obj;
2931 JS_PUBLIC_API(JSObject *)
2932 JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
2934 CHECK_REQUEST(cx);
2935 assertSameCompartment(cx, proto, parent);
2937 Class *clasp = Valueify(jsclasp);
2938 if (!clasp)
2939 clasp = &js_ObjectClass; /* default class is Object */
2941 JS_ASSERT(clasp != &js_FunctionClass);
2942 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
2944 JSObject *obj = NewNonFunction<WithProto::Class>(cx, clasp, proto, parent);
2946 JS_ASSERT_IF(obj, obj->getParent());
2947 return obj;
2950 JS_PUBLIC_API(JSObject *)
2951 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
2953 CHECK_REQUEST(cx);
2954 assertSameCompartment(cx, proto, parent);
2956 Class *clasp = Valueify(jsclasp);
2957 if (!clasp)
2958 clasp = &js_ObjectClass; /* default class is Object */
2960 JS_ASSERT(clasp != &js_FunctionClass);
2961 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
2963 return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
2966 JS_PUBLIC_API(JSBool)
2967 JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
2969 CHECK_REQUEST(cx);
2970 assertSameCompartment(cx, obj);
2972 JSScope *scope;
2973 JSIdArray *ida;
2974 uint32 nslots, i;
2976 if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx))
2977 return JS_FALSE;
2979 if (!obj->isNative()) {
2980 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2981 JSMSG_CANT_SEAL_OBJECT,
2982 obj->getClass()->name);
2983 return JS_FALSE;
2986 scope = obj->scope();
2988 #if defined JS_THREADSAFE && defined DEBUG
2989 /* Insist on scope being used exclusively by cx's thread. */
2990 if (scope->title.ownercx != cx) {
2991 JS_LOCK_OBJ(cx, obj);
2992 JS_ASSERT(obj->scope() == scope);
2993 JS_ASSERT(scope->title.ownercx == cx);
2994 JS_UNLOCK_SCOPE(cx, scope);
2996 #endif
2998 /* Nothing to do if obj's scope is already sealed. */
2999 if (scope->sealed())
3000 return JS_TRUE;
3002 /* XXX Enumerate lazy properties now, as they can't be added later. */
3003 ida = JS_Enumerate(cx, obj);
3004 if (!ida)
3005 return JS_FALSE;
3006 JS_DestroyIdArray(cx, ida);
3008 /* Ensure that obj has its own, mutable scope, and seal that scope. */
3009 JS_LOCK_OBJ(cx, obj);
3010 scope = js_GetMutableScope(cx, obj);
3011 if (scope)
3012 scope->seal(cx);
3013 JS_UNLOCK_OBJ(cx, obj);
3014 if (!scope)
3015 return JS_FALSE;
3017 /* If we are not sealing an entire object graph, we're done. */
3018 if (!deep)
3019 return JS_TRUE;
3021 /* Walk slots in obj and if any value is a non-null object, seal it. */
3022 nslots = scope->freeslot;
3023 for (i = 0; i != nslots; ++i) {
3024 const Value &v = obj->getSlot(i);
3025 if (i == JSSLOT_PRIVATE && (obj->getClass()->flags & JSCLASS_HAS_PRIVATE))
3026 continue;
3027 if (v.isPrimitive())
3028 continue;
3029 if (!JS_SealObject(cx, &v.toObject(), deep))
3030 return JS_FALSE;
3032 return JS_TRUE;
3035 JS_PUBLIC_API(JSObject *)
3036 JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
3038 CHECK_REQUEST(cx);
3039 assertSameCompartment(cx, proto, parent);
3040 Class *clasp = Valueify(jsclasp);
3041 if (!clasp)
3042 clasp = &js_ObjectClass; /* default class is Object */
3043 return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
3046 JS_PUBLIC_API(JSObject *)
3047 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *proto,
3048 JSObject *parent, uintN argc, jsval *argv)
3050 CHECK_REQUEST(cx);
3051 assertSameCompartment(cx, proto, parent, JSValueArray(argv, argc));
3052 Class *clasp = Valueify(jsclasp);
3053 if (!clasp)
3054 clasp = &js_ObjectClass; /* default class is Object */
3055 return js_ConstructObject(cx, clasp, proto, parent, argc, Valueify(argv));
3058 static JSBool
3059 LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3060 JSObject **objp, JSProperty **propp)
3062 CHECK_REQUEST(cx);
3063 assertSameCompartment(cx, obj, id);
3065 JSAutoResolveFlags rf(cx, flags);
3066 id = js_CheckForStringIndex(id);
3067 return obj->lookupProperty(cx, id, objp, propp);
3070 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
3072 static JSBool
3073 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, jsid id,
3074 JSProperty *prop, Value *vp)
3076 if (!prop) {
3077 /* XXX bad API: no way to tell "not defined" from "void value" */
3078 vp->setUndefined();
3079 return JS_TRUE;
3082 if (obj2->isNative()) {
3083 JSScopeProperty *sprop = (JSScopeProperty *) prop;
3085 if (sprop->isMethod()) {
3086 AutoScopePropertyRooter root(cx, sprop);
3087 JS_UNLOCK_OBJ(cx, obj2);
3088 vp->setObject(sprop->methodObject());
3089 return obj2->scope()->methodReadBarrier(cx, sprop, vp);
3092 /* Peek at the native property's slot value, without doing a Get. */
3093 if (SPROP_HAS_VALID_SLOT(sprop, obj2->scope()))
3094 *vp = obj2->lockedGetSlot(sprop->slot);
3095 else
3096 vp->setBoolean(true);
3097 JS_UNLOCK_OBJ(cx, obj2);
3098 } else if (obj2->isDenseArray()) {
3099 return js_GetDenseArrayElementValue(cx, obj2, id, vp);
3100 } else {
3101 /* XXX bad API: no way to return "defined but value unknown" */
3102 vp->setBoolean(true);
3104 return true;
3107 JS_PUBLIC_API(JSBool)
3108 JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3110 JSObject *obj2;
3111 JSProperty *prop;
3112 return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) &&
3113 LookupResult(cx, obj, obj2, id, prop, Valueify(vp));
3116 JS_PUBLIC_API(JSBool)
3117 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3119 return JS_LookupPropertyById(cx, obj, INT_TO_JSID(index), vp);
3122 JS_PUBLIC_API(JSBool)
3123 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3125 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3126 return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3129 JS_PUBLIC_API(JSBool)
3130 JS_LookupUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3132 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3133 return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3136 JS_PUBLIC_API(JSBool)
3137 JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3138 JSObject **objp, jsval *vp)
3140 JSBool ok;
3141 JSProperty *prop;
3143 CHECK_REQUEST(cx);
3144 assertSameCompartment(cx, obj, id);
3145 ok = obj->isNative()
3146 ? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0
3147 : obj->lookupProperty(cx, id, objp, &prop);
3148 return ok && LookupResult(cx, obj, *objp, id, prop, Valueify(vp));
3151 JS_PUBLIC_API(JSBool)
3152 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, uintN flags, jsval *vp)
3154 JSObject *obj2;
3155 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3156 return atom && JS_LookupPropertyWithFlagsById(cx, obj, ATOM_TO_JSID(atom), flags, &obj2, vp);
3159 static JSBool
3160 HasPropertyResult(JSContext *cx, JSObject *obj2, JSProperty *prop, JSBool *foundp)
3162 *foundp = (prop != NULL);
3163 if (prop)
3164 obj2->dropProperty(cx, prop);
3165 return true;
3168 JS_PUBLIC_API(JSBool)
3169 JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3171 JSObject *obj2;
3172 JSProperty *prop;
3173 return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3174 &obj2, &prop) &&
3175 HasPropertyResult(cx, obj2, prop, foundp);
3178 JS_PUBLIC_API(JSBool)
3179 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3181 return JS_HasPropertyById(cx, obj, INT_TO_JSID(index), foundp);
3184 JS_PUBLIC_API(JSBool)
3185 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3187 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3188 return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3191 JS_PUBLIC_API(JSBool)
3192 JS_HasUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, JSBool *foundp)
3194 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3195 return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3198 JS_PUBLIC_API(JSBool)
3199 JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3201 CHECK_REQUEST(cx);
3202 assertSameCompartment(cx, obj, id);
3204 if (!obj->isNative()) {
3205 JSObject *obj2;
3206 JSProperty *prop;
3208 if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3209 &obj2, &prop)) {
3210 return JS_FALSE;
3212 *foundp = (obj == obj2);
3213 if (prop)
3214 obj2->dropProperty(cx, prop);
3215 return JS_TRUE;
3218 JS_LOCK_OBJ(cx, obj);
3219 JSScope *scope = obj->scope();
3220 *foundp = scope->hasProperty(id);
3221 JS_UNLOCK_SCOPE(cx, scope);
3222 return JS_TRUE;
3225 JS_PUBLIC_API(JSBool)
3226 JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3228 return JS_AlreadyHasOwnPropertyById(cx, obj, INT_TO_JSID(index), foundp);
3231 JS_PUBLIC_API(JSBool)
3232 JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3234 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3235 return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3238 JS_PUBLIC_API(JSBool)
3239 JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3240 JSBool *foundp)
3242 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3243 return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3246 static JSBool
3247 DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value,
3248 PropertyOp getter, PropertyOp setter, uintN attrs,
3249 uintN flags, intN tinyid)
3251 CHECK_REQUEST(cx);
3252 assertSameCompartment(cx, obj, id, value,
3253 (attrs & JSPROP_GETTER)
3254 ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
3255 : NULL,
3256 (attrs & JSPROP_SETTER)
3257 ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
3258 : NULL);
3260 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
3261 if (flags != 0 && obj->isNative()) {
3262 return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter,
3263 attrs, flags, tinyid, NULL);
3265 return obj->defineProperty(cx, id, value, getter, setter, attrs);
3268 JS_PUBLIC_API(JSBool)
3269 JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
3270 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3272 return DefinePropertyById(cx, obj, id, Valueify(value), Valueify(getter),
3273 Valueify(setter), attrs, 0, 0);
3276 JS_PUBLIC_API(JSBool)
3277 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
3278 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3280 return DefinePropertyById(cx, obj, INT_TO_JSID(index), Valueify(value),
3281 Valueify(getter), Valueify(setter), attrs, 0, 0);
3284 static JSBool
3285 DefineProperty(JSContext *cx, JSObject *obj, const char *name, const Value &value,
3286 PropertyOp getter, PropertyOp setter, uintN attrs,
3287 uintN flags, intN tinyid)
3289 jsid id;
3290 JSAtom *atom;
3292 if (attrs & JSPROP_INDEX) {
3293 id = INT_TO_JSID(intptr_t(name));
3294 atom = NULL;
3295 attrs &= ~JSPROP_INDEX;
3296 } else {
3297 atom = js_Atomize(cx, name, strlen(name), 0);
3298 if (!atom)
3299 return JS_FALSE;
3300 id = ATOM_TO_JSID(atom);
3302 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid);
3305 JS_PUBLIC_API(JSBool)
3306 JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
3307 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3309 return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter),
3310 Valueify(setter), attrs, 0, 0);
3313 JS_PUBLIC_API(JSBool)
3314 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, int8 tinyid,
3315 jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3317 return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter),
3318 Valueify(setter), attrs, JSScopeProperty::HAS_SHORTID, tinyid);
3321 static JSBool
3322 DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3323 const Value &value, PropertyOp getter, PropertyOp setter, uintN attrs,
3324 uintN flags, intN tinyid)
3326 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3327 return atom && DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs,
3328 flags, tinyid);
3331 JS_PUBLIC_API(JSBool)
3332 JS_DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3333 jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3335 return DefineUCProperty(cx, obj, name, namelen, Valueify(value),
3336 Valueify(getter), Valueify(setter), attrs, 0, 0);
3339 JS_PUBLIC_API(JSBool)
3340 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3341 int8 tinyid, jsval value, JSPropertyOp getter, JSPropertyOp setter,
3342 uintN attrs)
3344 return DefineUCProperty(cx, obj, name, namelen, Valueify(value), Valueify(getter),
3345 Valueify(setter), attrs, JSScopeProperty::HAS_SHORTID, tinyid);
3348 JS_PUBLIC_API(JSBool)
3349 JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp)
3351 CHECK_REQUEST(cx);
3352 assertSameCompartment(cx, obj, id, descriptor);
3353 return js_DefineOwnProperty(cx, obj, id, Valueify(descriptor), bp);
3356 JS_PUBLIC_API(JSObject *)
3357 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp,
3358 JSObject *proto, uintN attrs)
3360 CHECK_REQUEST(cx);
3361 assertSameCompartment(cx, obj, proto);
3363 Class *clasp = Valueify(jsclasp);
3364 if (!clasp)
3365 clasp = &js_ObjectClass; /* default class is Object */
3367 JSObject *nobj = NewObject<WithProto::Class>(cx, clasp, proto, obj);
3368 if (!nobj)
3369 return NULL;
3371 if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
3372 return NULL;
3374 return nobj;
3377 JS_PUBLIC_API(JSBool)
3378 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
3380 JSBool ok;
3381 uintN attrs;
3383 CHECK_REQUEST(cx);
3384 for (ok = JS_TRUE; cds->name; cds++) {
3385 Value value = DoubleValue(cds->dval);
3386 attrs = cds->flags;
3387 if (!attrs)
3388 attrs = JSPROP_READONLY | JSPROP_PERMANENT;
3389 ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
3390 if (!ok)
3391 break;
3393 return ok;
3396 JS_PUBLIC_API(JSBool)
3397 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
3399 JSBool ok;
3401 for (ok = true; ps->name; ps++) {
3402 ok = DefineProperty(cx, obj, ps->name, UndefinedValue(),
3403 Valueify(ps->getter), Valueify(ps->setter),
3404 ps->flags, JSScopeProperty::HAS_SHORTID, ps->tinyid);
3405 if (!ok)
3406 break;
3408 return ok;
3411 JS_PUBLIC_API(JSBool)
3412 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *alias)
3414 JSObject *obj2;
3415 JSProperty *prop;
3416 JSBool ok;
3417 JSScopeProperty *sprop;
3419 CHECK_REQUEST(cx);
3420 assertSameCompartment(cx, obj);
3422 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3423 if (!atom)
3424 return JS_FALSE;
3425 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
3426 return JS_FALSE;
3427 if (!prop) {
3428 js_ReportIsNotDefined(cx, name);
3429 return JS_FALSE;
3431 if (obj2 != obj || !obj->isNative()) {
3432 obj2->dropProperty(cx, prop);
3433 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3434 alias, name, obj2->getClass()->name);
3435 return JS_FALSE;
3437 atom = js_Atomize(cx, alias, strlen(alias), 0);
3438 if (!atom) {
3439 ok = JS_FALSE;
3440 } else {
3441 sprop = (JSScopeProperty *)prop;
3442 ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
3443 sprop->getter(), sprop->setter(), sprop->slot,
3444 sprop->attributes(), sprop->getFlags() | JSScopeProperty::ALIAS,
3445 sprop->shortid)
3446 != NULL);
3448 JS_UNLOCK_OBJ(cx, obj);
3449 return ok;
3452 JS_PUBLIC_API(JSBool)
3453 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
3455 JSObject *obj2;
3456 JSProperty *prop;
3457 JSScopeProperty *sprop;
3458 JSBool ok;
3460 CHECK_REQUEST(cx);
3461 assertSameCompartment(cx, obj);
3463 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3464 if (!atom)
3465 return JS_FALSE;
3466 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
3467 return JS_FALSE;
3468 if (!prop) {
3469 js_ReportIsNotDefined(cx, name);
3470 return JS_FALSE;
3472 if (obj2 != obj || !obj->isNative()) {
3473 char numBuf[12];
3474 obj2->dropProperty(cx, prop);
3475 JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
3476 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3477 numBuf, name, obj2->getClass()->name);
3478 return JS_FALSE;
3480 sprop = (JSScopeProperty *)prop;
3481 ok = (js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
3482 sprop->getter(), sprop->setter(), sprop->slot,
3483 sprop->attributes(), sprop->getFlags() | JSScopeProperty::ALIAS,
3484 sprop->shortid)
3485 != NULL);
3486 JS_UNLOCK_OBJ(cx, obj);
3487 return ok;
3490 static JSBool
3491 GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3492 JSBool own, PropertyDescriptor *desc)
3494 JSObject *obj2;
3495 JSProperty *prop;
3497 if (!LookupPropertyById(cx, obj, id, flags, &obj2, &prop))
3498 return JS_FALSE;
3500 if (!prop || (own && obj != obj2)) {
3501 desc->obj = NULL;
3502 desc->attrs = 0;
3503 desc->getter = NULL;
3504 desc->setter = NULL;
3505 desc->value.setUndefined();
3506 if (prop)
3507 obj2->dropProperty(cx, prop);
3508 return JS_TRUE;
3511 desc->obj = obj2;
3512 if (obj2->isNative()) {
3513 JSScopeProperty *sprop = (JSScopeProperty *) prop;
3514 desc->attrs = sprop->attributes();
3516 if (sprop->isMethod()) {
3517 desc->getter = desc->setter = PropertyStub;
3518 desc->value.setObject(sprop->methodObject());
3519 } else {
3520 desc->getter = sprop->getter();
3521 desc->setter = sprop->setter();
3522 if (SPROP_HAS_VALID_SLOT(sprop, obj2->scope()))
3523 desc->value = obj2->lockedGetSlot(sprop->slot);
3524 else
3525 desc->value.setUndefined();
3527 JS_UNLOCK_OBJ(cx, obj2);
3528 } else if (obj2->isProxy()) {
3529 JSAutoResolveFlags rf(cx, flags);
3530 return own
3531 ? JSProxy::getOwnPropertyDescriptor(cx, obj2, id, desc)
3532 : JSProxy::getPropertyDescriptor(cx, obj2, id, desc);
3533 } else {
3534 if (!obj2->getAttributes(cx, id, &desc->attrs))
3535 return false;
3536 desc->getter = NULL;
3537 desc->setter = NULL;
3538 desc->value.setUndefined();
3540 return true;
3543 JS_PUBLIC_API(JSBool)
3544 JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3545 JSPropertyDescriptor *desc)
3547 return GetPropertyDescriptorById(cx, obj, id, flags, JS_FALSE, Valueify(desc));
3550 JS_PUBLIC_API(JSBool)
3551 JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *obj, jsid id,
3552 uintN *attrsp, JSBool *foundp,
3553 JSPropertyOp *getterp, JSPropertyOp *setterp)
3555 PropertyDescriptor desc;
3556 if (!GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, JS_FALSE, &desc))
3557 return false;
3559 *attrsp = desc.attrs;
3560 *foundp = (desc.obj != NULL);
3561 if (getterp)
3562 *getterp = Jsvalify(desc.getter);
3563 if (setterp)
3564 *setterp = Jsvalify(desc.setter);
3565 return true;
3568 JS_PUBLIC_API(JSBool)
3569 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3570 uintN *attrsp, JSBool *foundp)
3572 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3573 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3574 attrsp, foundp, NULL, NULL);
3577 JS_PUBLIC_API(JSBool)
3578 JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3579 uintN *attrsp, JSBool *foundp)
3581 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3582 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3583 attrsp, foundp, NULL, NULL);
3586 JS_PUBLIC_API(JSBool)
3587 JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, const char *name,
3588 uintN *attrsp, JSBool *foundp,
3589 JSPropertyOp *getterp, JSPropertyOp *setterp)
3591 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3592 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3593 attrsp, foundp, getterp, setterp);
3596 JS_PUBLIC_API(JSBool)
3597 JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
3598 const jschar *name, size_t namelen,
3599 uintN *attrsp, JSBool *foundp,
3600 JSPropertyOp *getterp, JSPropertyOp *setterp)
3602 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3603 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3604 attrsp, foundp, getterp, setterp);
3607 JS_PUBLIC_API(JSBool)
3608 JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3610 CHECK_REQUEST(cx);
3611 return js_GetOwnPropertyDescriptor(cx, obj, id, Valueify(vp));
3614 static JSBool
3615 SetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, uintN attrs, JSBool *foundp)
3617 JSObject *obj2;
3618 JSProperty *prop;
3620 if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
3621 return false;
3622 if (!prop || obj != obj2) {
3623 *foundp = false;
3624 if (prop)
3625 obj2->dropProperty(cx, prop);
3626 return true;
3628 JSBool ok = obj->isNative()
3629 ? js_SetNativeAttributes(cx, obj, (JSScopeProperty *) prop, attrs)
3630 : obj->setAttributes(cx, id, &attrs);
3631 if (ok)
3632 *foundp = true;
3633 return ok;
3636 JS_PUBLIC_API(JSBool)
3637 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3638 uintN attrs, JSBool *foundp)
3640 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3641 return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
3644 JS_PUBLIC_API(JSBool)
3645 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3646 uintN attrs, JSBool *foundp)
3648 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3649 return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
3652 JS_PUBLIC_API(JSBool)
3653 JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3655 CHECK_REQUEST(cx);
3656 assertSameCompartment(cx, obj, id);
3657 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3658 return obj->getProperty(cx, id, Valueify(vp));
3661 JS_PUBLIC_API(JSBool)
3662 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3664 return JS_GetPropertyById(cx, obj, INT_TO_JSID(index), vp);
3667 JS_PUBLIC_API(JSBool)
3668 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3670 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3671 return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3674 JS_PUBLIC_API(JSBool)
3675 JS_GetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3677 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3678 return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3681 JS_PUBLIC_API(JSBool)
3682 JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval *vp)
3684 CHECK_REQUEST(cx);
3685 assertSameCompartment(cx, obj, id);
3686 if (!js_GetMethod(cx, obj, id, JSGET_METHOD_BARRIER, Valueify(vp)))
3687 return JS_FALSE;
3688 if (objp)
3689 *objp = obj;
3690 return JS_TRUE;
3693 JS_PUBLIC_API(JSBool)
3694 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, jsval *vp)
3696 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3697 return atom && JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), objp, vp);
3700 JS_PUBLIC_API(JSBool)
3701 JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3703 CHECK_REQUEST(cx);
3704 assertSameCompartment(cx, obj, id);
3705 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
3706 return obj->setProperty(cx, id, Valueify(vp));
3709 JS_PUBLIC_API(JSBool)
3710 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3712 return JS_SetPropertyById(cx, obj, INT_TO_JSID(index), vp);
3715 JS_PUBLIC_API(JSBool)
3716 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3718 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3719 return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3722 JS_PUBLIC_API(JSBool)
3723 JS_SetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3725 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3726 return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3729 JS_PUBLIC_API(JSBool)
3730 JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
3732 CHECK_REQUEST(cx);
3733 assertSameCompartment(cx, obj, id);
3734 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3735 return obj->deleteProperty(cx, id, Valueify(rval));
3738 JS_PUBLIC_API(JSBool)
3739 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
3741 return JS_DeletePropertyById2(cx, obj, INT_TO_JSID(index), rval);
3744 JS_PUBLIC_API(JSBool)
3745 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name, jsval *rval)
3747 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3748 return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
3751 JS_PUBLIC_API(JSBool)
3752 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *rval)
3754 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3755 return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
3758 JS_PUBLIC_API(JSBool)
3759 JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id)
3761 jsval junk;
3762 return JS_DeletePropertyById2(cx, obj, id, &junk);
3765 JS_PUBLIC_API(JSBool)
3766 JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
3768 jsval junk;
3769 return JS_DeleteElement2(cx, obj, index, &junk);
3772 JS_PUBLIC_API(JSBool)
3773 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
3775 jsval junk;
3776 return JS_DeleteProperty2(cx, obj, name, &junk);
3779 JS_PUBLIC_API(void)
3780 JS_ClearScope(JSContext *cx, JSObject *obj)
3782 CHECK_REQUEST(cx);
3783 assertSameCompartment(cx, obj);
3785 JSFinalizeOp clearOp = obj->getOps()->clear;
3786 if (clearOp)
3787 clearOp(cx, obj);
3789 if (obj->isNative())
3790 js_ClearNative(cx, obj);
3792 /* Clear cached class objects on the global object. */
3793 if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) {
3794 int key;
3796 for (key = JSProto_Null; key < JSProto_LIMIT * 3; key++)
3797 JS_SetReservedSlot(cx, obj, key, JSVAL_VOID);
3800 js_InitRandom(cx);
3803 JS_PUBLIC_API(JSIdArray *)
3804 JS_Enumerate(JSContext *cx, JSObject *obj)
3806 CHECK_REQUEST(cx);
3807 assertSameCompartment(cx, obj);
3809 AutoIdVector props(cx);
3810 JSIdArray *ida;
3811 if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, props) || !VectorToIdArray(cx, props, &ida))
3812 return false;
3813 for (size_t n = 0; n < size_t(ida->length); ++n)
3814 JS_ASSERT(js_CheckForStringIndex(ida->vector[n]) == ida->vector[n]);
3815 return ida;
3819 * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
3820 * prop_iterator_class somehow...
3821 * + preserve the obj->enumerate API while optimizing the native object case
3822 * + native case here uses a JSScopeProperty *, but that iterates in reverse!
3823 * + so we make non-native match, by reverse-iterating after JS_Enumerating
3825 const uint32 JSSLOT_ITER_INDEX = JSSLOT_PRIVATE + 1;
3826 JS_STATIC_ASSERT(JSSLOT_ITER_INDEX < JS_INITIAL_NSLOTS);
3828 static void
3829 prop_iter_finalize(JSContext *cx, JSObject *obj)
3831 void *pdata = obj->getPrivate();
3832 if (!pdata)
3833 return;
3835 if (obj->fslots[JSSLOT_ITER_INDEX].toInt32() >= 0) {
3836 /* Non-native case: destroy the ida enumerated when obj was created. */
3837 JSIdArray *ida = (JSIdArray *) pdata;
3838 JS_DestroyIdArray(cx, ida);
3842 static void
3843 prop_iter_trace(JSTracer *trc, JSObject *obj)
3845 void *pdata = obj->getPrivate();
3846 if (!pdata)
3847 return;
3849 if (obj->fslots[JSSLOT_ITER_INDEX].toInt32() < 0) {
3850 /* Native case: just mark the next property to visit. */
3851 ((JSScopeProperty *) pdata)->trace(trc);
3852 } else {
3853 /* Non-native case: mark each id in the JSIdArray private. */
3854 JSIdArray *ida = (JSIdArray *) pdata;
3855 MarkIdRange(trc, ida->length, ida->vector, "prop iter");
3859 static Class prop_iter_class = {
3860 "PropertyIterator",
3861 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
3862 JSCLASS_MARK_IS_TRACE,
3863 PropertyStub, /* addProperty */
3864 PropertyStub, /* delProperty */
3865 PropertyStub, /* getProperty */
3866 PropertyStub, /* setProperty */
3867 EnumerateStub,
3868 ResolveStub,
3869 ConvertStub,
3870 prop_iter_finalize,
3871 NULL, /* reserved0 */
3872 NULL, /* checkAccess */
3873 NULL, /* call */
3874 NULL, /* construct */
3875 NULL, /* xdrObject */
3876 NULL, /* hasInstance */
3877 JS_CLASS_TRACE(prop_iter_trace)
3880 JS_PUBLIC_API(JSObject *)
3881 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
3883 JSObject *iterobj;
3884 JSScope *scope;
3885 void *pdata;
3886 jsint index;
3887 JSIdArray *ida;
3889 CHECK_REQUEST(cx);
3890 assertSameCompartment(cx, obj);
3891 iterobj = NewNonFunction<WithProto::Class>(cx, &prop_iter_class, NULL, obj);
3892 if (!iterobj)
3893 return NULL;
3895 if (obj->isNative()) {
3896 /* Native case: start with the last property in obj's own scope. */
3897 scope = obj->scope();
3898 pdata = scope->lastProperty();
3899 index = -1;
3900 } else {
3902 * Non-native case: enumerate a JSIdArray and keep it via private.
3904 * Note: we have to make sure that we root obj around the call to
3905 * JS_Enumerate to protect against multiple allocations under it.
3907 AutoObjectRooter tvr(cx, iterobj);
3908 ida = JS_Enumerate(cx, obj);
3909 if (!ida)
3910 return NULL;
3911 pdata = ida;
3912 index = ida->length;
3915 /* iterobj cannot escape to other threads here. */
3916 iterobj->setPrivate(pdata);
3917 iterobj->fslots[JSSLOT_ITER_INDEX].setInt32(index);
3918 return iterobj;
3921 JS_PUBLIC_API(JSBool)
3922 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
3924 jsint i;
3925 JSObject *obj;
3926 JSScopeProperty *sprop;
3927 JSIdArray *ida;
3929 CHECK_REQUEST(cx);
3930 assertSameCompartment(cx, iterobj);
3931 i = iterobj->fslots[JSSLOT_ITER_INDEX].toInt32();
3932 if (i < 0) {
3933 /* Native case: private data is a property tree node pointer. */
3934 obj = iterobj->getParent();
3935 JS_ASSERT(obj->isNative());
3936 sprop = (JSScopeProperty *) iterobj->getPrivate();
3939 * If the next property in the property tree ancestor line is
3940 * not enumerable, or it's an alias, skip it and keep on trying
3941 * to find an enumerable property that is still in scope.
3943 while (sprop && (!sprop->enumerable() || sprop->isAlias()))
3944 sprop = sprop->parent;
3946 if (!sprop) {
3947 *idp = JSID_VOID;
3948 } else {
3949 iterobj->setPrivate(sprop->parent);
3950 *idp = sprop->id;
3952 } else {
3953 /* Non-native case: use the ida enumerated when iterobj was created. */
3954 ida = (JSIdArray *) iterobj->getPrivate();
3955 JS_ASSERT(i <= ida->length);
3956 if (i == 0) {
3957 *idp = JSID_VOID;
3958 } else {
3959 *idp = ida->vector[--i];
3960 iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i));
3963 return JS_TRUE;
3966 JS_PUBLIC_API(JSBool)
3967 JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
3969 CHECK_REQUEST(cx);
3970 assertSameCompartment(cx, obj);
3971 return js_GetReservedSlot(cx, obj, index, Valueify(vp));
3974 JS_PUBLIC_API(JSBool)
3975 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
3977 CHECK_REQUEST(cx);
3978 assertSameCompartment(cx, obj, v);
3979 return js_SetReservedSlot(cx, obj, index, Valueify(v));
3982 JS_PUBLIC_API(JSObject *)
3983 JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
3985 CHECK_REQUEST(cx);
3986 /* NB: jsuint cast does ToUint32. */
3987 assertSameCompartment(cx, JSValueArray(vector, vector ? (jsuint)length : 0));
3988 return js_NewArrayObject(cx, (jsuint)length, Valueify(vector));
3991 JS_PUBLIC_API(JSBool)
3992 JS_IsArrayObject(JSContext *cx, JSObject *obj)
3994 assertSameCompartment(cx, obj);
3995 return obj->wrappedObject(cx)->isArray();
3998 JS_PUBLIC_API(JSBool)
3999 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
4001 CHECK_REQUEST(cx);
4002 assertSameCompartment(cx, obj);
4003 return js_GetLengthProperty(cx, obj, lengthp);
4006 JS_PUBLIC_API(JSBool)
4007 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
4009 CHECK_REQUEST(cx);
4010 assertSameCompartment(cx, obj);
4011 return js_SetLengthProperty(cx, obj, length);
4014 JS_PUBLIC_API(JSBool)
4015 JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
4017 CHECK_REQUEST(cx);
4018 assertSameCompartment(cx, obj);
4019 return js_HasLengthProperty(cx, obj, lengthp);
4022 JS_PUBLIC_API(JSBool)
4023 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
4024 jsval *vp, uintN *attrsp)
4026 CHECK_REQUEST(cx);
4027 assertSameCompartment(cx, obj, id);
4028 return CheckAccess(cx, obj, id, mode, Valueify(vp), attrsp);
4031 #ifdef JS_THREADSAFE
4032 JS_PUBLIC_API(jsrefcount)
4033 JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
4035 return JS_ATOMIC_INCREMENT(&principals->refcount);
4038 JS_PUBLIC_API(jsrefcount)
4039 JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
4041 jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
4042 if (rc == 0)
4043 principals->destroy(cx, principals);
4044 return rc;
4046 #endif
4048 JS_PUBLIC_API(JSSecurityCallbacks *)
4049 JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks)
4051 JSSecurityCallbacks *oldcallbacks;
4053 oldcallbacks = rt->securityCallbacks;
4054 rt->securityCallbacks = callbacks;
4055 return oldcallbacks;
4058 JS_PUBLIC_API(JSSecurityCallbacks *)
4059 JS_GetRuntimeSecurityCallbacks(JSRuntime *rt)
4061 return rt->securityCallbacks;
4064 JS_PUBLIC_API(JSSecurityCallbacks *)
4065 JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks)
4067 JSSecurityCallbacks *oldcallbacks;
4069 oldcallbacks = cx->securityCallbacks;
4070 cx->securityCallbacks = callbacks;
4071 return oldcallbacks;
4074 JS_PUBLIC_API(JSSecurityCallbacks *)
4075 JS_GetSecurityCallbacks(JSContext *cx)
4077 return cx->securityCallbacks
4078 ? cx->securityCallbacks
4079 : cx->runtime->securityCallbacks;
4082 JS_PUBLIC_API(JSFunction *)
4083 JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
4084 JSObject *parent, const char *name)
4086 JSAtom *atom;
4088 CHECK_REQUEST(cx);
4089 assertSameCompartment(cx, parent);
4091 if (!name) {
4092 atom = NULL;
4093 } else {
4094 atom = js_Atomize(cx, name, strlen(name), 0);
4095 if (!atom)
4096 return NULL;
4098 return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, atom);
4101 JS_PUBLIC_API(JSObject *)
4102 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
4104 CHECK_REQUEST(cx);
4105 assertSameCompartment(cx, parent); // XXX no funobj for now
4106 if (!parent) {
4107 if (cx->hasfp())
4108 parent = js_GetScopeChain(cx, cx->fp());
4109 if (!parent)
4110 parent = cx->globalObject;
4111 JS_ASSERT(parent);
4114 if (funobj->getClass() != &js_FunctionClass) {
4116 * We cannot clone this object, so fail (we used to return funobj, bad
4117 * idea, but we changed incompatibly to teach any abusers a lesson!).
4119 Value v = ObjectValue(*funobj);
4120 js_ReportIsNotFunction(cx, &v, 0);
4121 return NULL;
4124 JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
4125 JSObject *clone = CloneFunctionObject(cx, fun, parent);
4126 if (!clone)
4127 return NULL;
4130 * A flat closure carries its own environment, so why clone it? In case
4131 * someone wants to mutate its fixed slots or add ad-hoc properties. API
4132 * compatibility suggests we not return funobj and let callers mutate the
4133 * returned object at will.
4135 * But it's worse than that: API compatibility according to the test for
4136 * bug 300079 requires we get "upvars" from parent and its ancestors! So
4137 * we do that (grudgingly!). The scope chain ancestors are searched as if
4138 * they were activations, respecting the skip field in each upvar's cookie
4139 * but looking up the property by name instead of frame slot.
4141 if (FUN_FLAT_CLOSURE(fun)) {
4142 JS_ASSERT(funobj->dslots);
4143 if (!js_EnsureReservedSlots(cx, clone,
4144 fun->countInterpretedReservedSlots())) {
4145 return NULL;
4148 JSUpvarArray *uva = fun->u.i.script->upvars();
4149 JS_ASSERT(uva->length <= clone->dslots[-1].toPrivateUint32());
4151 void *mark = JS_ARENA_MARK(&cx->tempPool);
4152 jsuword *names = js_GetLocalNameArray(cx, fun, &cx->tempPool);
4153 if (!names)
4154 return NULL;
4156 uint32 i = 0, n = uva->length;
4157 for (; i < n; i++) {
4158 JSObject *obj = parent;
4159 int skip = uva->vector[i].level();
4160 while (--skip > 0) {
4161 if (!obj) {
4162 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4163 JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
4164 goto break2;
4166 obj = obj->getParent();
4169 JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(names[i]);
4170 if (!obj->getProperty(cx, ATOM_TO_JSID(atom), &clone->dslots[i]))
4171 break;
4174 break2:
4175 JS_ARENA_RELEASE(&cx->tempPool, mark);
4176 if (i < n)
4177 return NULL;
4180 return clone;
4183 JS_PUBLIC_API(JSObject *)
4184 JS_GetFunctionObject(JSFunction *fun)
4186 return FUN_OBJECT(fun);
4189 JS_PUBLIC_API(const char *)
4190 JS_GetFunctionName(JSFunction *fun)
4192 return fun->atom
4193 ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
4194 : js_anonymous_str;
4197 JS_PUBLIC_API(JSString *)
4198 JS_GetFunctionId(JSFunction *fun)
4200 return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
4203 JS_PUBLIC_API(uintN)
4204 JS_GetFunctionFlags(JSFunction *fun)
4206 return fun->flags;
4209 JS_PUBLIC_API(uint16)
4210 JS_GetFunctionArity(JSFunction *fun)
4212 return fun->nargs;
4215 JS_PUBLIC_API(JSBool)
4216 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
4218 return obj->getClass() == &js_FunctionClass;
4221 static JSBool
4222 js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp)
4224 JSFunctionSpec *fs;
4225 JSObject *tmp;
4226 FastNative native;
4228 fs = (JSFunctionSpec *) vp->toObject().getReservedSlot(0).toPrivate();
4229 JS_ASSERT((~fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) == 0);
4231 if (argc < 1) {
4232 js_ReportMissingArg(cx, *vp, 0);
4233 return JS_FALSE;
4236 if (vp[2].isPrimitive()) {
4238 * Make sure that this is an object or null, as required by the generic
4239 * functions.
4241 if (!js_ValueToObjectOrNull(cx, vp[2], &tmp))
4242 return JS_FALSE;
4243 vp[2].setObjectOrNull(tmp);
4247 * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
4248 * which is almost always the class constructor object, e.g. Array. Then
4249 * call the corresponding prototype native method with our first argument
4250 * passed as |this|.
4252 memmove(vp + 1, vp + 2, argc * sizeof(jsval));
4255 * Follow Function.prototype.apply and .call by using the global object as
4256 * the 'this' param if no args.
4258 if (!ComputeThisFromArgv(cx, vp + 2))
4259 return JS_FALSE;
4261 /* Clear the last parameter in case too few arguments were passed. */
4262 vp[2 + --argc].setUndefined();
4264 native =
4265 #ifdef JS_TRACER
4266 (fs->flags & JSFUN_TRCINFO)
4267 ? (FastNative) JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native
4269 #endif
4270 (FastNative) fs->call;
4271 return native(cx, argc, vp);
4274 static JSBool
4275 js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
4276 uintN argc, Value *argv, Value *rval)
4278 JSFunctionSpec *fs;
4279 JSObject *tmp;
4281 fs = (JSFunctionSpec *) argv[-2].toObject().getReservedSlot(0).toPrivate();
4282 JS_ASSERT((fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) ==
4283 JSFUN_GENERIC_NATIVE);
4285 if (argc < 1) {
4286 js_ReportMissingArg(cx, *(argv - 2), 0);
4287 return JS_FALSE;
4290 if (argv[0].isPrimitive()) {
4292 * Make sure that this is an object or null, as required by the generic
4293 * functions.
4295 if (!js_ValueToObjectOrNull(cx, argv[0], &tmp))
4296 return JS_FALSE;
4297 argv[0].setObjectOrNull(tmp);
4301 * Copy all actual (argc) arguments down over our |this| parameter,
4302 * argv[-1], which is almost always the class constructor object, e.g.
4303 * Array. Then call the corresponding prototype native method with our
4304 * first argument passed as |this|.
4306 memmove(argv - 1, argv, argc * sizeof(jsval));
4309 * Follow Function.prototype.apply and .call by using the global object as
4310 * the 'this' param if no args.
4312 if (!ComputeThisFromArgv(cx, argv))
4313 return JS_FALSE;
4314 js_GetTopStackFrame(cx)->setThisValue(argv[-1]);
4315 JS_ASSERT(cx->fp()->argv == argv);
4317 /* Clear the last parameter in case too few arguments were passed. */
4318 argv[--argc].setUndefined();
4320 return fs->call(cx, &argv[-1].toObject(), argc, Jsvalify(argv), Jsvalify(rval));
4323 JS_PUBLIC_API(JSBool)
4324 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
4326 uintN flags;
4327 JSObject *ctor;
4328 JSFunction *fun;
4330 CHECK_REQUEST(cx);
4331 assertSameCompartment(cx, obj);
4332 ctor = NULL;
4333 for (; fs->name; fs++) {
4334 flags = fs->flags;
4337 * Define a generic arity N+1 static method for the arity N prototype
4338 * method if flags contains JSFUN_GENERIC_NATIVE.
4340 if (flags & JSFUN_GENERIC_NATIVE) {
4341 if (!ctor) {
4342 ctor = JS_GetConstructor(cx, obj);
4343 if (!ctor)
4344 return JS_FALSE;
4347 flags &= ~JSFUN_GENERIC_NATIVE;
4348 fun = JS_DefineFunction(cx, ctor, fs->name,
4349 (flags & JSFUN_FAST_NATIVE)
4350 ? (JSNative) js_generic_fast_native_method_dispatcher
4351 : Jsvalify(js_generic_native_method_dispatcher),
4352 fs->nargs + 1,
4353 flags & ~JSFUN_TRCINFO);
4354 if (!fun)
4355 return JS_FALSE;
4356 fun->u.n.extra = (uint16)fs->extra;
4359 * As jsapi.h notes, fs must point to storage that lives as long
4360 * as fun->object lives.
4362 Value priv = PrivateValue(fs);
4363 if (!js_SetReservedSlot(cx, FUN_OBJECT(fun), 0, priv))
4364 return JS_FALSE;
4367 JS_ASSERT(!(flags & JSFUN_FAST_NATIVE) ||
4368 (uint16)(fs->extra >> 16) <= fs->nargs);
4369 fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
4370 if (!fun)
4371 return JS_FALSE;
4372 fun->u.n.extra = (uint16)fs->extra;
4374 return JS_TRUE;
4377 JS_PUBLIC_API(JSFunction *)
4378 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
4379 uintN nargs, uintN attrs)
4381 CHECK_REQUEST(cx);
4382 assertSameCompartment(cx, obj);
4383 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
4384 return atom ? js_DefineFunction(cx, obj, atom, Valueify(call), nargs, attrs) : NULL;
4387 JS_PUBLIC_API(JSFunction *)
4388 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
4389 const jschar *name, size_t namelen, JSNative call,
4390 uintN nargs, uintN attrs)
4392 CHECK_REQUEST(cx);
4393 assertSameCompartment(cx, obj);
4394 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
4395 return atom ? js_DefineFunction(cx, obj, atom, Valueify(call), nargs, attrs) : NULL;
4398 inline static void
4399 LAST_FRAME_EXCEPTION_CHECK(JSContext *cx, bool result)
4401 if (!result && !(cx->options & JSOPTION_DONT_REPORT_UNCAUGHT))
4402 js_ReportUncaughtException(cx);
4405 inline static void
4406 LAST_FRAME_CHECKS(JSContext *cx, bool result)
4408 if (!JS_IsRunning(cx)) {
4409 LAST_FRAME_EXCEPTION_CHECK(cx, result);
4413 inline static uint32
4414 JS_OPTIONS_TO_TCFLAGS(JSContext *cx)
4416 return ((cx->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) |
4417 ((cx->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0);
4420 JS_PUBLIC_API(JSScript *)
4421 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4422 const jschar *chars, size_t length,
4423 const char *filename, uintN lineno)
4425 CHECK_REQUEST(cx);
4426 assertSameCompartment(cx, obj, principals);
4428 uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4429 JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
4430 chars, length, NULL, filename, lineno);
4431 if (script && !js_NewScriptObject(cx, script)) {
4432 js_DestroyScript(cx, script);
4433 script = NULL;
4435 LAST_FRAME_CHECKS(cx, script);
4436 return script;
4439 JS_PUBLIC_API(JSScript *)
4440 JS_CompileUCScript(JSContext *cx, JSObject *obj, const jschar *chars, size_t length,
4441 const char *filename, uintN lineno)
4443 return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno);
4446 JS_PUBLIC_API(JSScript *)
4447 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
4448 JSPrincipals *principals,
4449 const char *bytes, size_t length,
4450 const char *filename, uintN lineno)
4452 CHECK_REQUEST(cx);
4454 jschar *chars = js_InflateString(cx, bytes, &length);
4455 if (!chars)
4456 return NULL;
4457 JSScript *script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno);
4458 cx->free(chars);
4459 return script;
4462 JS_PUBLIC_API(JSScript *)
4463 JS_CompileScript(JSContext *cx, JSObject *obj, const char *bytes, size_t length,
4464 const char *filename, uintN lineno)
4466 return JS_CompileScriptForPrincipals(cx, obj, NULL, bytes, length, filename, lineno);
4469 JS_PUBLIC_API(JSBool)
4470 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, const char *bytes, size_t length)
4472 jschar *chars;
4473 JSBool result;
4474 JSExceptionState *exnState;
4475 JSErrorReporter older;
4477 CHECK_REQUEST(cx);
4478 assertSameCompartment(cx, obj);
4479 chars = js_InflateString(cx, bytes, &length);
4480 if (!chars)
4481 return JS_TRUE;
4484 * Return true on any out-of-memory error, so our caller doesn't try to
4485 * collect more buffered source.
4487 result = JS_TRUE;
4488 exnState = JS_SaveExceptionState(cx);
4490 Parser parser(cx);
4491 if (parser.init(chars, length, NULL, NULL, 1)) {
4492 older = JS_SetErrorReporter(cx, NULL);
4493 if (!parser.parse(obj) &&
4494 parser.tokenStream.isUnexpectedEOF()) {
4496 * We ran into an error. If it was because we ran out of
4497 * source, we return false so our caller knows to try to
4498 * collect more buffered source.
4500 result = JS_FALSE;
4502 JS_SetErrorReporter(cx, older);
4505 cx->free(chars);
4506 JS_RestoreExceptionState(cx, exnState);
4507 return result;
4510 JS_PUBLIC_API(JSScript *)
4511 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
4513 FILE *fp;
4514 uint32 tcflags;
4515 JSScript *script;
4517 CHECK_REQUEST(cx);
4518 assertSameCompartment(cx, obj);
4519 if (!filename || strcmp(filename, "-") == 0) {
4520 fp = stdin;
4521 } else {
4522 fp = fopen(filename, "r");
4523 if (!fp) {
4524 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
4525 filename, "No such file or directory");
4526 return NULL;
4530 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4531 script = Compiler::compileScript(cx, obj, NULL, NULL, tcflags,
4532 NULL, 0, fp, filename, 1);
4533 if (fp != stdin)
4534 fclose(fp);
4535 if (script && !js_NewScriptObject(cx, script)) {
4536 js_DestroyScript(cx, script);
4537 script = NULL;
4539 LAST_FRAME_CHECKS(cx, script);
4540 return script;
4543 JS_PUBLIC_API(JSScript *)
4544 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *filename, FILE *file,
4545 JSPrincipals *principals)
4547 uint32 tcflags;
4548 JSScript *script;
4550 CHECK_REQUEST(cx);
4551 assertSameCompartment(cx, obj, principals);
4552 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4553 script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
4554 NULL, 0, file, filename, 1);
4555 if (script && !js_NewScriptObject(cx, script)) {
4556 js_DestroyScript(cx, script);
4557 script = NULL;
4559 LAST_FRAME_CHECKS(cx, script);
4560 return script;
4563 JS_PUBLIC_API(JSScript *)
4564 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *file)
4566 return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
4569 JS_PUBLIC_API(JSObject *)
4570 JS_NewScriptObject(JSContext *cx, JSScript *script)
4572 CHECK_REQUEST(cx);
4573 assertSameCompartment(cx, script);
4574 if (!script)
4575 return NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
4578 * This function should only ever be applied to JSScripts that had
4579 * script objects allocated for them when they were created, as
4580 * described in the comment for JSScript::u.object.
4582 JS_ASSERT(script->u.object);
4583 return script->u.object;
4586 JS_PUBLIC_API(JSObject *)
4587 JS_GetScriptObject(JSScript *script)
4590 * This function should only ever be applied to JSScripts that had
4591 * script objects allocated for them when they were created, as
4592 * described in the comment for JSScript::u.object.
4594 JS_ASSERT(script->u.object);
4595 return script->u.object;
4598 JS_PUBLIC_API(void)
4599 JS_DestroyScript(JSContext *cx, JSScript *script)
4601 CHECK_REQUEST(cx);
4604 * Originally, JSScript lifetimes were managed explicitly, and this function
4605 * was used to free a JSScript. Now, this function does nothing, and the
4606 * garbage collector manages JSScripts; you must root the JSScript's script
4607 * object (obtained via JS_GetScriptObject) to keep it alive.
4609 * However, since the script objects have taken over this responsibility, it
4610 * follows that every script passed here must have a script object.
4612 JS_ASSERT(script->u.object);
4615 JS_PUBLIC_API(JSFunction *)
4616 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
4617 JSPrincipals *principals, const char *name,
4618 uintN nargs, const char **argnames,
4619 const jschar *chars, size_t length,
4620 const char *filename, uintN lineno)
4622 JSFunction *fun;
4623 JSAtom *funAtom, *argAtom;
4624 uintN i;
4626 CHECK_REQUEST(cx);
4627 assertSameCompartment(cx, obj, principals);
4628 if (!name) {
4629 funAtom = NULL;
4630 } else {
4631 funAtom = js_Atomize(cx, name, strlen(name), 0);
4632 if (!funAtom) {
4633 fun = NULL;
4634 goto out2;
4637 fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
4638 if (!fun)
4639 goto out2;
4642 AutoObjectRooter tvr(cx, FUN_OBJECT(fun));
4643 MUST_FLOW_THROUGH("out");
4645 for (i = 0; i < nargs; i++) {
4646 argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
4647 if (!argAtom) {
4648 fun = NULL;
4649 goto out2;
4651 if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) {
4652 fun = NULL;
4653 goto out2;
4657 if (!Compiler::compileFunctionBody(cx, fun, principals,
4658 chars, length, filename, lineno)) {
4659 fun = NULL;
4660 goto out2;
4663 if (obj && funAtom &&
4664 !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), ObjectValue(*fun),
4665 NULL, NULL, JSPROP_ENUMERATE)) {
4666 fun = NULL;
4669 #ifdef JS_SCOPE_DEPTH_METER
4670 if (fun && obj) {
4671 JSObject *pobj = obj;
4672 uintN depth = 1;
4674 while ((pobj = pobj->getParent()) != NULL)
4675 ++depth;
4676 JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
4678 #endif
4681 out2:
4682 LAST_FRAME_CHECKS(cx, fun);
4683 return fun;
4686 JS_PUBLIC_API(JSFunction *)
4687 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
4688 uintN nargs, const char **argnames,
4689 const jschar *chars, size_t length,
4690 const char *filename, uintN lineno)
4692 return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames,
4693 chars, length, filename, lineno);
4696 JS_PUBLIC_API(JSFunction *)
4697 JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
4698 JSPrincipals *principals, const char *name,
4699 uintN nargs, const char **argnames,
4700 const char *bytes, size_t length,
4701 const char *filename, uintN lineno)
4703 jschar *chars = js_InflateString(cx, bytes, &length);
4704 if (!chars)
4705 return NULL;
4706 JSFunction *fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
4707 nargs, argnames, chars, length,
4708 filename, lineno);
4709 cx->free(chars);
4710 return fun;
4713 JS_PUBLIC_API(JSFunction *)
4714 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
4715 uintN nargs, const char **argnames,
4716 const char *bytes, size_t length,
4717 const char *filename, uintN lineno)
4719 return JS_CompileFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames, bytes, length,
4720 filename, lineno);
4723 JS_PUBLIC_API(JSString *)
4724 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, uintN indent)
4726 JSPrinter *jp;
4727 JSString *str;
4729 CHECK_REQUEST(cx);
4730 assertSameCompartment(cx, script);
4731 jp = js_NewPrinter(cx, name, NULL,
4732 indent & ~JS_DONT_PRETTY_PRINT,
4733 !(indent & JS_DONT_PRETTY_PRINT),
4734 false, false);
4735 if (!jp)
4736 return NULL;
4737 if (js_DecompileScript(jp, script))
4738 str = js_GetPrinterOutput(jp);
4739 else
4740 str = NULL;
4741 js_DestroyPrinter(jp);
4742 return str;
4745 JS_PUBLIC_API(JSString *)
4746 JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
4748 CHECK_REQUEST(cx);
4749 assertSameCompartment(cx, fun);
4750 return js_DecompileToString(cx, "JS_DecompileFunction", fun,
4751 indent & ~JS_DONT_PRETTY_PRINT,
4752 !(indent & JS_DONT_PRETTY_PRINT),
4753 false, false, js_DecompileFunction);
4756 JS_PUBLIC_API(JSString *)
4757 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
4759 CHECK_REQUEST(cx);
4760 assertSameCompartment(cx, fun);
4761 return js_DecompileToString(cx, "JS_DecompileFunctionBody", fun,
4762 indent & ~JS_DONT_PRETTY_PRINT,
4763 !(indent & JS_DONT_PRETTY_PRINT),
4764 false, false, js_DecompileFunctionBody);
4767 JS_PUBLIC_API(JSBool)
4768 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
4770 JSBool ok;
4772 CHECK_REQUEST(cx);
4773 assertSameCompartment(cx, obj, script);
4774 /* This should receive only scripts handed out via the JSAPI. */
4775 JS_ASSERT(script == JSScript::emptyScript() || script->u.object);
4776 ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
4777 LAST_FRAME_CHECKS(cx, ok);
4778 return ok;
4781 JS_PUBLIC_API(JSBool)
4782 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
4783 JSPrincipals *principals,
4784 const jschar *chars, uintN length,
4785 const char *filename, uintN lineno,
4786 jsval *rval)
4788 JSScript *script;
4789 JSBool ok;
4791 CHECK_REQUEST(cx);
4792 script = Compiler::compileScript(cx, obj, NULL, principals,
4793 !rval
4794 ? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
4795 : TCF_COMPILE_N_GO,
4796 chars, length, NULL, filename, lineno);
4797 if (!script) {
4798 LAST_FRAME_CHECKS(cx, script);
4799 return JS_FALSE;
4801 ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
4802 LAST_FRAME_CHECKS(cx, ok);
4803 js_DestroyScript(cx, script);
4804 return ok;
4807 JS_PUBLIC_API(JSBool)
4808 JS_EvaluateUCScript(JSContext *cx, JSObject *obj, const jschar *chars, uintN length,
4809 const char *filename, uintN lineno, jsval *rval)
4811 return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno, rval);
4814 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
4815 JS_PUBLIC_API(JSBool)
4816 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4817 const char *bytes, uintN nbytes,
4818 const char *filename, uintN lineno, jsval *rval)
4820 size_t length = nbytes;
4821 jschar *chars = js_InflateString(cx, bytes, &length);
4822 if (!chars)
4823 return JS_FALSE;
4824 JSBool ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
4825 filename, lineno, rval);
4826 cx->free(chars);
4827 return ok;
4830 JS_PUBLIC_API(JSBool)
4831 JS_EvaluateScript(JSContext *cx, JSObject *obj, const char *bytes, uintN nbytes,
4832 const char *filename, uintN lineno, jsval *rval)
4834 return JS_EvaluateScriptForPrincipals(cx, obj, NULL, bytes, nbytes, filename, lineno, rval);
4837 JS_PUBLIC_API(JSBool)
4838 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, jsval *argv,
4839 jsval *rval)
4841 JSBool ok;
4843 CHECK_REQUEST(cx);
4844 assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc));
4845 ok = InternalCall(cx, obj, ObjectValue(*fun), argc, Valueify(argv), Valueify(rval));
4846 LAST_FRAME_CHECKS(cx, ok);
4847 return ok;
4850 JS_PUBLIC_API(JSBool)
4851 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, jsval *argv,
4852 jsval *rval)
4854 CHECK_REQUEST(cx);
4855 assertSameCompartment(cx, obj, JSValueArray(argv, argc));
4857 AutoValueRooter tvr(cx);
4858 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
4859 JSBool ok = atom &&
4860 js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, tvr.addr()) &&
4861 InternalCall(cx, obj, tvr.value(), argc, Valueify(argv), Valueify(rval));
4862 LAST_FRAME_CHECKS(cx, ok);
4863 return ok;
4866 JS_PUBLIC_API(JSBool)
4867 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, jsval *argv,
4868 jsval *rval)
4870 JSBool ok;
4872 CHECK_REQUEST(cx);
4873 assertSameCompartment(cx, obj, fval, JSValueArray(argv, argc));
4874 ok = InternalCall(cx, obj, Valueify(fval), argc, Valueify(argv), Valueify(rval));
4875 LAST_FRAME_CHECKS(cx, ok);
4876 return ok;
4879 JS_PUBLIC_API(JSObject *)
4880 JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv)
4882 CHECK_REQUEST(cx);
4883 assertSameCompartment(cx, ctor, JSValueArray(argv, argc));
4885 // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
4886 // is not a simple variation of JSOP_CALL. We have to determine what class
4887 // of object to create, create it, and clamp the return value to an object,
4888 // among other details. js_InvokeConstructor does the hard work.
4889 InvokeArgsGuard args;
4890 if (!cx->stack().pushInvokeArgs(cx, argc, args))
4891 return NULL;
4893 args.callee().setObject(*ctor);
4894 args.thisv().setNull();
4895 memcpy(args.argv(), argv, argc * sizeof(jsval));
4897 bool ok = InvokeConstructor(cx, args);
4898 JSObject *obj = ok ? args.rval().toObjectOrNull() : NULL;
4900 LAST_FRAME_CHECKS(cx, ok);
4901 return obj;
4904 JS_PUBLIC_API(JSOperationCallback)
4905 JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback)
4907 #ifdef JS_THREADSAFE
4908 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
4909 #endif
4910 JSOperationCallback old = cx->operationCallback;
4911 cx->operationCallback = callback;
4912 return old;
4915 JS_PUBLIC_API(JSOperationCallback)
4916 JS_GetOperationCallback(JSContext *cx)
4918 return cx->operationCallback;
4921 JS_PUBLIC_API(void)
4922 JS_TriggerOperationCallback(JSContext *cx)
4925 * We allow for cx to come from another thread. Thus we must deal with
4926 * possible JS_ClearContextThread calls when accessing cx->thread. But we
4927 * assume that the calling thread is in a request so JSThread cannot be
4928 * GC-ed.
4930 JSThreadData *td;
4931 #ifdef JS_THREADSAFE
4932 JSThread *thread = cx->thread;
4933 if (!thread)
4934 return;
4935 td = &thread->data;
4936 #else
4937 td = JS_THREAD_DATA(cx);
4938 #endif
4939 td->triggerOperationCallback();
4942 JS_PUBLIC_API(void)
4943 JS_TriggerAllOperationCallbacks(JSRuntime *rt)
4945 js_TriggerAllOperationCallbacks(rt, JS_FALSE);
4948 JS_PUBLIC_API(JSBool)
4949 JS_IsRunning(JSContext *cx)
4952 * The use of cx->fp below is safe. Rationale: Here we don't care if the
4953 * interpreter state is stale. We just want to know if there *is* any
4954 * interpreter state.
4956 VOUCH_DOES_NOT_REQUIRE_STACK();
4958 #ifdef JS_TRACER
4959 JS_ASSERT_IF(JS_TRACE_MONITOR(cx).tracecx == cx, cx->hasfp());
4960 #endif
4961 JSStackFrame *fp = cx->maybefp();
4962 while (fp && fp->isDummyFrame())
4963 fp = fp->down;
4964 return fp != NULL;
4967 JS_PUBLIC_API(JSBool)
4968 JS_IsConstructing(JSContext *cx)
4970 return cx->isConstructing();
4973 JS_PUBLIC_API(JSStackFrame *)
4974 JS_SaveFrameChain(JSContext *cx)
4976 CHECK_REQUEST(cx);
4977 JSStackFrame *fp = js_GetTopStackFrame(cx);
4978 if (!fp)
4979 return NULL;
4980 cx->saveActiveSegment();
4981 return fp;
4984 JS_PUBLIC_API(void)
4985 JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
4987 CHECK_REQUEST(cx);
4988 JS_ASSERT_NOT_ON_TRACE(cx);
4989 JS_ASSERT(!cx->hasfp());
4990 if (!fp)
4991 return;
4992 cx->restoreSegment();
4995 /************************************************************************/
4997 JS_PUBLIC_API(JSString *)
4998 JS_NewString(JSContext *cx, char *bytes, size_t nbytes)
5000 size_t length = nbytes;
5001 jschar *chars;
5002 JSString *str;
5004 CHECK_REQUEST(cx);
5006 /* Make a UTF-16 vector from the 8-bit char codes in bytes. */
5007 chars = js_InflateString(cx, bytes, &length);
5008 if (!chars)
5009 return NULL;
5011 /* Free chars (but not bytes, which caller frees on error) if we fail. */
5012 str = js_NewString(cx, chars, length);
5013 if (!str) {
5014 cx->free(chars);
5015 return NULL;
5018 /* Hand off bytes to the deflated string cache, if possible. */
5019 if (!cx->runtime->deflatedStringCache->setBytes(cx, str, bytes))
5020 cx->free(bytes);
5021 return str;
5024 JS_PUBLIC_API(JSString *)
5025 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
5027 jschar *js;
5028 JSString *str;
5030 CHECK_REQUEST(cx);
5031 js = js_InflateString(cx, s, &n);
5032 if (!js)
5033 return NULL;
5034 str = js_NewString(cx, js, n);
5035 if (!str)
5036 cx->free(js);
5037 return str;
5040 JS_PUBLIC_API(JSString *)
5041 JS_NewStringCopyZ(JSContext *cx, const char *s)
5043 size_t n;
5044 jschar *js;
5045 JSString *str;
5047 CHECK_REQUEST(cx);
5048 if (!s)
5049 return cx->runtime->emptyString;
5050 n = strlen(s);
5051 js = js_InflateString(cx, s, &n);
5052 if (!js)
5053 return NULL;
5054 str = js_NewString(cx, js, n);
5055 if (!str)
5056 cx->free(js);
5057 return str;
5060 JS_PUBLIC_API(JSBool)
5061 JS_StringHasBeenInterned(JSString *str)
5063 return str->isAtomized();
5066 JS_PUBLIC_API(JSString *)
5067 JS_InternString(JSContext *cx, const char *s)
5069 JSAtom *atom;
5071 CHECK_REQUEST(cx);
5072 atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
5073 if (!atom)
5074 return NULL;
5075 return ATOM_TO_STRING(atom);
5078 JS_PUBLIC_API(JSString *)
5079 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
5081 CHECK_REQUEST(cx);
5082 return js_NewString(cx, chars, length);
5085 JS_PUBLIC_API(JSString *)
5086 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
5088 CHECK_REQUEST(cx);
5089 return js_NewStringCopyN(cx, s, n);
5092 JS_PUBLIC_API(JSString *)
5093 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
5095 CHECK_REQUEST(cx);
5096 if (!s)
5097 return cx->runtime->emptyString;
5098 return js_NewStringCopyZ(cx, s);
5101 JS_PUBLIC_API(JSString *)
5102 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
5104 JSAtom *atom;
5106 CHECK_REQUEST(cx);
5107 atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
5108 if (!atom)
5109 return NULL;
5110 return ATOM_TO_STRING(atom);
5113 JS_PUBLIC_API(JSString *)
5114 JS_InternUCString(JSContext *cx, const jschar *s)
5116 return JS_InternUCStringN(cx, s, js_strlen(s));
5119 JS_PUBLIC_API(char *)
5120 JS_GetStringBytes(JSString *str)
5122 const char *bytes;
5124 bytes = js_GetStringBytes(NULL, str);
5125 return (char *)(bytes ? bytes : "");
5128 JS_PUBLIC_API(jschar *)
5129 JS_GetStringChars(JSString *str)
5131 size_t n, size;
5132 jschar *s;
5134 str->ensureNotRope();
5137 * API botch (again, shades of JS_GetStringBytes): we have no cx to report
5138 * out-of-memory when undepending strings, so we replace JSString::undepend
5139 * with explicit malloc call and ignore its errors.
5141 * If we fail to convert a dependent string into an independent one, our
5142 * caller will not be guaranteed a \u0000 terminator as a backstop. This
5143 * may break some clients who already misbehave on embedded NULs.
5145 * The gain of dependent strings, which cure quadratic and cubic growth
5146 * rate bugs in string concatenation, is worth this slight loss in API
5147 * compatibility.
5149 if (str->isDependent()) {
5150 n = str->dependentLength();
5151 size = (n + 1) * sizeof(jschar);
5152 s = (jschar *) js_malloc(size);
5153 if (s) {
5154 memcpy(s, str->dependentChars(), n * sizeof *s);
5155 s[n] = 0;
5156 str->initFlat(s, n);
5157 } else {
5158 s = str->dependentChars();
5160 } else {
5161 str->flatClearMutable();
5162 s = str->flatChars();
5164 return s;
5167 JS_PUBLIC_API(size_t)
5168 JS_GetStringLength(JSString *str)
5170 return str->length();
5173 JS_PUBLIC_API(const char *)
5174 JS_GetStringBytesZ(JSContext *cx, JSString *str)
5176 assertSameCompartment(cx, str);
5177 return js_GetStringBytes(cx, str);
5180 JS_PUBLIC_API(const jschar *)
5181 JS_GetStringCharsZ(JSContext *cx, JSString *str)
5183 assertSameCompartment(cx, str);
5184 return str->undepend(cx);
5187 JS_PUBLIC_API(intN)
5188 JS_CompareStrings(JSString *str1, JSString *str2)
5190 return js_CompareStrings(str1, str2);
5193 JS_PUBLIC_API(JSString *)
5194 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
5196 CHECK_REQUEST(cx);
5197 return js_NewString(cx, chars, length);
5200 JS_PUBLIC_API(JSString *)
5201 JS_NewDependentString(JSContext *cx, JSString *str, size_t start, size_t length)
5203 CHECK_REQUEST(cx);
5204 return js_NewDependentString(cx, str, start, length);
5207 JS_PUBLIC_API(JSString *)
5208 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
5210 CHECK_REQUEST(cx);
5211 return js_ConcatStrings(cx, left, right);
5214 JS_PUBLIC_API(const jschar *)
5215 JS_UndependString(JSContext *cx, JSString *str)
5217 CHECK_REQUEST(cx);
5218 return str->undepend(cx);
5221 JS_PUBLIC_API(JSBool)
5222 JS_MakeStringImmutable(JSContext *cx, JSString *str)
5224 CHECK_REQUEST(cx);
5225 return js_MakeStringImmutable(cx, str);
5228 JS_PUBLIC_API(JSBool)
5229 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, size_t *dstlenp)
5231 size_t n;
5233 if (!dst) {
5234 n = js_GetDeflatedStringLength(cx, src, srclen);
5235 if (n == (size_t)-1) {
5236 *dstlenp = 0;
5237 return JS_FALSE;
5239 *dstlenp = n;
5240 return JS_TRUE;
5243 return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5246 JS_PUBLIC_API(JSBool)
5247 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp)
5249 return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5252 JS_PUBLIC_API(char *)
5253 JS_EncodeString(JSContext *cx, JSString *str)
5255 return js_DeflateString(cx, str->chars(), str->length());
5258 JS_PUBLIC_API(JSBool)
5259 JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
5260 JSONWriteCallback callback, void *data)
5262 CHECK_REQUEST(cx);
5263 assertSameCompartment(cx, replacer, space);
5264 JSCharBuffer cb(cx);
5265 if (!js_Stringify(cx, Valueify(vp), replacer, Valueify(space), cb))
5266 return false;
5267 return callback(cb.begin(), cb.length(), data);
5270 JS_PUBLIC_API(JSBool)
5271 JS_TryJSON(JSContext *cx, jsval *vp)
5273 CHECK_REQUEST(cx);
5274 assertSameCompartment(cx, *vp);
5275 return js_TryJSON(cx, Valueify(vp));
5278 JS_PUBLIC_API(JSONParser *)
5279 JS_BeginJSONParse(JSContext *cx, jsval *vp)
5281 CHECK_REQUEST(cx);
5282 return js_BeginJSONParse(cx, Valueify(vp));
5285 JS_PUBLIC_API(JSBool)
5286 JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len)
5288 CHECK_REQUEST(cx);
5289 return js_ConsumeJSONText(cx, jp, data, len);
5292 JS_PUBLIC_API(JSBool)
5293 JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver)
5295 CHECK_REQUEST(cx);
5296 assertSameCompartment(cx, reviver);
5297 return js_FinishJSONParse(cx, jp, Valueify(reviver));
5301 * The following determines whether C Strings are to be treated as UTF-8
5302 * or ISO-8859-1. For correct operation, it must be set prior to the
5303 * first call to JS_NewRuntime.
5305 #ifndef JS_C_STRINGS_ARE_UTF8
5306 JSBool js_CStringsAreUTF8 = JS_FALSE;
5307 #endif
5309 JS_PUBLIC_API(JSBool)
5310 JS_CStringsAreUTF8()
5312 return js_CStringsAreUTF8;
5315 JS_PUBLIC_API(void)
5316 JS_SetCStringsAreUTF8()
5318 JS_ASSERT(!js_NewRuntimeWasCalled);
5320 #ifndef JS_C_STRINGS_ARE_UTF8
5321 js_CStringsAreUTF8 = JS_TRUE;
5322 #endif
5325 /************************************************************************/
5327 JS_PUBLIC_API(void)
5328 JS_ReportError(JSContext *cx, const char *format, ...)
5330 va_list ap;
5332 va_start(ap, format);
5333 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
5334 va_end(ap);
5337 JS_PUBLIC_API(void)
5338 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
5339 void *userRef, const uintN errorNumber, ...)
5341 va_list ap;
5343 va_start(ap, errorNumber);
5344 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5345 errorNumber, JS_TRUE, ap);
5346 va_end(ap);
5349 JS_PUBLIC_API(void)
5350 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
5351 void *userRef, const uintN errorNumber, ...)
5353 va_list ap;
5355 va_start(ap, errorNumber);
5356 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5357 errorNumber, JS_FALSE, ap);
5358 va_end(ap);
5361 JS_PUBLIC_API(JSBool)
5362 JS_ReportWarning(JSContext *cx, const char *format, ...)
5364 va_list ap;
5365 JSBool ok;
5367 va_start(ap, format);
5368 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
5369 va_end(ap);
5370 return ok;
5373 JS_PUBLIC_API(JSBool)
5374 JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
5375 JSErrorCallback errorCallback, void *userRef,
5376 const uintN errorNumber, ...)
5378 va_list ap;
5379 JSBool ok;
5381 va_start(ap, errorNumber);
5382 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5383 errorNumber, JS_TRUE, ap);
5384 va_end(ap);
5385 return ok;
5388 JS_PUBLIC_API(JSBool)
5389 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
5390 JSErrorCallback errorCallback, void *userRef,
5391 const uintN errorNumber, ...)
5393 va_list ap;
5394 JSBool ok;
5396 va_start(ap, errorNumber);
5397 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5398 errorNumber, JS_FALSE, ap);
5399 va_end(ap);
5400 return ok;
5403 JS_PUBLIC_API(void)
5404 JS_ReportOutOfMemory(JSContext *cx)
5406 js_ReportOutOfMemory(cx);
5409 JS_PUBLIC_API(void)
5410 JS_ReportAllocationOverflow(JSContext *cx)
5412 js_ReportAllocationOverflow(cx);
5415 JS_PUBLIC_API(JSErrorReporter)
5416 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
5418 JSErrorReporter older;
5420 older = cx->errorReporter;
5421 cx->errorReporter = er;
5422 return older;
5425 /************************************************************************/
5428 * Regular Expressions.
5430 JS_PUBLIC_API(JSObject *)
5431 JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags)
5433 CHECK_REQUEST(cx);
5434 jschar *chars = js_InflateString(cx, bytes, &length);
5435 if (!chars)
5436 return NULL;
5437 JSObject *obj = RegExp::createObject(cx, chars, length, flags);
5438 cx->free(chars);
5439 return obj;
5442 JS_PUBLIC_API(JSObject *)
5443 JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags)
5445 CHECK_REQUEST(cx);
5446 return RegExp::createObject(cx, chars, length, flags);
5449 JS_PUBLIC_API(void)
5450 JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline)
5452 CHECK_REQUEST(cx);
5453 assertSameCompartment(cx, input);
5455 /* No locking required, cx is thread-private and input must be live. */
5456 cx->regExpStatics.reset(input, !!multiline);
5459 JS_PUBLIC_API(void)
5460 JS_ClearRegExpStatics(JSContext *cx)
5462 /* No locking required, cx is thread-private and input must be live. */
5463 cx->regExpStatics.clear();
5466 JS_PUBLIC_API(void)
5467 JS_ClearRegExpRoots(JSContext *cx)
5469 /* No locking required, cx is thread-private and input must be live. */
5470 cx->regExpStatics.clear();
5473 JS_PUBLIC_API(JSBool)
5474 JS_ExecuteRegExp(JSContext *cx, JSObject *obj, jschar *chars, size_t length,
5475 size_t *indexp, JSBool test, jsval *rval)
5477 CHECK_REQUEST(cx);
5479 RegExp *re = RegExp::extractFrom(obj);
5480 if (!re) {
5481 return JS_FALSE;
5484 JSString *str = js_NewStringCopyN(cx, chars, length);
5485 if (!str) {
5486 return JS_FALSE;
5488 AutoValueRooter v(cx, StringValue(str));
5490 return re->execute(cx, str, indexp, test, Valueify(rval));
5493 /* TODO: compile, get/set other statics... */
5495 /************************************************************************/
5497 JS_PUBLIC_API(void)
5498 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
5500 cx->localeCallbacks = callbacks;
5503 JS_PUBLIC_API(JSLocaleCallbacks *)
5504 JS_GetLocaleCallbacks(JSContext *cx)
5506 return cx->localeCallbacks;
5509 /************************************************************************/
5511 JS_PUBLIC_API(JSBool)
5512 JS_IsExceptionPending(JSContext *cx)
5514 return (JSBool) cx->throwing;
5517 JS_PUBLIC_API(JSBool)
5518 JS_GetPendingException(JSContext *cx, jsval *vp)
5520 CHECK_REQUEST(cx);
5521 if (!cx->throwing)
5522 return JS_FALSE;
5523 Valueify(*vp) = cx->exception;
5524 return JS_TRUE;
5527 JS_PUBLIC_API(void)
5528 JS_SetPendingException(JSContext *cx, jsval v)
5530 CHECK_REQUEST(cx);
5531 assertSameCompartment(cx, v);
5532 SetPendingException(cx, Valueify(v));
5535 JS_PUBLIC_API(void)
5536 JS_ClearPendingException(JSContext *cx)
5538 cx->throwing = JS_FALSE;
5539 cx->exception.setUndefined();
5542 JS_PUBLIC_API(JSBool)
5543 JS_ReportPendingException(JSContext *cx)
5545 JSBool ok;
5546 JSPackedBool save;
5548 CHECK_REQUEST(cx);
5551 * Set cx->generatingError to suppress the standard error-to-exception
5552 * conversion done by all {js,JS}_Report* functions except for OOM. The
5553 * cx->generatingError flag was added to suppress recursive divergence
5554 * under js_ErrorToException, but it serves for our purposes here too.
5556 save = cx->generatingError;
5557 cx->generatingError = JS_TRUE;
5558 ok = js_ReportUncaughtException(cx);
5559 cx->generatingError = save;
5560 return ok;
5563 struct JSExceptionState {
5564 JSBool throwing;
5565 jsval exception;
5568 JS_PUBLIC_API(JSExceptionState *)
5569 JS_SaveExceptionState(JSContext *cx)
5571 JSExceptionState *state;
5573 CHECK_REQUEST(cx);
5574 state = (JSExceptionState *) cx->malloc(sizeof(JSExceptionState));
5575 if (state) {
5576 state->throwing = JS_GetPendingException(cx, &state->exception);
5577 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
5578 js_AddRoot(cx, Valueify(&state->exception), "JSExceptionState.exception");
5580 return state;
5583 JS_PUBLIC_API(void)
5584 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
5586 CHECK_REQUEST(cx);
5587 if (state) {
5588 if (state->throwing)
5589 JS_SetPendingException(cx, state->exception);
5590 else
5591 JS_ClearPendingException(cx);
5592 JS_DropExceptionState(cx, state);
5596 JS_PUBLIC_API(void)
5597 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
5599 CHECK_REQUEST(cx);
5600 if (state) {
5601 if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
5602 assertSameCompartment(cx, state->exception);
5603 JS_RemoveValueRoot(cx, &state->exception);
5605 cx->free(state);
5609 JS_PUBLIC_API(JSErrorReport *)
5610 JS_ErrorFromException(JSContext *cx, jsval v)
5612 CHECK_REQUEST(cx);
5613 assertSameCompartment(cx, v);
5614 return js_ErrorFromException(cx, v);
5617 JS_PUBLIC_API(JSBool)
5618 JS_ThrowReportedError(JSContext *cx, const char *message,
5619 JSErrorReport *reportp)
5621 return JS_IsRunning(cx) &&
5622 js_ErrorToException(cx, message, reportp, NULL, NULL);
5625 JS_PUBLIC_API(JSBool)
5626 JS_ThrowStopIteration(JSContext *cx)
5628 return js_ThrowStopIteration(cx);
5632 * Get the owning thread id of a context. Returns 0 if the context is not
5633 * owned by any thread.
5635 JS_PUBLIC_API(jsword)
5636 JS_GetContextThread(JSContext *cx)
5638 #ifdef JS_THREADSAFE
5639 return reinterpret_cast<jsword>(JS_THREAD_ID(cx));
5640 #else
5641 return 0;
5642 #endif
5646 * Set the current thread as the owning thread of a context. Returns the
5647 * old owning thread id, or -1 if the operation failed.
5649 JS_PUBLIC_API(jsword)
5650 JS_SetContextThread(JSContext *cx)
5652 #ifdef JS_THREADSAFE
5653 JS_ASSERT(cx->requestDepth == 0);
5654 if (cx->thread) {
5655 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
5656 return reinterpret_cast<jsword>(cx->thread->id);
5659 if (!js_InitContextThread(cx)) {
5660 js_ReportOutOfMemory(cx);
5661 return -1;
5664 /* Here the GC lock is still held after js_InitContextThread took it. */
5665 JS_UNLOCK_GC(cx->runtime);
5666 #endif
5667 return 0;
5670 JS_PUBLIC_API(jsword)
5671 JS_ClearContextThread(JSContext *cx)
5673 #ifdef JS_THREADSAFE
5675 * This must be called outside a request and, if cx is associated with a
5676 * thread, this must be called only from that thread. If not, this is a
5677 * harmless no-op.
5679 JS_ASSERT(cx->requestDepth == 0);
5680 if (!cx->thread)
5681 return 0;
5682 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
5683 void *old = cx->thread->id;
5686 * We must not race with a GC that accesses cx->thread for all threads,
5687 * see bug 476934.
5689 JSRuntime *rt = cx->runtime;
5690 AutoLockGC lock(rt);
5691 js_WaitForGC(rt);
5692 js_ClearContextThread(cx);
5693 return reinterpret_cast<jsword>(old);
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 <windows.h>
5728 * Initialization routine for the JS DLL.
5730 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
5732 return TRUE;
5735 #endif