Bug 617935: Check string lengths using StringBuffer. (r=lw)
[mozilla-central.git] / js / src / jsapi.cpp
blob23b12798f1fb37f512ff69d5ca79ced0985779e8
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=78:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
25 * Contributor(s):
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 * JavaScript API.
44 #include <ctype.h>
45 #include <stdarg.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <sys/stat.h>
49 #include "jstypes.h"
50 #include "jsstdint.h"
51 #include "jsarena.h"
52 #include "jsutil.h"
53 #include "jsclist.h"
54 #include "jsdhash.h"
55 #include "jsprf.h"
56 #include "jsapi.h"
57 #include "jsarray.h"
58 #include "jsatom.h"
59 #include "jsbool.h"
60 #include "jsbuiltins.h"
61 #include "jsclone.h"
62 #include "jscntxt.h"
63 #include "jsversion.h"
64 #include "jsdate.h"
65 #include "jsemit.h"
66 #include "jsexn.h"
67 #include "jsfun.h"
68 #include "jsgc.h"
69 #include "jsinterp.h"
70 #include "jsiter.h"
71 #include "jslock.h"
72 #include "jsmath.h"
73 #include "jsnum.h"
74 #include "json.h"
75 #include "jsobj.h"
76 #include "jsopcode.h"
77 #include "jsparse.h"
78 #include "jsproxy.h"
79 #include "jsregexp.h"
80 #include "jsscan.h"
81 #include "jsscope.h"
82 #include "jsscript.h"
83 #include "jsstr.h"
84 #include "jstracer.h"
85 #include "jsdbgapi.h"
86 #include "prmjtime.h"
87 #include "jsstaticcheck.h"
88 #include "jsvector.h"
89 #include "jswrapper.h"
90 #include "jstypedarray.h"
92 #include "jsatominlines.h"
93 #include "jscntxtinlines.h"
94 #include "jsinterpinlines.h"
95 #include "jsobjinlines.h"
96 #include "jsscopeinlines.h"
97 #include "jscntxtinlines.h"
98 #include "jsregexpinlines.h"
99 #include "jsscriptinlines.h"
100 #include "jsstrinlines.h"
101 #include "assembler/wtf/Platform.h"
103 #if ENABLE_YARR_JIT
104 #include "assembler/jit/ExecutableAllocator.h"
105 #include "methodjit/Logging.h"
106 #endif
108 #if JS_HAS_XML_SUPPORT
109 #include "jsxml.h"
110 #endif
112 using namespace js;
113 using namespace js::gc;
115 static JSClass dummy_class = {
116 "jdummy",
117 JSCLASS_GLOBAL_FLAGS,
118 JS_PropertyStub, JS_PropertyStub,
119 JS_PropertyStub, JS_PropertyStub,
120 JS_EnumerateStub, JS_ResolveStub,
121 JS_ConvertStub, NULL,
122 JSCLASS_NO_OPTIONAL_MEMBERS
125 class AutoVersionAPI
127 JSContext * const cx;
128 JSVersion oldVersion;
129 bool oldVersionWasOverride;
130 uint32 oldOptions;
132 public:
133 explicit AutoVersionAPI(JSContext *cx, JSVersion newVersion)
134 : cx(cx), oldVersion(cx->findVersion()), oldVersionWasOverride(cx->isVersionOverridden()),
135 oldOptions(cx->options) {
137 * Note: ANONFUNFIX in newVersion is ignored for backwards
138 * compatibility, must be set via JS_SetOptions. (Because of this, we
139 * inherit the current ANONFUNFIX setting from the options.
141 cx->options = VersionHasXML(newVersion)
142 ? (cx->options | JSOPTION_XML)
143 : (cx->options & ~JSOPTION_XML);
145 VersionSetAnonFunFix(&newVersion, OptionsHasAnonFunFix(cx->options));
146 cx->maybeOverrideVersion(newVersion);
147 cx->checkOptionVersionSync();
150 ~AutoVersionAPI() {
151 cx->options = oldOptions;
152 if (oldVersionWasOverride) {
153 JS_ALWAYS_TRUE(cx->maybeOverrideVersion(oldVersion));
154 } else {
155 cx->clearVersionOverride();
156 cx->setDefaultVersion(oldVersion);
158 JS_ASSERT(cx->findVersion() == oldVersion);
162 #ifdef HAVE_VA_LIST_AS_ARRAY
163 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
164 #else
165 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
166 #endif
168 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
169 JS_PUBLIC_DATA(jsid) JS_DEFAULT_XML_NAMESPACE_ID = { size_t(JSID_TYPE_DEFAULT_XML_NAMESPACE) };
170 JS_PUBLIC_DATA(jsid) JSID_VOID = { size_t(JSID_TYPE_VOID) };
171 JS_PUBLIC_DATA(jsid) JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) };
172 #endif
174 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
175 JS_PUBLIC_DATA(jsval) JSVAL_NULL = { BUILD_JSVAL(JSVAL_TAG_NULL, 0) };
176 JS_PUBLIC_DATA(jsval) JSVAL_ZERO = { BUILD_JSVAL(JSVAL_TAG_INT32, 0) };
177 JS_PUBLIC_DATA(jsval) JSVAL_ONE = { BUILD_JSVAL(JSVAL_TAG_INT32, 1) };
178 JS_PUBLIC_DATA(jsval) JSVAL_FALSE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_FALSE) };
179 JS_PUBLIC_DATA(jsval) JSVAL_TRUE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_TRUE) };
180 JS_PUBLIC_DATA(jsval) JSVAL_VOID = { BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0) };
181 #endif
183 /* Make sure that jschar is two bytes unsigned integer */
184 JS_STATIC_ASSERT((jschar)-1 > 0);
185 JS_STATIC_ASSERT(sizeof(jschar) == 2);
187 JS_PUBLIC_API(int64)
188 JS_Now()
190 return PRMJ_Now();
193 JS_PUBLIC_API(jsval)
194 JS_GetNaNValue(JSContext *cx)
196 return Jsvalify(cx->runtime->NaNValue);
199 JS_PUBLIC_API(jsval)
200 JS_GetNegativeInfinityValue(JSContext *cx)
202 return Jsvalify(cx->runtime->negativeInfinityValue);
205 JS_PUBLIC_API(jsval)
206 JS_GetPositiveInfinityValue(JSContext *cx)
208 return Jsvalify(cx->runtime->positiveInfinityValue);
211 JS_PUBLIC_API(jsval)
212 JS_GetEmptyStringValue(JSContext *cx)
214 return STRING_TO_JSVAL(cx->runtime->emptyString);
217 JS_PUBLIC_API(JSString *)
218 JS_GetEmptyString(JSRuntime *rt)
220 JS_ASSERT(rt->state == JSRTS_UP);
221 return rt->emptyString;
224 static JSBool
225 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, jsval **vpp, va_list *app)
227 const char *format;
228 JSArgumentFormatMap *map;
230 format = *formatp;
231 for (map = cx->argumentFormatMap; map; map = map->next) {
232 if (!strncmp(format, map->format, map->length)) {
233 *formatp = format + map->length;
234 return map->formatter(cx, format, fromJS, vpp, app);
237 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
238 return JS_FALSE;
241 JS_PUBLIC_API(JSBool)
242 JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format, ...)
244 va_list ap;
245 JSBool ok;
247 va_start(ap, format);
248 ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
249 va_end(ap);
250 return ok;
253 JS_PUBLIC_API(JSBool)
254 JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format, va_list ap)
256 jsval *sp;
257 JSBool required;
258 char c;
259 JSFunction *fun;
260 jsdouble d;
261 JSString *str;
262 JSObject *obj;
264 CHECK_REQUEST(cx);
265 assertSameCompartment(cx, JSValueArray(argv - 2, argc + 2));
266 sp = argv;
267 required = JS_TRUE;
268 while ((c = *format++) != '\0') {
269 if (isspace(c))
270 continue;
271 if (c == '/') {
272 required = JS_FALSE;
273 continue;
275 if (sp == argv + argc) {
276 if (required) {
277 fun = js_ValueToFunction(cx, Valueify(&argv[-2]), 0);
278 if (fun) {
279 char numBuf[12];
280 JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
281 JSAutoByteString funNameBytes;
282 if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
283 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
284 name, numBuf, (argc == 1) ? "" : "s");
287 return JS_FALSE;
289 break;
291 switch (c) {
292 case 'b':
293 *va_arg(ap, JSBool *) = js_ValueToBoolean(Valueify(*sp));
294 break;
295 case 'c':
296 if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
297 return JS_FALSE;
298 break;
299 case 'i':
300 if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
301 return JS_FALSE;
302 break;
303 case 'u':
304 if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
305 return JS_FALSE;
306 break;
307 case 'j':
308 if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
309 return JS_FALSE;
310 break;
311 case 'd':
312 if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
313 return JS_FALSE;
314 break;
315 case 'I':
316 if (!JS_ValueToNumber(cx, *sp, &d))
317 return JS_FALSE;
318 *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
319 break;
320 case 'S':
321 case 'W':
322 str = js_ValueToString(cx, Valueify(*sp));
323 if (!str)
324 return JS_FALSE;
325 *sp = STRING_TO_JSVAL(str);
326 if (c == 'W') {
327 const jschar *chars = js_GetStringChars(cx, str);
328 if (!chars)
329 return JS_FALSE;
330 *va_arg(ap, const jschar **) = chars;
331 } else {
332 *va_arg(ap, JSString **) = str;
334 break;
335 case 'o':
336 if (!js_ValueToObjectOrNull(cx, Valueify(*sp), &obj))
337 return JS_FALSE;
338 *sp = OBJECT_TO_JSVAL(obj);
339 *va_arg(ap, JSObject **) = obj;
340 break;
341 case 'f':
342 obj = js_ValueToFunctionObject(cx, Valueify(sp), 0);
343 if (!obj)
344 return JS_FALSE;
345 *sp = OBJECT_TO_JSVAL(obj);
346 *va_arg(ap, JSFunction **) = GET_FUNCTION_PRIVATE(cx, obj);
347 break;
348 case 'v':
349 *va_arg(ap, jsval *) = *sp;
350 break;
351 case '*':
352 break;
353 default:
354 format--;
355 if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
356 JS_ADDRESSOF_VA_LIST(ap))) {
357 return JS_FALSE;
359 /* NB: the formatter already updated sp, so we continue here. */
360 continue;
362 sp++;
364 return JS_TRUE;
367 JS_PUBLIC_API(JSBool)
368 JS_AddArgumentFormatter(JSContext *cx, const char *format, JSArgumentFormatter formatter)
370 size_t length;
371 JSArgumentFormatMap **mpp, *map;
373 length = strlen(format);
374 mpp = &cx->argumentFormatMap;
375 while ((map = *mpp) != NULL) {
376 /* Insert before any shorter string to match before prefixes. */
377 if (map->length < length)
378 break;
379 if (map->length == length && !strcmp(map->format, format))
380 goto out;
381 mpp = &map->next;
383 map = (JSArgumentFormatMap *) cx->malloc(sizeof *map);
384 if (!map)
385 return JS_FALSE;
386 map->format = format;
387 map->length = length;
388 map->next = *mpp;
389 *mpp = map;
390 out:
391 map->formatter = formatter;
392 return JS_TRUE;
395 JS_PUBLIC_API(void)
396 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
398 size_t length;
399 JSArgumentFormatMap **mpp, *map;
401 length = strlen(format);
402 mpp = &cx->argumentFormatMap;
403 while ((map = *mpp) != NULL) {
404 if (map->length == length && !strcmp(map->format, format)) {
405 *mpp = map->next;
406 cx->free(map);
407 return;
409 mpp = &map->next;
413 JS_PUBLIC_API(JSBool)
414 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
416 JSBool ok;
417 JSObject *obj;
418 JSString *str;
419 jsdouble d;
421 CHECK_REQUEST(cx);
422 assertSameCompartment(cx, v);
423 switch (type) {
424 case JSTYPE_VOID:
425 *vp = JSVAL_VOID;
426 ok = JS_TRUE;
427 break;
428 case JSTYPE_OBJECT:
429 ok = js_ValueToObjectOrNull(cx, Valueify(v), &obj);
430 if (ok)
431 *vp = OBJECT_TO_JSVAL(obj);
432 break;
433 case JSTYPE_FUNCTION:
434 *vp = v;
435 obj = js_ValueToFunctionObject(cx, Valueify(vp), JSV2F_SEARCH_STACK);
436 ok = (obj != NULL);
437 break;
438 case JSTYPE_STRING:
439 str = js_ValueToString(cx, Valueify(v));
440 ok = (str != NULL);
441 if (ok)
442 *vp = STRING_TO_JSVAL(str);
443 break;
444 case JSTYPE_NUMBER:
445 ok = JS_ValueToNumber(cx, v, &d);
446 if (ok)
447 *vp = DOUBLE_TO_JSVAL(d);
448 break;
449 case JSTYPE_BOOLEAN:
450 *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(Valueify(v)));
451 return JS_TRUE;
452 default: {
453 char numBuf[12];
454 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
455 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE, numBuf);
456 ok = JS_FALSE;
457 break;
460 return ok;
463 JS_PUBLIC_API(JSBool)
464 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
466 CHECK_REQUEST(cx);
467 assertSameCompartment(cx, v);
468 return js_ValueToObjectOrNull(cx, Valueify(v), objp);
471 JS_PUBLIC_API(JSFunction *)
472 JS_ValueToFunction(JSContext *cx, jsval v)
474 CHECK_REQUEST(cx);
475 assertSameCompartment(cx, v);
476 return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
479 JS_PUBLIC_API(JSFunction *)
480 JS_ValueToConstructor(JSContext *cx, jsval v)
482 CHECK_REQUEST(cx);
483 assertSameCompartment(cx, v);
484 return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
487 JS_PUBLIC_API(JSString *)
488 JS_ValueToString(JSContext *cx, jsval v)
490 CHECK_REQUEST(cx);
491 assertSameCompartment(cx, v);
492 return js_ValueToString(cx, Valueify(v));
495 JS_PUBLIC_API(JSString *)
496 JS_ValueToSource(JSContext *cx, jsval v)
498 CHECK_REQUEST(cx);
499 assertSameCompartment(cx, v);
500 return js_ValueToSource(cx, Valueify(v));
503 JS_PUBLIC_API(JSBool)
504 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
506 CHECK_REQUEST(cx);
507 assertSameCompartment(cx, v);
509 AutoValueRooter tvr(cx, Valueify(v));
510 return ValueToNumber(cx, tvr.value(), dp);
513 JS_PUBLIC_API(JSBool)
514 JS_DoubleIsInt32(jsdouble d, jsint *ip)
516 return JSDOUBLE_IS_INT32(d, (int32_t *)ip);
519 JS_PUBLIC_API(JSBool)
520 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
522 CHECK_REQUEST(cx);
523 assertSameCompartment(cx, v);
525 AutoValueRooter tvr(cx, Valueify(v));
526 return ValueToECMAInt32(cx, tvr.value(), (int32_t *)ip);
529 JS_PUBLIC_API(JSBool)
530 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
532 CHECK_REQUEST(cx);
533 assertSameCompartment(cx, v);
535 AutoValueRooter tvr(cx, Valueify(v));
536 return ValueToECMAUint32(cx, tvr.value(), (uint32_t *)ip);
539 JS_PUBLIC_API(JSBool)
540 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
542 CHECK_REQUEST(cx);
543 assertSameCompartment(cx, v);
545 AutoValueRooter tvr(cx, Valueify(v));
546 return ValueToInt32(cx, tvr.value(), (int32_t *)ip);
549 JS_PUBLIC_API(JSBool)
550 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
552 CHECK_REQUEST(cx);
553 assertSameCompartment(cx, v);
555 AutoValueRooter tvr(cx, Valueify(v));
556 return ValueToUint16(cx, tvr.value(), (uint16_t *)ip);
559 JS_PUBLIC_API(JSBool)
560 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
562 CHECK_REQUEST(cx);
563 assertSameCompartment(cx, v);
564 *bp = js_ValueToBoolean(Valueify(v));
565 return JS_TRUE;
568 JS_PUBLIC_API(JSType)
569 JS_TypeOfValue(JSContext *cx, jsval v)
571 CHECK_REQUEST(cx);
572 assertSameCompartment(cx, v);
573 return TypeOfValue(cx, Valueify(v));
576 JS_PUBLIC_API(const char *)
577 JS_GetTypeName(JSContext *cx, JSType type)
579 if ((uintN)type >= (uintN)JSTYPE_LIMIT)
580 return NULL;
581 return JS_TYPE_STR(type);
584 JS_PUBLIC_API(JSBool)
585 JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
587 assertSameCompartment(cx, v1, v2);
588 return StrictlyEqual(cx, Valueify(v1), Valueify(v2), equal);
591 JS_PUBLIC_API(JSBool)
592 JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same)
594 assertSameCompartment(cx, v1, v2);
595 return SameValue(cx, Valueify(v1), Valueify(v2), same);
598 /************************************************************************/
601 * Has a new runtime ever been created? This flag is used to detect unsafe
602 * changes to js_CStringsAreUTF8 after a runtime has been created, and to
603 * ensure that "first checks" on runtime creation are run only once.
605 #ifdef DEBUG
606 static JSBool js_NewRuntimeWasCalled = JS_FALSE;
607 #endif
609 JSRuntime::JSRuntime()
610 : gcChunkAllocator(&defaultGCChunkAllocator)
612 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
613 JS_INIT_CLIST(&contextList);
614 JS_INIT_CLIST(&trapList);
615 JS_INIT_CLIST(&watchPointList);
618 bool
619 JSRuntime::init(uint32 maxbytes)
621 #ifdef JS_METHODJIT_SPEW
622 JMCheckLogging();
623 #endif
625 #ifdef DEBUG
626 functionMeterFilename = getenv("JS_FUNCTION_STATFILE");
627 if (functionMeterFilename) {
628 if (!methodReadBarrierCountMap.init())
629 return false;
630 if (!unjoinedFunctionCountMap.init())
631 return false;
633 propTreeStatFilename = getenv("JS_PROPTREE_STATFILE");
634 propTreeDumpFilename = getenv("JS_PROPTREE_DUMPFILE");
635 if (meterEmptyShapes()) {
636 if (!emptyShapes.init())
637 return false;
639 #endif
641 if (!(defaultCompartment = new JSCompartment(this)) ||
642 !defaultCompartment->init() ||
643 !compartments.append(defaultCompartment)) {
644 return false;
647 if (!js_InitGC(this, maxbytes) || !js_InitAtomState(this))
648 return false;
650 wrapObjectCallback = js::TransparentObjectWrapper;
652 #ifdef JS_THREADSAFE
653 /* this is asymmetric with JS_ShutDown: */
654 if (!js_SetupLocks(8, 16))
655 return false;
656 rtLock = JS_NEW_LOCK();
657 if (!rtLock)
658 return false;
659 stateChange = JS_NEW_CONDVAR(gcLock);
660 if (!stateChange)
661 return false;
662 debuggerLock = JS_NEW_LOCK();
663 if (!debuggerLock)
664 return false;
665 #endif
667 debugMode = JS_FALSE;
669 return propertyTree.init() && js_InitThreads(this);
672 JSRuntime::~JSRuntime()
674 #ifdef DEBUG
675 /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
676 if (!JS_CLIST_IS_EMPTY(&contextList)) {
677 JSContext *cx, *iter = NULL;
678 uintN cxcount = 0;
679 while ((cx = js_ContextIterator(this, JS_TRUE, &iter)) != NULL) {
680 fprintf(stderr,
681 "JS API usage error: found live context at %p\n",
682 (void *) cx);
683 cxcount++;
685 fprintf(stderr,
686 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
687 cxcount, (cxcount == 1) ? "" : "s");
689 #endif
691 js_FinishThreads(this);
692 js_FreeRuntimeScriptState(this);
693 js_FinishAtomState(this);
695 js_FinishGC(this);
696 #ifdef JS_THREADSAFE
697 if (gcLock)
698 JS_DESTROY_LOCK(gcLock);
699 if (gcDone)
700 JS_DESTROY_CONDVAR(gcDone);
701 if (requestDone)
702 JS_DESTROY_CONDVAR(requestDone);
703 if (rtLock)
704 JS_DESTROY_LOCK(rtLock);
705 if (stateChange)
706 JS_DESTROY_CONDVAR(stateChange);
707 if (debuggerLock)
708 JS_DESTROY_LOCK(debuggerLock);
709 #endif
710 propertyTree.finish();
713 JS_PUBLIC_API(JSRuntime *)
714 JS_NewRuntime(uint32 maxbytes)
716 #ifdef DEBUG
717 if (!js_NewRuntimeWasCalled) {
719 * This code asserts that the numbers associated with the error names
720 * in jsmsg.def are monotonically increasing. It uses values for the
721 * error names enumerated in jscntxt.c. It's not a compile-time check
722 * but it's better than nothing.
724 int errorNumber = 0;
725 #define MSG_DEF(name, number, count, exception, format) \
726 JS_ASSERT(name == errorNumber++);
727 #include "js.msg"
728 #undef MSG_DEF
730 #define MSG_DEF(name, number, count, exception, format) \
731 JS_BEGIN_MACRO \
732 uintN numfmtspecs = 0; \
733 const char *fmt; \
734 for (fmt = format; *fmt != '\0'; fmt++) { \
735 if (*fmt == '{' && isdigit(fmt[1])) \
736 ++numfmtspecs; \
738 JS_ASSERT(count == numfmtspecs); \
739 JS_END_MACRO;
740 #include "js.msg"
741 #undef MSG_DEF
743 js_NewRuntimeWasCalled = JS_TRUE;
745 #endif /* DEBUG */
747 void *mem = js_calloc(sizeof(JSRuntime));
748 if (!mem)
749 return NULL;
751 JSRuntime *rt = new (mem) JSRuntime();
752 if (!rt->init(maxbytes)) {
753 JS_DestroyRuntime(rt);
754 return NULL;
757 return rt;
760 JS_PUBLIC_API(void)
761 JS_DestroyRuntime(JSRuntime *rt)
763 rt->~JSRuntime();
765 js_free(rt);
768 #ifdef JS_REPRMETER
769 namespace reprmeter {
770 extern void js_DumpReprMeter();
772 #endif
774 JS_PUBLIC_API(void)
775 JS_ShutDown(void)
777 #ifdef MOZ_TRACEVIS
778 StopTraceVis();
779 #endif
781 #ifdef JS_OPMETER
782 extern void js_DumpOpMeters();
783 js_DumpOpMeters();
784 #endif
786 #ifdef JS_REPRMETER
787 reprmeter::js_DumpReprMeter();
788 #endif
790 #ifdef JS_THREADSAFE
791 js_CleanupLocks();
792 #endif
793 PRMJ_NowShutdown();
796 JS_PUBLIC_API(void *)
797 JS_GetRuntimePrivate(JSRuntime *rt)
799 return rt->data;
802 JS_PUBLIC_API(void)
803 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
805 rt->data = data;
808 #ifdef JS_THREADSAFE
809 static void
810 StartRequest(JSContext *cx)
812 JSThread *t = cx->thread;
813 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
815 if (t->data.requestDepth) {
816 t->data.requestDepth++;
817 } else {
818 JSRuntime *rt = cx->runtime;
819 AutoLockGC lock(rt);
821 /* Wait until the GC is finished. */
822 if (rt->gcThread != cx->thread) {
823 while (rt->gcThread)
824 JS_AWAIT_GC_DONE(rt);
827 /* Indicate that a request is running. */
828 rt->requestCount++;
829 t->data.requestDepth = 1;
832 * Adjust rt->interruptCounter to reflect any interrupts added while the
833 * thread was suspended.
835 if (t->data.interruptFlags)
836 JS_ATOMIC_INCREMENT(&rt->interruptCounter);
838 if (rt->requestCount == 1 && rt->activityCallback)
839 rt->activityCallback(rt->activityCallbackArg, true);
843 static void
844 StopRequest(JSContext *cx)
846 JSThread *t = cx->thread;
847 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
848 JS_ASSERT(t->data.requestDepth != 0);
849 if (t->data.requestDepth != 1) {
850 t->data.requestDepth--;
851 } else {
852 LeaveTrace(cx); /* for GC safety */
854 t->data.conservativeGC.updateForRequestEnd(t->suspendCount);
856 /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
857 JSRuntime *rt = cx->runtime;
858 AutoLockGC lock(rt);
860 t->data.requestDepth = 0;
863 * Adjust rt->interruptCounter to reflect any interrupts added while the
864 * thread still had active requests.
866 if (t->data.interruptFlags)
867 JS_ATOMIC_DECREMENT(&rt->interruptCounter);
869 /* Give the GC a chance to run if this was the last request running. */
870 JS_ASSERT(rt->requestCount > 0);
871 rt->requestCount--;
872 if (rt->requestCount == 0) {
873 JS_NOTIFY_REQUEST_DONE(rt);
874 if (rt->activityCallback)
875 rt->activityCallback(rt->activityCallbackArg, false);
879 #endif /* JS_THREADSAFE */
881 JS_PUBLIC_API(void)
882 JS_BeginRequest(JSContext *cx)
884 #ifdef JS_THREADSAFE
885 cx->outstandingRequests++;
886 StartRequest(cx);
887 #endif
890 JS_PUBLIC_API(void)
891 JS_EndRequest(JSContext *cx)
893 #ifdef JS_THREADSAFE
894 JS_ASSERT(cx->outstandingRequests != 0);
895 cx->outstandingRequests--;
896 StopRequest(cx);
897 #endif
900 /* Yield to pending GC operations, regardless of request depth */
901 JS_PUBLIC_API(void)
902 JS_YieldRequest(JSContext *cx)
904 #ifdef JS_THREADSAFE
905 CHECK_REQUEST(cx);
906 JS_ResumeRequest(cx, JS_SuspendRequest(cx));
907 #endif
910 JS_PUBLIC_API(jsrefcount)
911 JS_SuspendRequest(JSContext *cx)
913 #ifdef JS_THREADSAFE
914 JSThread *t = cx->thread;
915 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
917 jsrefcount saveDepth = t->data.requestDepth;
918 if (!saveDepth)
919 return 0;
921 t->suspendCount++;
922 t->data.requestDepth = 1;
923 StopRequest(cx);
924 return saveDepth;
925 #else
926 return 0;
927 #endif
930 JS_PUBLIC_API(void)
931 JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
933 #ifdef JS_THREADSAFE
934 JSThread *t = cx->thread;
935 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
936 if (saveDepth == 0)
937 return;
938 JS_ASSERT(saveDepth >= 1);
939 JS_ASSERT(!t->data.requestDepth);
940 JS_ASSERT(t->suspendCount);
941 StartRequest(cx);
942 t->data.requestDepth = saveDepth;
943 t->suspendCount--;
944 #endif
947 JS_PUBLIC_API(JSBool)
948 JS_IsInRequest(JSContext *cx)
950 #ifdef JS_THREADSAFE
951 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
952 return JS_THREAD_DATA(cx)->requestDepth != 0;
953 #else
954 return false;
955 #endif
958 JS_PUBLIC_API(void)
959 JS_Lock(JSRuntime *rt)
961 JS_LOCK_RUNTIME(rt);
964 JS_PUBLIC_API(void)
965 JS_Unlock(JSRuntime *rt)
967 JS_UNLOCK_RUNTIME(rt);
970 JS_PUBLIC_API(JSContextCallback)
971 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
973 JSContextCallback old;
975 old = rt->cxCallback;
976 rt->cxCallback = cxCallback;
977 return old;
980 JS_PUBLIC_API(JSContext *)
981 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
983 return js_NewContext(rt, stackChunkSize);
986 JS_PUBLIC_API(void)
987 JS_DestroyContext(JSContext *cx)
989 js_DestroyContext(cx, JSDCM_FORCE_GC);
992 JS_PUBLIC_API(void)
993 JS_DestroyContextNoGC(JSContext *cx)
995 js_DestroyContext(cx, JSDCM_NO_GC);
998 JS_PUBLIC_API(void)
999 JS_DestroyContextMaybeGC(JSContext *cx)
1001 js_DestroyContext(cx, JSDCM_MAYBE_GC);
1004 JS_PUBLIC_API(void *)
1005 JS_GetContextPrivate(JSContext *cx)
1007 return cx->data;
1010 JS_PUBLIC_API(void)
1011 JS_SetContextPrivate(JSContext *cx, void *data)
1013 cx->data = data;
1016 JS_PUBLIC_API(JSRuntime *)
1017 JS_GetRuntime(JSContext *cx)
1019 return cx->runtime;
1022 JS_PUBLIC_API(JSContext *)
1023 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
1025 return js_ContextIterator(rt, JS_TRUE, iterp);
1028 JS_PUBLIC_API(JSVersion)
1029 JS_GetVersion(JSContext *cx)
1031 return VersionNumber(cx->findVersion());
1034 JS_PUBLIC_API(JSVersion)
1035 JS_SetVersion(JSContext *cx, JSVersion newVersion)
1037 JS_ASSERT(VersionIsKnown(newVersion));
1038 JS_ASSERT(!VersionHasFlags(newVersion));
1039 JSVersion newVersionNumber = newVersion;
1041 JSVersion oldVersion = cx->findVersion();
1042 JSVersion oldVersionNumber = VersionNumber(oldVersion);
1043 if (oldVersionNumber == newVersionNumber)
1044 return oldVersionNumber; /* No override actually occurs! */
1046 /* We no longer support 1.4 or below. */
1047 if (newVersionNumber != JSVERSION_DEFAULT && newVersionNumber <= JSVERSION_1_4)
1048 return oldVersionNumber;
1050 cx->optionFlagsToVersion(&newVersion);
1051 cx->maybeOverrideVersion(newVersion);
1052 cx->checkOptionVersionSync();
1053 return oldVersionNumber;
1056 static struct v2smap {
1057 JSVersion version;
1058 const char *string;
1059 } v2smap[] = {
1060 {JSVERSION_1_0, "1.0"},
1061 {JSVERSION_1_1, "1.1"},
1062 {JSVERSION_1_2, "1.2"},
1063 {JSVERSION_1_3, "1.3"},
1064 {JSVERSION_1_4, "1.4"},
1065 {JSVERSION_ECMA_3, "ECMAv3"},
1066 {JSVERSION_1_5, "1.5"},
1067 {JSVERSION_1_6, "1.6"},
1068 {JSVERSION_1_7, "1.7"},
1069 {JSVERSION_1_8, "1.8"},
1070 {JSVERSION_ECMA_5, "ECMAv5"},
1071 {JSVERSION_DEFAULT, js_default_str},
1072 {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
1075 JS_PUBLIC_API(const char *)
1076 JS_VersionToString(JSVersion version)
1078 int i;
1080 for (i = 0; v2smap[i].string; i++)
1081 if (v2smap[i].version == version)
1082 return v2smap[i].string;
1083 return "unknown";
1086 JS_PUBLIC_API(JSVersion)
1087 JS_StringToVersion(const char *string)
1089 int i;
1091 for (i = 0; v2smap[i].string; i++)
1092 if (strcmp(v2smap[i].string, string) == 0)
1093 return v2smap[i].version;
1094 return JSVERSION_UNKNOWN;
1097 JS_PUBLIC_API(uint32)
1098 JS_GetOptions(JSContext *cx)
1101 * Can't check option/version synchronization here.
1102 * We may have been synchronized with a script version that was formerly on
1103 * the stack, but has now been popped.
1105 return cx->options;
1108 JS_PUBLIC_API(uint32)
1109 JS_SetOptions(JSContext *cx, uint32 options)
1111 AutoLockGC lock(cx->runtime);
1112 uint32 oldopts = cx->options;
1113 cx->options = options;
1114 cx->syncOptionsToVersion();
1115 cx->updateJITEnabled();
1116 cx->checkOptionVersionSync();
1117 return oldopts;
1120 JS_PUBLIC_API(uint32)
1121 JS_ToggleOptions(JSContext *cx, uint32 options)
1123 AutoLockGC lock(cx->runtime);
1124 cx->checkOptionVersionSync();
1125 uint32 oldopts = cx->options;
1126 cx->options ^= options;
1127 cx->syncOptionsToVersion();
1128 cx->updateJITEnabled();
1129 cx->checkOptionVersionSync();
1130 return oldopts;
1133 JS_PUBLIC_API(const char *)
1134 JS_GetImplementationVersion(void)
1136 return "JavaScript-C 1.8.0 pre-release 1 2007-10-03";
1139 JS_PUBLIC_API(JSCompartmentCallback)
1140 JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback)
1142 JSCompartmentCallback old = rt->compartmentCallback;
1143 rt->compartmentCallback = callback;
1144 return old;
1147 JS_PUBLIC_API(JSWrapObjectCallback)
1148 JS_SetWrapObjectCallbacks(JSRuntime *rt,
1149 JSWrapObjectCallback callback,
1150 JSPreWrapCallback precallback)
1152 JSWrapObjectCallback old = rt->wrapObjectCallback;
1153 rt->wrapObjectCallback = callback;
1154 rt->preWrapObjectCallback = precallback;
1155 return old;
1158 JS_PUBLIC_API(JSCrossCompartmentCall *)
1159 JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
1161 CHECK_REQUEST(cx);
1163 JS_ASSERT(target);
1164 AutoCompartment *call = new AutoCompartment(cx, target);
1165 if (!call)
1166 return NULL;
1167 if (!call->enter()) {
1168 delete call;
1169 return NULL;
1171 return reinterpret_cast<JSCrossCompartmentCall *>(call);
1174 JS_PUBLIC_API(JSCrossCompartmentCall *)
1175 JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
1177 CHECK_REQUEST(cx);
1179 JS_ASSERT(target);
1180 JSObject *scriptObject = target->u.object;
1181 if (!scriptObject) {
1182 SwitchToCompartment sc(cx, target->compartment);
1183 scriptObject = JS_NewGlobalObject(cx, &dummy_class);
1184 if (!scriptObject)
1185 return NULL;
1187 return JS_EnterCrossCompartmentCall(cx, scriptObject);
1190 JS_PUBLIC_API(void)
1191 JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
1193 AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
1194 CHECK_REQUEST(realcall->context);
1195 realcall->leave();
1196 delete realcall;
1199 bool
1200 JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target)
1202 JS_ASSERT(!call);
1203 if (cx->compartment == target->getCompartment()) {
1204 call = reinterpret_cast<JSCrossCompartmentCall*>(1);
1205 return true;
1207 call = JS_EnterCrossCompartmentCall(cx, target);
1208 return call != NULL;
1211 bool
1212 JSAutoEnterCompartment::enter(JSContext *cx, JSScript *target)
1214 JS_ASSERT(!call);
1215 if (cx->compartment == target->compartment) {
1216 call = reinterpret_cast<JSCrossCompartmentCall*>(1);
1217 return true;
1219 call = JS_EnterCrossCompartmentCallScript(cx, target);
1220 return call != NULL;
1223 void
1224 JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target)
1226 (void) enter(cx, target);
1229 JS_PUBLIC_API(void *)
1230 JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data)
1232 CHECK_REQUEST(cx);
1233 void *old = compartment->data;
1234 compartment->data = data;
1235 return old;
1238 JS_PUBLIC_API(void *)
1239 JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment)
1241 CHECK_REQUEST(cx);
1242 return compartment->data;
1245 JS_PUBLIC_API(JSBool)
1246 JS_WrapObject(JSContext *cx, JSObject **objp)
1248 CHECK_REQUEST(cx);
1249 return cx->compartment->wrap(cx, objp);
1252 JS_PUBLIC_API(JSBool)
1253 JS_WrapValue(JSContext *cx, jsval *vp)
1255 CHECK_REQUEST(cx);
1256 return cx->compartment->wrap(cx, Valueify(vp));
1259 JS_PUBLIC_API(JSObject *)
1260 JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target)
1262 // This function is called when an object moves between two different
1263 // compartments. In that case, we need to "move" the window from origobj's
1264 // compartment to target's compartment.
1265 JSCompartment *destination = target->getCompartment();
1266 if (origobj->getCompartment() == destination) {
1267 // If the original object is in the same compartment as the
1268 // destination, then we know that we won't find wrapper in the
1269 // destination's cross compartment map and that the same object
1270 // will continue to work.
1271 if (!origobj->swap(cx, target))
1272 return NULL;
1273 return origobj;
1276 JSObject *obj;
1277 WrapperMap &map = destination->crossCompartmentWrappers;
1278 Value origv = ObjectValue(*origobj);
1280 // There might already be a wrapper for the original object in the new
1281 // compartment.
1282 if (WrapperMap::Ptr p = map.lookup(origv)) {
1283 // If there is, make it the primary outer window proxy around the
1284 // inner (accomplished by swapping target's innards with the old,
1285 // possibly security wrapper, innards).
1286 obj = &p->value.toObject();
1287 map.remove(p);
1288 if (!obj->swap(cx, target))
1289 return NULL;
1290 } else {
1291 // Otherwise, this is going to be our outer window proxy in the new
1292 // compartment.
1293 obj = target;
1296 // Now, iterate through other scopes looking for references to the old
1297 // outer window. They need to be updated to point at the new outer window.
1298 // They also might transition between different types of security wrappers
1299 // based on whether the new compartment is same origin with them.
1300 Value targetv = ObjectValue(*obj);
1301 WrapperVector &vector = cx->runtime->compartments;
1302 AutoValueVector toTransplant(cx);
1303 toTransplant.reserve(vector.length());
1305 for (JSCompartment **p = vector.begin(), **end = vector.end(); p != end; ++p) {
1306 WrapperMap &pmap = (*p)->crossCompartmentWrappers;
1307 if (WrapperMap::Ptr wp = pmap.lookup(origv)) {
1308 // We found a wrapper. Remember and root it.
1309 toTransplant.append(wp->value);
1313 for (Value *begin = toTransplant.begin(), *end = toTransplant.end(); begin != end; ++begin) {
1314 JSObject *wobj = &begin->toObject();
1315 JSCompartment *wcompartment = wobj->compartment();
1316 WrapperMap &pmap = wcompartment->crossCompartmentWrappers;
1317 JS_ASSERT(pmap.lookup(origv));
1318 pmap.remove(origv);
1320 // First, we wrap it in the new compartment. This will return a
1321 // new wrapper.
1322 AutoCompartment ac(cx, wobj);
1323 JSObject *tobj = obj;
1324 if (!ac.enter() || !wcompartment->wrap(cx, &tobj))
1325 return NULL;
1327 // Now, because we need to maintain object identity, we do a brain
1328 // transplant on the old object. At the same time, we update the
1329 // entry in the compartment's wrapper map to point to the old
1330 // wrapper.
1331 JS_ASSERT(tobj != wobj);
1332 if (!wobj->swap(cx, tobj))
1333 return NULL;
1334 pmap.put(targetv, ObjectValue(*wobj));
1337 // Lastly, update the original object to point to the new one.
1339 AutoCompartment ac(cx, origobj);
1340 JSObject *tobj = obj;
1341 if (!ac.enter() || !JS_WrapObject(cx, &tobj))
1342 return NULL;
1343 if (!origobj->swap(cx, tobj))
1344 return NULL;
1345 origobj->getCompartment()->crossCompartmentWrappers.put(targetv, origv);
1348 return obj;
1351 JS_PUBLIC_API(JSObject *)
1352 JS_GetGlobalObject(JSContext *cx)
1354 return cx->globalObject;
1357 JS_PUBLIC_API(void)
1358 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1360 CHECK_REQUEST(cx);
1362 cx->globalObject = obj;
1363 if (!cx->hasfp())
1364 cx->resetCompartment();
1367 class AutoResolvingEntry {
1368 public:
1369 AutoResolvingEntry() : entry(NULL) {}
1372 * Returns false on error. But N.B. if obj[id] was already being resolved,
1373 * this is a no-op, and we silently treat that as success.
1375 bool start(JSContext *cx, JSObject *obj, jsid id, uint32 flag) {
1376 JS_ASSERT(!entry);
1377 this->cx = cx;
1378 key.obj = obj;
1379 key.id = id;
1380 this->flag = flag;
1381 bool ok = !!js_StartResolving(cx, &key, flag, &entry);
1382 JS_ASSERT_IF(!ok, !entry);
1383 return ok;
1386 ~AutoResolvingEntry() {
1387 if (entry)
1388 js_StopResolving(cx, &key, flag, NULL, 0);
1391 private:
1392 JSContext *cx;
1393 JSResolvingKey key;
1394 uint32 flag;
1395 JSResolvingEntry *entry;
1398 JSObject *
1399 js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1401 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
1402 JSObject *fun_proto, *obj_proto;
1404 /* If cx has no global object, use obj so prototypes can be found. */
1405 if (!cx->globalObject)
1406 JS_SetGlobalObject(cx, obj);
1408 /* Record Function and Object in cx->resolvingTable. */
1409 AutoResolvingEntry e1, e2;
1410 JSAtom **classAtoms = cx->runtime->atomState.classAtoms;
1411 if (!e1.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Function]), JSRESFLAG_LOOKUP) ||
1412 !e2.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Object]), JSRESFLAG_LOOKUP)) {
1413 return NULL;
1416 /* Initialize the function class first so constructors can be made. */
1417 if (!js_GetClassPrototype(cx, obj, JSProto_Function, &fun_proto))
1418 return NULL;
1419 if (!fun_proto) {
1420 fun_proto = js_InitFunctionClass(cx, obj);
1421 if (!fun_proto)
1422 return NULL;
1423 } else {
1424 JSObject *ctor;
1426 ctor = JS_GetConstructor(cx, fun_proto);
1427 if (!ctor)
1428 return NULL;
1429 obj->defineProperty(cx, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
1430 ObjectValue(*ctor), 0, 0, 0);
1433 /* Initialize the object class next so Object.prototype works. */
1434 if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto))
1435 return NULL;
1436 if (!obj_proto)
1437 obj_proto = js_InitObjectClass(cx, obj);
1438 if (!obj_proto)
1439 return NULL;
1441 /* Function.prototype and the global object delegate to Object.prototype. */
1442 fun_proto->setProto(obj_proto);
1443 if (!obj->getProto())
1444 obj->setProto(obj_proto);
1446 return fun_proto;
1449 JS_PUBLIC_API(JSBool)
1450 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1452 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
1453 CHECK_REQUEST(cx);
1456 * JS_SetGlobalObject might or might not change cx's compartment, so call
1457 * it before assertSameCompartment. (The API contract is that *after* this,
1458 * cx and obj must be in the same compartment.)
1460 if (!cx->globalObject)
1461 JS_SetGlobalObject(cx, obj);
1462 assertSameCompartment(cx, obj);
1464 /* Define a top-level property 'undefined' with the undefined value. */
1465 JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1466 if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1467 PropertyStub, PropertyStub,
1468 JSPROP_PERMANENT | JSPROP_READONLY)) {
1469 return JS_FALSE;
1472 /* Function and Object require cooperative bootstrapping magic. */
1473 if (!js_InitFunctionAndObjectClasses(cx, obj))
1474 return JS_FALSE;
1476 /* Initialize the rest of the standard objects and functions. */
1477 return js_InitArrayClass(cx, obj) &&
1478 js_InitBooleanClass(cx, obj) &&
1479 js_InitExceptionClasses(cx, obj) &&
1480 js_InitMathClass(cx, obj) &&
1481 js_InitNumberClass(cx, obj) &&
1482 js_InitJSONClass(cx, obj) &&
1483 js_InitRegExpClass(cx, obj) &&
1484 js_InitStringClass(cx, obj) &&
1485 js_InitTypedArrayClasses(cx, obj) &&
1486 #if JS_HAS_XML_SUPPORT
1487 js_InitXMLClasses(cx, obj) &&
1488 #endif
1489 #if JS_HAS_GENERATORS
1490 js_InitIteratorClasses(cx, obj) &&
1491 #endif
1492 js_InitDateClass(cx, obj) &&
1493 js_InitProxyClass(cx, obj);
1496 #define CLASP(name) (&js_##name##Class)
1497 #define TYPED_ARRAY_CLASP(type) (&TypedArray::fastClasses[TypedArray::type])
1498 #define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
1499 #define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
1500 #define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
1501 #define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
1503 typedef struct JSStdName {
1504 JSObjectOp init;
1505 size_t atomOffset; /* offset of atom pointer in JSAtomState */
1506 const char *name; /* null if atom is pre-pinned, else name */
1507 Class *clasp;
1508 } JSStdName;
1510 static JSAtom *
1511 StdNameToAtom(JSContext *cx, JSStdName *stdn)
1513 size_t offset;
1514 JSAtom *atom;
1515 const char *name;
1517 offset = stdn->atomOffset;
1518 atom = OFFSET_TO_ATOM(cx->runtime, offset);
1519 if (!atom) {
1520 name = stdn->name;
1521 if (name) {
1522 atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1523 OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1526 return atom;
1530 * Table of class initializers and their atom offsets in rt->atomState.
1531 * If you add a "standard" class, remember to update this table.
1533 static JSStdName standard_class_atoms[] = {
1534 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Function)},
1535 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Object)},
1536 {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)},
1537 {js_InitBooleanClass, EAGER_ATOM_AND_CLASP(Boolean)},
1538 {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)},
1539 {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)},
1540 {js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)},
1541 {js_InitStringClass, EAGER_ATOM_AND_CLASP(String)},
1542 {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)},
1543 {js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)},
1544 #if JS_HAS_XML_SUPPORT
1545 {js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)},
1546 {js_InitNamespaceClass, EAGER_ATOM_AND_CLASP(Namespace)},
1547 {js_InitQNameClass, EAGER_ATOM_AND_CLASP(QName)},
1548 #endif
1549 #if JS_HAS_GENERATORS
1550 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
1551 #endif
1552 {js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
1553 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
1554 {NULL, 0, NULL, NULL}
1558 * Table of top-level function and constant names and their init functions.
1559 * If you add a "standard" global function or property, remember to update
1560 * this table.
1562 static JSStdName standard_class_names[] = {
1563 {js_InitObjectClass, EAGER_ATOM(eval), CLASP(Object)},
1565 /* Global properties and functions defined by the Number class. */
1566 {js_InitNumberClass, EAGER_ATOM(NaN), CLASP(Number)},
1567 {js_InitNumberClass, EAGER_ATOM(Infinity), CLASP(Number)},
1568 {js_InitNumberClass, LAZY_ATOM(isNaN), CLASP(Number)},
1569 {js_InitNumberClass, LAZY_ATOM(isFinite), CLASP(Number)},
1570 {js_InitNumberClass, LAZY_ATOM(parseFloat), CLASP(Number)},
1571 {js_InitNumberClass, LAZY_ATOM(parseInt), CLASP(Number)},
1573 /* String global functions. */
1574 {js_InitStringClass, LAZY_ATOM(escape), CLASP(String)},
1575 {js_InitStringClass, LAZY_ATOM(unescape), CLASP(String)},
1576 {js_InitStringClass, LAZY_ATOM(decodeURI), CLASP(String)},
1577 {js_InitStringClass, LAZY_ATOM(encodeURI), CLASP(String)},
1578 {js_InitStringClass, LAZY_ATOM(decodeURIComponent), CLASP(String)},
1579 {js_InitStringClass, LAZY_ATOM(encodeURIComponent), CLASP(String)},
1580 #if JS_HAS_UNEVAL
1581 {js_InitStringClass, LAZY_ATOM(uneval), CLASP(String)},
1582 #endif
1584 /* Exception constructors. */
1585 {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)},
1586 {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
1587 {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
1588 {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
1589 {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
1590 {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
1591 {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
1592 {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)},
1594 #if JS_HAS_XML_SUPPORT
1595 {js_InitXMLClass, LAZY_ATOM(XMLList), CLASP(XML)},
1596 {js_InitXMLClass, LAZY_ATOM(isXMLName), CLASP(XML)},
1597 #endif
1599 #if JS_HAS_GENERATORS
1600 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)},
1601 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Generator)},
1602 #endif
1604 /* Typed Arrays */
1605 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
1606 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int8Array), TYPED_ARRAY_CLASP(TYPE_INT8)},
1607 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8Array), TYPED_ARRAY_CLASP(TYPE_UINT8)},
1608 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int16Array), TYPED_ARRAY_CLASP(TYPE_INT16)},
1609 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint16Array), TYPED_ARRAY_CLASP(TYPE_UINT16)},
1610 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int32Array), TYPED_ARRAY_CLASP(TYPE_INT32)},
1611 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint32Array), TYPED_ARRAY_CLASP(TYPE_UINT32)},
1612 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float32Array), TYPED_ARRAY_CLASP(TYPE_FLOAT32)},
1613 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
1614 {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8ClampedArray),
1615 TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
1617 {js_InitProxyClass, EAGER_ATOM_AND_CLASP(Proxy)},
1619 {NULL, 0, NULL, NULL}
1622 static JSStdName object_prototype_names[] = {
1623 /* Object.prototype properties (global delegates to Object.prototype). */
1624 {js_InitObjectClass, EAGER_ATOM(proto), CLASP(Object)},
1625 #if JS_HAS_TOSOURCE
1626 {js_InitObjectClass, EAGER_ATOM(toSource), CLASP(Object)},
1627 #endif
1628 {js_InitObjectClass, EAGER_ATOM(toString), CLASP(Object)},
1629 {js_InitObjectClass, EAGER_ATOM(toLocaleString), CLASP(Object)},
1630 {js_InitObjectClass, EAGER_ATOM(valueOf), CLASP(Object)},
1631 #if JS_HAS_OBJ_WATCHPOINT
1632 {js_InitObjectClass, LAZY_ATOM(watch), CLASP(Object)},
1633 {js_InitObjectClass, LAZY_ATOM(unwatch), CLASP(Object)},
1634 #endif
1635 {js_InitObjectClass, LAZY_ATOM(hasOwnProperty), CLASP(Object)},
1636 {js_InitObjectClass, LAZY_ATOM(isPrototypeOf), CLASP(Object)},
1637 {js_InitObjectClass, LAZY_ATOM(propertyIsEnumerable), CLASP(Object)},
1638 #if OLD_GETTER_SETTER_METHODS
1639 {js_InitObjectClass, LAZY_ATOM(defineGetter), CLASP(Object)},
1640 {js_InitObjectClass, LAZY_ATOM(defineSetter), CLASP(Object)},
1641 {js_InitObjectClass, LAZY_ATOM(lookupGetter), CLASP(Object)},
1642 {js_InitObjectClass, LAZY_ATOM(lookupSetter), CLASP(Object)},
1643 #endif
1645 {NULL, 0, NULL, NULL}
1648 JS_PUBLIC_API(JSBool)
1649 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
1651 JSString *idstr;
1652 JSRuntime *rt;
1653 JSAtom *atom;
1654 JSStdName *stdnm;
1655 uintN i;
1657 CHECK_REQUEST(cx);
1658 assertSameCompartment(cx, obj, id);
1659 *resolved = JS_FALSE;
1661 rt = cx->runtime;
1662 JS_ASSERT(rt->state != JSRTS_DOWN);
1663 if (rt->state == JSRTS_LANDING || !JSID_IS_ATOM(id))
1664 return JS_TRUE;
1666 idstr = JSID_TO_STRING(id);
1668 /* Check whether we're resolving 'undefined', and define it if so. */
1669 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1670 if (idstr == ATOM_TO_STRING(atom)) {
1671 *resolved = JS_TRUE;
1672 return obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1673 PropertyStub, PropertyStub,
1674 JSPROP_PERMANENT | JSPROP_READONLY);
1677 /* Try for class constructors/prototypes named by well-known atoms. */
1678 stdnm = NULL;
1679 for (i = 0; standard_class_atoms[i].init; i++) {
1680 JS_ASSERT(standard_class_atoms[i].clasp);
1681 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1682 if (idstr == ATOM_TO_STRING(atom)) {
1683 stdnm = &standard_class_atoms[i];
1684 break;
1688 if (!stdnm) {
1689 /* Try less frequently used top-level functions and constants. */
1690 for (i = 0; standard_class_names[i].init; i++) {
1691 JS_ASSERT(standard_class_names[i].clasp);
1692 atom = StdNameToAtom(cx, &standard_class_names[i]);
1693 if (!atom)
1694 return JS_FALSE;
1695 if (idstr == ATOM_TO_STRING(atom)) {
1696 stdnm = &standard_class_names[i];
1697 break;
1701 if (!stdnm && !obj->getProto()) {
1703 * Try even less frequently used names delegated from the global
1704 * object to Object.prototype, but only if the Object class hasn't
1705 * yet been initialized.
1707 for (i = 0; object_prototype_names[i].init; i++) {
1708 JS_ASSERT(object_prototype_names[i].clasp);
1709 atom = StdNameToAtom(cx, &object_prototype_names[i]);
1710 if (!atom)
1711 return JS_FALSE;
1712 if (idstr == ATOM_TO_STRING(atom)) {
1713 stdnm = &object_prototype_names[i];
1714 break;
1720 if (stdnm) {
1722 * If this standard class is anonymous, then we don't want to resolve
1723 * by name.
1725 JS_ASSERT(obj->isGlobal());
1726 if (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)
1727 return JS_TRUE;
1729 JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(stdnm->clasp);
1730 if (obj->getReservedSlot(key).isObject())
1731 return JS_TRUE;
1733 if (!stdnm->init(cx, obj))
1734 return JS_FALSE;
1735 *resolved = JS_TRUE;
1737 return JS_TRUE;
1740 JS_PUBLIC_API(JSBool)
1741 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1743 JSRuntime *rt;
1744 JSAtom *atom;
1745 uintN i;
1747 CHECK_REQUEST(cx);
1748 assertSameCompartment(cx, obj);
1749 rt = cx->runtime;
1751 /* Check whether we need to bind 'undefined' and define it if so. */
1752 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1753 if (!obj->nativeContains(ATOM_TO_JSID(atom)) &&
1754 !obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1755 PropertyStub, PropertyStub,
1756 JSPROP_PERMANENT | JSPROP_READONLY)) {
1757 return JS_FALSE;
1760 /* Initialize any classes that have not been resolved yet. */
1761 for (i = 0; standard_class_atoms[i].init; i++) {
1762 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1763 if (!obj->nativeContains(ATOM_TO_JSID(atom)) &&
1764 !standard_class_atoms[i].init(cx, obj)) {
1765 return JS_FALSE;
1769 return JS_TRUE;
1772 namespace js {
1774 JSIdArray *
1775 NewIdArray(JSContext *cx, jsint length)
1777 JSIdArray *ida;
1779 ida = (JSIdArray *)
1780 cx->calloc(offsetof(JSIdArray, vector) + length * sizeof(jsval));
1781 if (ida)
1782 ida->length = length;
1783 return ida;
1789 * Unlike realloc(3), this function frees ida on failure.
1791 static JSIdArray *
1792 SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
1794 JSIdArray *rida;
1796 rida = (JSIdArray *)
1797 JS_realloc(cx, ida,
1798 offsetof(JSIdArray, vector) + length * sizeof(jsval));
1799 if (!rida) {
1800 JS_DestroyIdArray(cx, ida);
1801 } else {
1802 rida->length = length;
1804 return rida;
1807 static JSIdArray *
1808 AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1810 jsint i, length;
1812 i = *ip;
1813 length = ida->length;
1814 if (i >= length) {
1815 ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
1816 if (!ida)
1817 return NULL;
1818 JS_ASSERT(i < ida->length);
1820 ida->vector[i] = ATOM_TO_JSID(atom);
1821 *ip = i + 1;
1822 return ida;
1825 static JSIdArray *
1826 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
1827 jsint *ip, JSBool *foundp)
1829 *foundp = obj->nativeContains(ATOM_TO_JSID(atom));
1830 if (*foundp)
1831 ida = AddAtomToArray(cx, atom, ida, ip);
1832 return ida;
1835 JS_PUBLIC_API(JSIdArray *)
1836 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, JSIdArray *ida)
1838 JSRuntime *rt;
1839 jsint i, j, k;
1840 JSAtom *atom;
1841 JSBool found;
1842 JSObjectOp init;
1844 CHECK_REQUEST(cx);
1845 assertSameCompartment(cx, obj, ida);
1846 rt = cx->runtime;
1847 if (ida) {
1848 i = ida->length;
1849 } else {
1850 ida = NewIdArray(cx, 8);
1851 if (!ida)
1852 return NULL;
1853 i = 0;
1856 /* Check whether 'undefined' has been resolved and enumerate it if so. */
1857 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1858 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1859 if (!ida)
1860 return NULL;
1862 /* Enumerate only classes that *have* been resolved. */
1863 for (j = 0; standard_class_atoms[j].init; j++) {
1864 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
1865 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1866 if (!ida)
1867 return NULL;
1869 if (found) {
1870 init = standard_class_atoms[j].init;
1872 for (k = 0; standard_class_names[k].init; k++) {
1873 if (standard_class_names[k].init == init) {
1874 atom = StdNameToAtom(cx, &standard_class_names[k]);
1875 ida = AddAtomToArray(cx, atom, ida, &i);
1876 if (!ida)
1877 return NULL;
1881 if (init == js_InitObjectClass) {
1882 for (k = 0; object_prototype_names[k].init; k++) {
1883 atom = StdNameToAtom(cx, &object_prototype_names[k]);
1884 ida = AddAtomToArray(cx, atom, ida, &i);
1885 if (!ida)
1886 return NULL;
1892 /* Trim to exact length. */
1893 return SetIdArrayLength(cx, ida, i);
1896 #undef CLASP
1897 #undef EAGER_ATOM
1898 #undef EAGER_CLASS_ATOM
1899 #undef EAGER_ATOM_CLASP
1900 #undef LAZY_ATOM
1902 JS_PUBLIC_API(JSBool)
1903 JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp)
1905 CHECK_REQUEST(cx);
1906 assertSameCompartment(cx, obj);
1907 return js_GetClassObject(cx, obj, key, objp);
1910 JS_PUBLIC_API(JSObject *)
1911 JS_GetScopeChain(JSContext *cx)
1913 CHECK_REQUEST(cx);
1914 return GetScopeChain(cx);
1917 JS_PUBLIC_API(JSObject *)
1918 JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
1920 assertSameCompartment(cx, obj);
1921 return obj->getGlobal();
1924 JS_PUBLIC_API(JSObject *)
1925 JS_GetGlobalForScopeChain(JSContext *cx)
1927 CHECK_REQUEST(cx);
1928 return GetGlobalForScopeChain(cx);
1931 JS_PUBLIC_API(jsval)
1932 JS_ComputeThis(JSContext *cx, jsval *vp)
1934 assertSameCompartment(cx, JSValueArray(vp, 2));
1935 if (!ComputeThisFromVp(cx, Valueify(vp)))
1936 return JSVAL_NULL;
1937 return vp[1];
1940 JS_PUBLIC_API(void *)
1941 JS_malloc(JSContext *cx, size_t nbytes)
1943 return cx->malloc(nbytes);
1946 JS_PUBLIC_API(void *)
1947 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1949 return cx->realloc(p, nbytes);
1952 JS_PUBLIC_API(void)
1953 JS_free(JSContext *cx, void *p)
1955 return cx->free(p);
1958 JS_PUBLIC_API(void)
1959 JS_updateMallocCounter(JSContext *cx, size_t nbytes)
1961 return cx->runtime->updateMallocCounter(nbytes);
1964 JS_PUBLIC_API(char *)
1965 JS_strdup(JSContext *cx, const char *s)
1967 size_t n;
1968 void *p;
1970 n = strlen(s) + 1;
1971 p = cx->malloc(n);
1972 if (!p)
1973 return NULL;
1974 return (char *)memcpy(p, s, n);
1977 JS_PUBLIC_API(JSBool)
1978 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
1980 d = JS_CANONICALIZE_NAN(d);
1981 Valueify(rval)->setNumber(d);
1982 return JS_TRUE;
1985 #undef JS_AddRoot
1987 JS_PUBLIC_API(JSBool)
1988 JS_AddValueRoot(JSContext *cx, jsval *vp)
1990 CHECK_REQUEST(cx);
1991 return js_AddRoot(cx, Valueify(vp), NULL);
1994 JS_PUBLIC_API(JSBool)
1995 JS_AddStringRoot(JSContext *cx, JSString **rp)
1997 CHECK_REQUEST(cx);
1998 return js_AddGCThingRoot(cx, (void **)rp, NULL);
2001 JS_PUBLIC_API(JSBool)
2002 JS_AddObjectRoot(JSContext *cx, JSObject **rp)
2004 CHECK_REQUEST(cx);
2005 return js_AddGCThingRoot(cx, (void **)rp, NULL);
2008 JS_PUBLIC_API(JSBool)
2009 JS_AddGCThingRoot(JSContext *cx, void **rp)
2011 CHECK_REQUEST(cx);
2012 return js_AddGCThingRoot(cx, (void **)rp, NULL);
2015 JS_PUBLIC_API(JSBool)
2016 JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name)
2018 CHECK_REQUEST(cx);
2019 return js_AddRoot(cx, Valueify(vp), name);
2022 JS_PUBLIC_API(JSBool)
2023 JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name)
2025 CHECK_REQUEST(cx);
2026 return js_AddGCThingRoot(cx, (void **)rp, name);
2029 JS_PUBLIC_API(JSBool)
2030 JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name)
2032 CHECK_REQUEST(cx);
2033 return js_AddGCThingRoot(cx, (void **)rp, name);
2036 JS_PUBLIC_API(JSBool)
2037 JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name)
2039 CHECK_REQUEST(cx);
2040 return js_AddGCThingRoot(cx, (void **)rp, name);
2043 JS_PUBLIC_API(JSBool)
2044 JS_RemoveValueRoot(JSContext *cx, jsval *vp)
2046 CHECK_REQUEST(cx);
2047 return js_RemoveRoot(cx->runtime, (void *)vp);
2050 JS_PUBLIC_API(JSBool)
2051 JS_RemoveStringRoot(JSContext *cx, JSString **rp)
2053 CHECK_REQUEST(cx);
2054 return js_RemoveRoot(cx->runtime, (void *)rp);
2057 JS_PUBLIC_API(JSBool)
2058 JS_RemoveObjectRoot(JSContext *cx, JSObject **rp)
2060 CHECK_REQUEST(cx);
2061 return js_RemoveRoot(cx->runtime, (void *)rp);
2064 JS_PUBLIC_API(JSBool)
2065 JS_RemoveGCThingRoot(JSContext *cx, void **rp)
2067 CHECK_REQUEST(cx);
2068 return js_RemoveRoot(cx->runtime, (void *)rp);
2071 #ifdef DEBUG
2073 JS_PUBLIC_API(void)
2074 JS_DumpNamedRoots(JSRuntime *rt,
2075 void (*dump)(const char *name, void *rp, JSGCRootType type, void *data),
2076 void *data)
2078 js_DumpNamedRoots(rt, dump, data);
2081 #endif /* DEBUG */
2083 JS_PUBLIC_API(uint32)
2084 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
2086 return js_MapGCRoots(rt, map, data);
2089 JS_PUBLIC_API(JSBool)
2090 JS_LockGCThing(JSContext *cx, void *thing)
2092 JSBool ok;
2094 CHECK_REQUEST(cx);
2095 ok = js_LockGCThingRT(cx->runtime, thing);
2096 if (!ok)
2097 JS_ReportOutOfMemory(cx);
2098 return ok;
2101 JS_PUBLIC_API(JSBool)
2102 JS_LockGCThingRT(JSRuntime *rt, void *thing)
2104 return js_LockGCThingRT(rt, thing);
2107 JS_PUBLIC_API(JSBool)
2108 JS_UnlockGCThing(JSContext *cx, void *thing)
2110 CHECK_REQUEST(cx);
2111 js_UnlockGCThingRT(cx->runtime, thing);
2112 return true;
2115 JS_PUBLIC_API(JSBool)
2116 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
2118 js_UnlockGCThingRT(rt, thing);
2119 return true;
2122 JS_PUBLIC_API(void)
2123 JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
2125 rt->gcExtraRootsTraceOp = traceOp;
2126 rt->gcExtraRootsData = data;
2129 JS_PUBLIC_API(void)
2130 JS_TraceRuntime(JSTracer *trc)
2132 TraceRuntime(trc);
2135 JS_PUBLIC_API(void)
2136 JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
2138 JS_ASSERT(thing);
2139 MarkKind(trc, thing, kind);
2142 #ifdef DEBUG
2144 #ifdef HAVE_XPCONNECT
2145 #include "dump_xpc.h"
2146 #endif
2148 JS_PUBLIC_API(void)
2149 JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, uint32 kind,
2150 JSBool details)
2152 const char *name;
2153 size_t n;
2155 if (bufsize == 0)
2156 return;
2158 switch (kind) {
2159 case JSTRACE_OBJECT:
2161 JSObject *obj = (JSObject *)thing;
2162 Class *clasp = obj->getClass();
2164 name = clasp->name;
2165 #ifdef HAVE_XPCONNECT
2166 if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
2167 void *privateThing = obj->getPrivate();
2168 if (privateThing) {
2169 const char *xpcClassName = GetXPCObjectClassName(privateThing);
2170 if (xpcClassName)
2171 name = xpcClassName;
2174 #endif
2175 break;
2178 case JSTRACE_STRING:
2179 name = ((JSString *)thing)->isDependent()
2180 ? "substring"
2181 : "string";
2182 break;
2184 #if JS_HAS_XML_SUPPORT
2185 case JSTRACE_XML:
2186 name = "xml";
2187 break;
2188 #endif
2189 default:
2190 JS_ASSERT(0);
2191 return;
2192 break;
2195 n = strlen(name);
2196 if (n > bufsize - 1)
2197 n = bufsize - 1;
2198 memcpy(buf, name, n + 1);
2199 buf += n;
2200 bufsize -= n;
2202 if (details && bufsize > 2) {
2203 *buf++ = ' ';
2204 bufsize--;
2206 switch (kind) {
2207 case JSTRACE_OBJECT:
2209 JSObject *obj = (JSObject *)thing;
2210 Class *clasp = obj->getClass();
2211 if (clasp == &js_FunctionClass) {
2212 JSFunction *fun = GET_FUNCTION_PRIVATE(trc->context, obj);
2213 if (!fun) {
2214 JS_snprintf(buf, bufsize, "<newborn>");
2215 } else if (FUN_OBJECT(fun) != obj) {
2216 JS_snprintf(buf, bufsize, "%p", fun);
2217 } else {
2218 if (fun->atom)
2219 PutEscapedString(buf, bufsize, ATOM_TO_STRING(fun->atom), 0);
2221 } else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
2222 JS_snprintf(buf, bufsize, "%p", obj->getPrivate());
2223 } else {
2224 JS_snprintf(buf, bufsize, "<no private>");
2226 break;
2229 case JSTRACE_STRING:
2231 JSString *str = (JSString *)thing;
2232 if (str->isLinear())
2233 PutEscapedString(buf, bufsize, str->assertIsLinear(), 0);
2234 else
2235 JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
2236 break;
2239 #if JS_HAS_XML_SUPPORT
2240 case JSTRACE_XML:
2242 extern const char *js_xml_class_str[];
2243 JSXML *xml = (JSXML *)thing;
2245 JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]);
2246 break;
2248 #endif
2249 default:
2250 JS_ASSERT(0);
2251 break;
2254 buf[bufsize - 1] = '\0';
2257 typedef struct JSHeapDumpNode JSHeapDumpNode;
2259 struct JSHeapDumpNode {
2260 void *thing;
2261 uint32 kind;
2262 JSHeapDumpNode *next; /* next sibling */
2263 JSHeapDumpNode *parent; /* node with the thing that refer to thing
2264 from this node */
2265 char edgeName[1]; /* name of the edge from parent->thing
2266 into thing */
2269 typedef struct JSDumpingTracer {
2270 JSTracer base;
2271 JSDHashTable visited;
2272 JSBool ok;
2273 void *startThing;
2274 void *thingToFind;
2275 void *thingToIgnore;
2276 JSHeapDumpNode *parentNode;
2277 JSHeapDumpNode **lastNodep;
2278 char buffer[200];
2279 } JSDumpingTracer;
2281 static void
2282 DumpNotify(JSTracer *trc, void *thing, uint32 kind)
2284 JSDumpingTracer *dtrc;
2285 JSContext *cx;
2286 JSDHashEntryStub *entry;
2287 JSHeapDumpNode *node;
2288 const char *edgeName;
2289 size_t edgeNameSize;
2291 JS_ASSERT(trc->callback == DumpNotify);
2292 dtrc = (JSDumpingTracer *)trc;
2294 if (!dtrc->ok || thing == dtrc->thingToIgnore)
2295 return;
2297 cx = trc->context;
2300 * Check if we have already seen thing unless it is thingToFind to include
2301 * it to the graph each time we reach it and print all live things that
2302 * refer to thingToFind.
2304 * This does not print all possible paths leading to thingToFind since
2305 * when a thing A refers directly or indirectly to thingToFind and A is
2306 * present several times in the graph, we will print only the first path
2307 * leading to A and thingToFind, other ways to reach A will be ignored.
2309 if (dtrc->thingToFind != thing) {
2311 * The startThing check allows to avoid putting startThing into the
2312 * hash table before tracing startThing in JS_DumpHeap.
2314 if (thing == dtrc->startThing)
2315 return;
2316 entry = (JSDHashEntryStub *)
2317 JS_DHashTableOperate(&dtrc->visited, thing, JS_DHASH_ADD);
2318 if (!entry) {
2319 JS_ReportOutOfMemory(cx);
2320 dtrc->ok = JS_FALSE;
2321 return;
2323 if (entry->key)
2324 return;
2325 entry->key = thing;
2328 if (dtrc->base.debugPrinter) {
2329 dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer));
2330 edgeName = dtrc->buffer;
2331 } else if (dtrc->base.debugPrintIndex != (size_t)-1) {
2332 JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]",
2333 (const char *)dtrc->base.debugPrintArg,
2334 dtrc->base.debugPrintIndex);
2335 edgeName = dtrc->buffer;
2336 } else {
2337 edgeName = (const char*)dtrc->base.debugPrintArg;
2340 edgeNameSize = strlen(edgeName) + 1;
2341 node = (JSHeapDumpNode *)
2342 cx->malloc(offsetof(JSHeapDumpNode, edgeName) + edgeNameSize);
2343 if (!node) {
2344 dtrc->ok = JS_FALSE;
2345 return;
2348 node->thing = thing;
2349 node->kind = kind;
2350 node->next = NULL;
2351 node->parent = dtrc->parentNode;
2352 memcpy(node->edgeName, edgeName, edgeNameSize);
2354 JS_ASSERT(!*dtrc->lastNodep);
2355 *dtrc->lastNodep = node;
2356 dtrc->lastNodep = &node->next;
2359 /* Dump node and the chain that leads to thing it contains. */
2360 static JSBool
2361 DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
2363 JSHeapDumpNode *prev, *following;
2364 size_t chainLimit;
2365 JSBool ok;
2366 enum { MAX_PARENTS_TO_PRINT = 10 };
2368 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2369 &dtrc->base, node->thing, node->kind, JS_TRUE);
2370 if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
2371 return JS_FALSE;
2374 * We need to print the parent chain in the reverse order. To do it in
2375 * O(N) time where N is the chain length we first reverse the chain while
2376 * searching for the top and then print each node while restoring the
2377 * chain order.
2379 chainLimit = MAX_PARENTS_TO_PRINT;
2380 prev = NULL;
2381 for (;;) {
2382 following = node->parent;
2383 node->parent = prev;
2384 prev = node;
2385 node = following;
2386 if (!node)
2387 break;
2388 if (chainLimit == 0) {
2389 if (fputs("...", fp) < 0)
2390 return JS_FALSE;
2391 break;
2393 --chainLimit;
2396 node = prev;
2397 prev = following;
2398 ok = JS_TRUE;
2399 do {
2400 /* Loop must continue even when !ok to restore the parent chain. */
2401 if (ok) {
2402 if (!prev) {
2403 /* Print edge from some runtime root or startThing. */
2404 if (fputs(node->edgeName, fp) < 0)
2405 ok = JS_FALSE;
2406 } else {
2407 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2408 &dtrc->base, prev->thing, prev->kind,
2409 JS_FALSE);
2410 if (fprintf(fp, "(%p %s).%s",
2411 prev->thing, dtrc->buffer, node->edgeName) < 0) {
2412 ok = JS_FALSE;
2416 following = node->parent;
2417 node->parent = prev;
2418 prev = node;
2419 node = following;
2420 } while (node);
2422 return ok && putc('\n', fp) >= 0;
2425 JS_PUBLIC_API(JSBool)
2426 JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind,
2427 void *thingToFind, size_t maxDepth, void *thingToIgnore)
2429 JSDumpingTracer dtrc;
2430 JSHeapDumpNode *node, *children, *next, *parent;
2431 size_t depth;
2432 JSBool thingToFindWasTraced;
2434 if (maxDepth == 0)
2435 return JS_TRUE;
2437 JS_TRACER_INIT(&dtrc.base, cx, DumpNotify);
2438 if (!JS_DHashTableInit(&dtrc.visited, JS_DHashGetStubOps(),
2439 NULL, sizeof(JSDHashEntryStub),
2440 JS_DHASH_DEFAULT_CAPACITY(100))) {
2441 JS_ReportOutOfMemory(cx);
2442 return JS_FALSE;
2444 dtrc.ok = JS_TRUE;
2445 dtrc.startThing = startThing;
2446 dtrc.thingToFind = thingToFind;
2447 dtrc.thingToIgnore = thingToIgnore;
2448 dtrc.parentNode = NULL;
2449 node = NULL;
2450 dtrc.lastNodep = &node;
2451 if (!startThing) {
2452 JS_ASSERT(startKind == 0);
2453 TraceRuntime(&dtrc.base);
2454 } else {
2455 JS_TraceChildren(&dtrc.base, startThing, startKind);
2458 depth = 1;
2459 if (!node)
2460 goto dump_out;
2462 thingToFindWasTraced = thingToFind && thingToFind == startThing;
2463 for (;;) {
2465 * Loop must continue even when !dtrc.ok to free all nodes allocated
2466 * so far.
2468 if (dtrc.ok) {
2469 if (thingToFind == NULL || thingToFind == node->thing)
2470 dtrc.ok = DumpNode(&dtrc, fp, node);
2472 /* Descend into children. */
2473 if (dtrc.ok &&
2474 depth < maxDepth &&
2475 (thingToFind != node->thing || !thingToFindWasTraced)) {
2476 dtrc.parentNode = node;
2477 children = NULL;
2478 dtrc.lastNodep = &children;
2479 JS_TraceChildren(&dtrc.base, node->thing, node->kind);
2480 if (thingToFind == node->thing)
2481 thingToFindWasTraced = JS_TRUE;
2482 if (children != NULL) {
2483 ++depth;
2484 node = children;
2485 continue;
2490 /* Move to next or parents next and free the node. */
2491 for (;;) {
2492 next = node->next;
2493 parent = node->parent;
2494 cx->free(node);
2495 node = next;
2496 if (node)
2497 break;
2498 if (!parent)
2499 goto dump_out;
2500 JS_ASSERT(depth > 1);
2501 --depth;
2502 node = parent;
2506 dump_out:
2507 JS_ASSERT(depth == 1);
2508 JS_DHashTableFinish(&dtrc.visited);
2509 return dtrc.ok;
2512 #endif /* DEBUG */
2514 JS_PUBLIC_API(void)
2515 JS_MarkGCThing(JSContext *cx, jsval v, const char *name, void *arg)
2517 JSTracer *trc;
2519 trc = (JSTracer *)arg;
2520 if (!trc)
2521 trc = cx->runtime->gcMarkingTracer;
2522 else
2523 JS_ASSERT(trc == cx->runtime->gcMarkingTracer);
2525 #ifdef JS_THREADSAFE
2526 JS_ASSERT(cx->runtime->gcThread == trc->context->thread);
2527 #endif
2528 MarkValue(trc, Valueify(v), name ? name : "unknown");
2531 extern JS_PUBLIC_API(JSBool)
2532 JS_IsGCMarkingTracer(JSTracer *trc)
2534 return IS_GC_MARKING_TRACER(trc);
2537 JS_PUBLIC_API(void)
2538 JS_GC(JSContext *cx)
2540 LeaveTrace(cx);
2542 /* Don't nuke active arenas if executing or compiling. */
2543 if (cx->tempPool.current == &cx->tempPool.first)
2544 JS_FinishArenaPool(&cx->tempPool);
2545 js_GC(cx, NULL, GC_NORMAL);
2548 JS_PUBLIC_API(void)
2549 JS_MaybeGC(JSContext *cx)
2551 LeaveTrace(cx);
2553 /* Don't nuke active arenas if executing or compiling. */
2554 if (cx->tempPool.current == &cx->tempPool.first)
2555 JS_FinishArenaPool(&cx->tempPool);
2557 MaybeGC(cx);
2560 JS_PUBLIC_API(JSGCCallback)
2561 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
2563 CHECK_REQUEST(cx);
2564 return JS_SetGCCallbackRT(cx->runtime, cb);
2567 JS_PUBLIC_API(JSGCCallback)
2568 JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
2570 JSGCCallback oldcb;
2572 oldcb = rt->gcCallback;
2573 rt->gcCallback = cb;
2574 return oldcb;
2577 JS_PUBLIC_API(JSBool)
2578 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
2580 JS_ASSERT(thing);
2581 JS_ASSERT(!cx->runtime->gcMarkingTracer);
2582 return IsAboutToBeFinalized(cx, thing);
2585 JS_PUBLIC_API(void)
2586 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
2588 switch (key) {
2589 case JSGC_MAX_BYTES:
2590 rt->gcMaxBytes = value;
2591 break;
2592 case JSGC_MAX_MALLOC_BYTES:
2593 rt->setGCMaxMallocBytes(value);
2594 break;
2595 case JSGC_STACKPOOL_LIFESPAN:
2596 rt->gcEmptyArenaPoolLifespan = value;
2597 break;
2598 case JSGC_MODE:
2599 rt->gcMode = JSGCMode(value);
2600 JS_ASSERT(rt->gcMode == JSGC_MODE_GLOBAL ||
2601 rt->gcMode == JSGC_MODE_COMPARTMENT);
2602 break;
2603 default:
2604 JS_ASSERT(key == JSGC_TRIGGER_FACTOR);
2605 JS_ASSERT(value >= 100);
2606 rt->setGCTriggerFactor(value);
2607 return;
2611 JS_PUBLIC_API(uint32)
2612 JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
2614 switch (key) {
2615 case JSGC_MAX_BYTES:
2616 return rt->gcMaxBytes;
2617 case JSGC_MAX_MALLOC_BYTES:
2618 return rt->gcMaxMallocBytes;
2619 case JSGC_STACKPOOL_LIFESPAN:
2620 return rt->gcEmptyArenaPoolLifespan;
2621 case JSGC_TRIGGER_FACTOR:
2622 return rt->gcTriggerFactor;
2623 case JSGC_BYTES:
2624 return rt->gcBytes;
2625 case JSGC_MODE:
2626 return uint32(rt->gcMode);
2627 default:
2628 JS_ASSERT(key == JSGC_NUMBER);
2629 return rt->gcNumber;
2633 JS_PUBLIC_API(void)
2634 JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32 value)
2636 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2637 #ifdef JS_TRACER
2638 SetMaxCodeCacheBytes(cx, value);
2639 #endif
2642 JS_PUBLIC_API(uint32)
2643 JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key)
2645 JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2646 #ifdef JS_TRACER
2647 return JS_THREAD_DATA(cx)->maxCodeCacheBytes;
2648 #else
2649 return 0;
2650 #endif
2653 JS_PUBLIC_API(void)
2654 JS_FlushCaches(JSContext *cx)
2656 #ifdef JS_TRACER
2657 FlushJITCache(cx);
2658 #endif
2661 JS_PUBLIC_API(intN)
2662 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
2664 return JSExternalString::changeFinalizer(NULL, finalizer);
2667 JS_PUBLIC_API(intN)
2668 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
2670 return JSExternalString::changeFinalizer(finalizer, NULL);
2673 JS_PUBLIC_API(JSString *)
2674 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
2676 CHECK_REQUEST(cx);
2677 JS_ASSERT(uintN(type) < JSExternalString::TYPE_LIMIT);
2679 JSExternalString *str = js_NewGCExternalString(cx, uintN(type));
2680 if (!str)
2681 return NULL;
2682 str->initFlat(chars, length);
2683 str->externalStringType = type;
2684 cx->runtime->updateMallocCounter((length + 1) * sizeof(jschar));
2685 return str;
2688 JS_PUBLIC_API(intN)
2689 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
2692 * No need to test this in js_GetExternalStringGCType, which asserts its
2693 * inverse instead of wasting cycles on testing a condition we can ensure
2694 * by auditing in-VM calls to the js_... helper.
2696 if (JSString::isStatic(str))
2697 return -1;
2699 return js_GetExternalStringGCType(str);
2702 JS_PUBLIC_API(void)
2703 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
2705 #if JS_STACK_GROWTH_DIRECTION > 0
2706 if (limitAddr == 0)
2707 limitAddr = jsuword(-1);
2708 #endif
2709 cx->stackLimit = limitAddr;
2712 JS_PUBLIC_API(void)
2713 JS_SetNativeStackQuota(JSContext *cx, size_t stackSize)
2715 #ifdef JS_THREADSAFE
2716 JS_ASSERT(cx->thread);
2717 #endif
2719 #if JS_STACK_GROWTH_DIRECTION > 0
2720 if (stackSize == 0) {
2721 cx->stackLimit = jsuword(-1);
2722 } else {
2723 jsuword stackBase = reinterpret_cast<jsuword>(JS_THREAD_DATA(cx)->nativeStackBase);
2724 JS_ASSERT(stackBase <= size_t(-1) - stackSize);
2725 cx->stackLimit = stackBase + stackSize - 1;
2727 #else
2728 if (stackSize == 0) {
2729 cx->stackLimit = 0;
2730 } else {
2731 jsuword stackBase = reinterpret_cast<jsuword>(JS_THREAD_DATA(cx)->nativeStackBase);
2732 JS_ASSERT(stackBase >= stackSize);
2733 cx->stackLimit = stackBase - (stackSize - 1);
2735 #endif
2738 JS_PUBLIC_API(void)
2739 JS_SetScriptStackQuota(JSContext *cx, size_t quota)
2741 cx->scriptStackQuota = quota;
2744 /************************************************************************/
2746 JS_PUBLIC_API(void)
2747 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
2749 cx->free(ida);
2752 JS_PUBLIC_API(JSBool)
2753 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
2755 CHECK_REQUEST(cx);
2756 assertSameCompartment(cx, v);
2757 return ValueToId(cx, Valueify(v), idp);
2760 JS_PUBLIC_API(JSBool)
2761 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
2763 CHECK_REQUEST(cx);
2764 *vp = IdToJsval(id);
2765 assertSameCompartment(cx, *vp);
2766 return JS_TRUE;
2769 JS_PUBLIC_API(JSBool)
2770 JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
2772 return JS_TRUE;
2775 JS_PUBLIC_API(JSBool)
2776 JS_EnumerateStub(JSContext *cx, JSObject *obj)
2778 return JS_TRUE;
2781 JS_PUBLIC_API(JSBool)
2782 JS_ResolveStub(JSContext *cx, JSObject *obj, jsid id)
2784 return JS_TRUE;
2787 JS_PUBLIC_API(JSBool)
2788 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
2790 JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION);
2791 return js_TryValueOf(cx, obj, type, Valueify(vp));
2794 JS_PUBLIC_API(void)
2795 JS_FinalizeStub(JSContext *cx, JSObject *obj)
2798 JS_PUBLIC_API(JSObject *)
2799 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
2800 JSClass *clasp, JSNative constructor, uintN nargs,
2801 JSPropertySpec *ps, JSFunctionSpec *fs,
2802 JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
2804 CHECK_REQUEST(cx);
2805 assertSameCompartment(cx, obj, parent_proto);
2806 return js_InitClass(cx, obj, parent_proto, Valueify(clasp),
2807 Valueify(constructor), nargs,
2808 ps, fs, static_ps, static_fs);
2811 #ifdef JS_THREADSAFE
2812 JS_PUBLIC_API(JSClass *)
2813 JS_GetClass(JSContext *cx, JSObject *obj)
2815 return Jsvalify(obj->getClass());
2817 #else
2818 JS_PUBLIC_API(JSClass *)
2819 JS_GetClass(JSObject *obj)
2821 return Jsvalify(obj->getClass());
2823 #endif
2825 JS_PUBLIC_API(JSBool)
2826 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2828 CHECK_REQUEST(cx);
2829 assertSameCompartment(cx, obj);
2830 return InstanceOf(cx, obj, Valueify(clasp), Valueify(argv));
2833 JS_PUBLIC_API(JSBool)
2834 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
2836 assertSameCompartment(cx, obj, v);
2837 return HasInstance(cx, obj, Valueify(&v), bp);
2840 JS_PUBLIC_API(void *)
2841 JS_GetPrivate(JSContext *cx, JSObject *obj)
2843 return obj->getPrivate();
2846 JS_PUBLIC_API(JSBool)
2847 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2849 obj->setPrivate(data);
2850 return true;
2853 JS_PUBLIC_API(void *)
2854 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2856 if (!InstanceOf(cx, obj, Valueify(clasp), Valueify(argv)))
2857 return NULL;
2858 return obj->getPrivate();
2861 JS_PUBLIC_API(JSObject *)
2862 JS_GetPrototype(JSContext *cx, JSObject *obj)
2864 JSObject *proto;
2866 CHECK_REQUEST(cx);
2867 assertSameCompartment(cx, obj);
2868 proto = obj->getProto();
2870 /* Beware ref to dead object (we may be called from obj's finalizer). */
2871 return proto && proto->map ? proto : NULL;
2874 JS_PUBLIC_API(JSBool)
2875 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
2877 CHECK_REQUEST(cx);
2878 assertSameCompartment(cx, obj, proto);
2879 return SetProto(cx, obj, proto, JS_FALSE);
2882 JS_PUBLIC_API(JSObject *)
2883 JS_GetParent(JSContext *cx, JSObject *obj)
2885 assertSameCompartment(cx, obj);
2886 JSObject *parent = obj->getParent();
2888 /* Beware ref to dead object (we may be called from obj's finalizer). */
2889 return parent && parent->map ? parent : NULL;
2892 JS_PUBLIC_API(JSBool)
2893 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
2895 CHECK_REQUEST(cx);
2896 JS_ASSERT(parent || !obj->getParent());
2897 assertSameCompartment(cx, obj, parent);
2898 obj->setParent(parent);
2899 return true;
2902 JS_PUBLIC_API(JSObject *)
2903 JS_GetConstructor(JSContext *cx, JSObject *proto)
2905 Value cval;
2907 CHECK_REQUEST(cx);
2908 assertSameCompartment(cx, proto);
2910 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
2912 if (!proto->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), &cval))
2913 return NULL;
2915 JSObject *funobj;
2916 if (!IsFunctionObject(cval, &funobj)) {
2917 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
2918 proto->getClass()->name);
2919 return NULL;
2921 return &cval.toObject();
2924 JS_PUBLIC_API(JSBool)
2925 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
2927 assertSameCompartment(cx, obj);
2928 *idp = OBJECT_TO_JSID(obj);
2929 return JS_TRUE;
2932 JS_PUBLIC_API(JSObject *)
2933 JS_NewGlobalObject(JSContext *cx, JSClass *clasp)
2935 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
2936 CHECK_REQUEST(cx);
2937 JS_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
2938 JSObject *obj = NewNonFunction<WithProto::Given>(cx, Valueify(clasp), NULL, NULL);
2939 if (!obj)
2940 return NULL;
2942 obj->syncSpecialEquality();
2944 /* Construct a regexp statics object for this global object. */
2945 JSObject *res = regexp_statics_construct(cx, obj);
2946 if (!res ||
2947 !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_REGEXP_STATICS,
2948 ObjectValue(*res))) {
2949 return NULL;
2952 return obj;
2955 JS_PUBLIC_API(JSObject *)
2956 JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals)
2958 CHECK_REQUEST(cx);
2959 JSCompartment *compartment = NewCompartment(cx, principals);
2960 if (!compartment)
2961 return NULL;
2963 JSCompartment *saved = cx->compartment;
2964 cx->compartment = compartment;
2965 JSObject *obj = JS_NewGlobalObject(cx, clasp);
2966 cx->compartment = saved;
2968 return obj;
2971 JS_PUBLIC_API(JSObject *)
2972 JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
2974 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
2975 CHECK_REQUEST(cx);
2976 assertSameCompartment(cx, proto, parent);
2978 Class *clasp = Valueify(jsclasp);
2979 if (!clasp)
2980 clasp = &js_ObjectClass; /* default class is Object */
2982 JS_ASSERT(clasp != &js_FunctionClass);
2983 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
2985 JSObject *obj = NewNonFunction<WithProto::Class>(cx, clasp, proto, parent);
2986 if (obj)
2987 obj->syncSpecialEquality();
2989 JS_ASSERT_IF(obj, obj->getParent());
2990 return obj;
2993 JS_PUBLIC_API(JSObject *)
2994 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
2996 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
2997 CHECK_REQUEST(cx);
2998 assertSameCompartment(cx, proto, parent);
3000 Class *clasp = Valueify(jsclasp);
3001 if (!clasp)
3002 clasp = &js_ObjectClass; /* default class is Object */
3004 JS_ASSERT(clasp != &js_FunctionClass);
3005 JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
3007 JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
3008 if (obj)
3009 obj->syncSpecialEquality();
3010 return obj;
3013 JS_PUBLIC_API(JSObject *)
3014 JS_NewObjectForConstructor(JSContext *cx, const jsval *vp)
3016 CHECK_REQUEST(cx);
3017 assertSameCompartment(cx, *vp);
3019 return js_CreateThis(cx, JSVAL_TO_OBJECT(*vp));
3022 JS_PUBLIC_API(JSBool)
3023 JS_IsExtensible(JSObject *obj)
3025 return obj->isExtensible();
3028 JS_PUBLIC_API(JSBool)
3029 JS_FreezeObject(JSContext *cx, JSObject *obj)
3031 CHECK_REQUEST(cx);
3032 assertSameCompartment(cx, obj);
3034 return obj->freeze(cx);
3037 JS_PUBLIC_API(JSBool)
3038 JS_DeepFreezeObject(JSContext *cx, JSObject *obj)
3040 CHECK_REQUEST(cx);
3041 assertSameCompartment(cx, obj);
3043 /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */
3044 if (!obj->isExtensible())
3045 return true;
3047 if (!obj->freeze(cx))
3048 return false;
3050 /* Walk slots in obj and if any value is a non-null object, seal it. */
3051 for (uint32 i = 0, n = obj->slotSpan(); i < n; ++i) {
3052 const Value &v = obj->getSlot(i);
3053 if (v.isPrimitive())
3054 continue;
3055 if (!JS_DeepFreezeObject(cx, &v.toObject()))
3056 return false;
3059 return true;
3062 JS_PUBLIC_API(JSObject *)
3063 JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
3065 CHECK_REQUEST(cx);
3066 assertSameCompartment(cx, proto, parent);
3067 Class *clasp = Valueify(jsclasp);
3068 if (!clasp)
3069 clasp = &js_ObjectClass; /* default class is Object */
3070 return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
3073 JS_PUBLIC_API(JSObject *)
3074 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *proto,
3075 JSObject *parent, uintN argc, jsval *argv)
3077 CHECK_REQUEST(cx);
3078 assertSameCompartment(cx, proto, parent, JSValueArray(argv, argc));
3079 Class *clasp = Valueify(jsclasp);
3080 if (!clasp)
3081 clasp = &js_ObjectClass; /* default class is Object */
3082 return js_ConstructObject(cx, clasp, proto, parent, argc, Valueify(argv));
3085 static JSBool
3086 LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3087 JSObject **objp, JSProperty **propp)
3089 CHECK_REQUEST(cx);
3090 assertSameCompartment(cx, obj, id);
3092 JSAutoResolveFlags rf(cx, flags);
3093 id = js_CheckForStringIndex(id);
3094 return obj->lookupProperty(cx, id, objp, propp);
3097 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
3099 static JSBool
3100 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, jsid id,
3101 JSProperty *prop, Value *vp)
3103 if (!prop) {
3104 /* XXX bad API: no way to tell "not defined" from "void value" */
3105 vp->setUndefined();
3106 return JS_TRUE;
3109 if (obj2->isNative()) {
3110 Shape *shape = (Shape *) prop;
3112 if (shape->isMethod()) {
3113 AutoShapeRooter root(cx, shape);
3114 vp->setObject(shape->methodObject());
3115 return obj2->methodReadBarrier(cx, *shape, vp);
3118 /* Peek at the native property's slot value, without doing a Get. */
3119 if (obj2->containsSlot(shape->slot)) {
3120 *vp = obj2->nativeGetSlot(shape->slot);
3121 return true;
3123 } else {
3124 if (obj2->isDenseArray())
3125 return js_GetDenseArrayElementValue(cx, obj2, id, vp);
3126 if (obj2->isProxy()) {
3127 AutoPropertyDescriptorRooter desc(cx);
3128 if (!JSProxy::getPropertyDescriptor(cx, obj2, id, false, &desc))
3129 return false;
3130 if (!(desc.attrs & JSPROP_SHARED)) {
3131 *vp = desc.value;
3132 return true;
3137 /* XXX bad API: no way to return "defined but value unknown" */
3138 vp->setBoolean(true);
3139 return true;
3142 JS_PUBLIC_API(JSBool)
3143 JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3145 JSObject *obj2;
3146 JSProperty *prop;
3147 return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) &&
3148 LookupResult(cx, obj, obj2, id, prop, Valueify(vp));
3151 JS_PUBLIC_API(JSBool)
3152 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3154 return JS_LookupPropertyById(cx, obj, INT_TO_JSID(index), vp);
3157 JS_PUBLIC_API(JSBool)
3158 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3160 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3161 return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3164 JS_PUBLIC_API(JSBool)
3165 JS_LookupUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3167 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3168 return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3171 JS_PUBLIC_API(JSBool)
3172 JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3173 JSObject **objp, jsval *vp)
3175 JSBool ok;
3176 JSProperty *prop;
3178 CHECK_REQUEST(cx);
3179 assertSameCompartment(cx, obj, id);
3180 ok = obj->isNative()
3181 ? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0
3182 : obj->lookupProperty(cx, id, objp, &prop);
3183 return ok && LookupResult(cx, obj, *objp, id, prop, Valueify(vp));
3186 JS_PUBLIC_API(JSBool)
3187 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, uintN flags, jsval *vp)
3189 JSObject *obj2;
3190 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3191 return atom && JS_LookupPropertyWithFlagsById(cx, obj, ATOM_TO_JSID(atom), flags, &obj2, vp);
3194 JS_PUBLIC_API(JSBool)
3195 JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3197 JSObject *obj2;
3198 JSProperty *prop;
3199 JSBool ok = LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3200 &obj2, &prop);
3201 *foundp = (prop != NULL);
3202 return ok;
3205 JS_PUBLIC_API(JSBool)
3206 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3208 return JS_HasPropertyById(cx, obj, INT_TO_JSID(index), foundp);
3211 JS_PUBLIC_API(JSBool)
3212 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3214 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3215 return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3218 JS_PUBLIC_API(JSBool)
3219 JS_HasUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, JSBool *foundp)
3221 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3222 return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3225 JS_PUBLIC_API(JSBool)
3226 JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3228 CHECK_REQUEST(cx);
3229 assertSameCompartment(cx, obj, id);
3231 if (!obj->isNative()) {
3232 JSObject *obj2;
3233 JSProperty *prop;
3235 if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3236 &obj2, &prop)) {
3237 return JS_FALSE;
3239 *foundp = (obj == obj2);
3240 return JS_TRUE;
3243 *foundp = obj->nativeContains(id);
3244 return JS_TRUE;
3247 JS_PUBLIC_API(JSBool)
3248 JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3250 return JS_AlreadyHasOwnPropertyById(cx, obj, INT_TO_JSID(index), foundp);
3253 JS_PUBLIC_API(JSBool)
3254 JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3256 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3257 return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3260 JS_PUBLIC_API(JSBool)
3261 JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3262 JSBool *foundp)
3264 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3265 return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3268 static JSBool
3269 DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value,
3270 PropertyOp getter, PropertyOp setter, uintN attrs,
3271 uintN flags, intN tinyid)
3273 CHECK_REQUEST(cx);
3274 assertSameCompartment(cx, obj, id, value,
3275 (attrs & JSPROP_GETTER)
3276 ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
3277 : NULL,
3278 (attrs & JSPROP_SETTER)
3279 ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
3280 : NULL);
3282 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
3283 if (flags != 0 && obj->isNative()) {
3284 return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter,
3285 attrs, flags, tinyid, NULL);
3287 return obj->defineProperty(cx, id, value, getter, setter, attrs);
3290 JS_PUBLIC_API(JSBool)
3291 JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
3292 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3294 return DefinePropertyById(cx, obj, id, Valueify(value), Valueify(getter),
3295 Valueify(setter), attrs, 0, 0);
3298 JS_PUBLIC_API(JSBool)
3299 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
3300 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3302 return DefinePropertyById(cx, obj, INT_TO_JSID(index), Valueify(value),
3303 Valueify(getter), Valueify(setter), attrs, 0, 0);
3306 static JSBool
3307 DefineProperty(JSContext *cx, JSObject *obj, const char *name, const Value &value,
3308 PropertyOp getter, PropertyOp setter, uintN attrs,
3309 uintN flags, intN tinyid)
3311 jsid id;
3312 JSAtom *atom;
3314 if (attrs & JSPROP_INDEX) {
3315 id = INT_TO_JSID(intptr_t(name));
3316 atom = NULL;
3317 attrs &= ~JSPROP_INDEX;
3318 } else {
3319 atom = js_Atomize(cx, name, strlen(name), 0);
3320 if (!atom)
3321 return JS_FALSE;
3322 id = ATOM_TO_JSID(atom);
3324 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid);
3327 JS_PUBLIC_API(JSBool)
3328 JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
3329 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3331 return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter),
3332 Valueify(setter), attrs, 0, 0);
3335 JS_PUBLIC_API(JSBool)
3336 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, int8 tinyid,
3337 jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3339 return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter),
3340 Valueify(setter), attrs, Shape::HAS_SHORTID, tinyid);
3343 static JSBool
3344 DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3345 const Value &value, PropertyOp getter, PropertyOp setter, uintN attrs,
3346 uintN flags, intN tinyid)
3348 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3349 return atom && DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs,
3350 flags, tinyid);
3353 JS_PUBLIC_API(JSBool)
3354 JS_DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3355 jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3357 return DefineUCProperty(cx, obj, name, namelen, Valueify(value),
3358 Valueify(getter), Valueify(setter), attrs, 0, 0);
3361 JS_PUBLIC_API(JSBool)
3362 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3363 int8 tinyid, jsval value, JSPropertyOp getter, JSPropertyOp setter,
3364 uintN attrs)
3366 return DefineUCProperty(cx, obj, name, namelen, Valueify(value), Valueify(getter),
3367 Valueify(setter), attrs, Shape::HAS_SHORTID, tinyid);
3370 JS_PUBLIC_API(JSBool)
3371 JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp)
3373 CHECK_REQUEST(cx);
3374 assertSameCompartment(cx, obj, id, descriptor);
3375 return js_DefineOwnProperty(cx, obj, id, Valueify(descriptor), bp);
3378 JS_PUBLIC_API(JSObject *)
3379 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp,
3380 JSObject *proto, uintN attrs)
3382 CHECK_REQUEST(cx);
3383 assertSameCompartment(cx, obj, proto);
3385 Class *clasp = Valueify(jsclasp);
3386 if (!clasp)
3387 clasp = &js_ObjectClass; /* default class is Object */
3389 JSObject *nobj = NewObject<WithProto::Class>(cx, clasp, proto, obj);
3390 if (!nobj)
3391 return NULL;
3393 nobj->syncSpecialEquality();
3395 if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
3396 return NULL;
3398 return nobj;
3401 JS_PUBLIC_API(JSBool)
3402 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
3404 JSBool ok;
3405 uintN attrs;
3407 CHECK_REQUEST(cx);
3408 for (ok = JS_TRUE; cds->name; cds++) {
3409 Value value = DoubleValue(cds->dval);
3410 attrs = cds->flags;
3411 if (!attrs)
3412 attrs = JSPROP_READONLY | JSPROP_PERMANENT;
3413 ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
3414 if (!ok)
3415 break;
3417 return ok;
3420 JS_PUBLIC_API(JSBool)
3421 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
3423 JSBool ok;
3425 for (ok = true; ps->name; ps++) {
3426 ok = DefineProperty(cx, obj, ps->name, UndefinedValue(),
3427 Valueify(ps->getter), Valueify(ps->setter),
3428 ps->flags, Shape::HAS_SHORTID, ps->tinyid);
3429 if (!ok)
3430 break;
3432 return ok;
3435 JS_PUBLIC_API(JSBool)
3436 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *alias)
3438 JSObject *obj2;
3439 JSProperty *prop;
3440 JSBool ok;
3441 Shape *shape;
3443 CHECK_REQUEST(cx);
3444 assertSameCompartment(cx, obj);
3446 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3447 if (!atom)
3448 return JS_FALSE;
3449 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
3450 return JS_FALSE;
3451 if (!prop) {
3452 js_ReportIsNotDefined(cx, name);
3453 return JS_FALSE;
3455 if (obj2 != obj || !obj->isNative()) {
3456 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3457 alias, name, obj2->getClass()->name);
3458 return JS_FALSE;
3460 atom = js_Atomize(cx, alias, strlen(alias), 0);
3461 if (!atom) {
3462 ok = JS_FALSE;
3463 } else {
3464 shape = (Shape *)prop;
3465 ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
3466 shape->getter(), shape->setter(), shape->slot,
3467 shape->attributes(), shape->getFlags() | Shape::ALIAS,
3468 shape->shortid)
3469 != NULL);
3471 return ok;
3474 JS_PUBLIC_API(JSBool)
3475 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
3477 JSObject *obj2;
3478 JSProperty *prop;
3479 Shape *shape;
3481 CHECK_REQUEST(cx);
3482 assertSameCompartment(cx, obj);
3484 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3485 if (!atom)
3486 return JS_FALSE;
3487 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
3488 return JS_FALSE;
3489 if (!prop) {
3490 js_ReportIsNotDefined(cx, name);
3491 return JS_FALSE;
3493 if (obj2 != obj || !obj->isNative()) {
3494 char numBuf[12];
3495 JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
3496 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3497 numBuf, name, obj2->getClass()->name);
3498 return JS_FALSE;
3500 shape = (Shape *)prop;
3501 return js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
3502 shape->getter(), shape->setter(), shape->slot,
3503 shape->attributes(), shape->getFlags() | Shape::ALIAS,
3504 shape->shortid)
3505 != NULL;
3508 static JSBool
3509 GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3510 JSBool own, PropertyDescriptor *desc)
3512 JSObject *obj2;
3513 JSProperty *prop;
3515 if (!LookupPropertyById(cx, obj, id, flags, &obj2, &prop))
3516 return JS_FALSE;
3518 if (!prop || (own && obj != obj2)) {
3519 desc->obj = NULL;
3520 desc->attrs = 0;
3521 desc->getter = NULL;
3522 desc->setter = NULL;
3523 desc->value.setUndefined();
3524 return JS_TRUE;
3527 desc->obj = obj2;
3528 if (obj2->isNative()) {
3529 Shape *shape = (Shape *) prop;
3530 desc->attrs = shape->attributes();
3532 if (shape->isMethod()) {
3533 desc->getter = desc->setter = PropertyStub;
3534 desc->value.setObject(shape->methodObject());
3535 } else {
3536 desc->getter = shape->getter();
3537 desc->setter = shape->setter();
3538 if (obj2->containsSlot(shape->slot))
3539 desc->value = obj2->nativeGetSlot(shape->slot);
3540 else
3541 desc->value.setUndefined();
3543 } else {
3544 if (obj2->isProxy()) {
3545 JSAutoResolveFlags rf(cx, flags);
3546 return own
3547 ? JSProxy::getOwnPropertyDescriptor(cx, obj2, id, false, desc)
3548 : JSProxy::getPropertyDescriptor(cx, obj2, id, false, desc);
3550 if (!obj2->getAttributes(cx, id, &desc->attrs))
3551 return false;
3552 desc->getter = NULL;
3553 desc->setter = NULL;
3554 desc->value.setUndefined();
3556 return true;
3559 JS_PUBLIC_API(JSBool)
3560 JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3561 JSPropertyDescriptor *desc)
3563 return GetPropertyDescriptorById(cx, obj, id, flags, JS_FALSE, Valueify(desc));
3566 JS_PUBLIC_API(JSBool)
3567 JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *obj, jsid id,
3568 uintN *attrsp, JSBool *foundp,
3569 JSPropertyOp *getterp, JSPropertyOp *setterp)
3571 PropertyDescriptor desc;
3572 if (!GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, JS_FALSE, &desc))
3573 return false;
3575 *attrsp = desc.attrs;
3576 *foundp = (desc.obj != NULL);
3577 if (getterp)
3578 *getterp = Jsvalify(desc.getter);
3579 if (setterp)
3580 *setterp = Jsvalify(desc.setter);
3581 return true;
3584 JS_PUBLIC_API(JSBool)
3585 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3586 uintN *attrsp, JSBool *foundp)
3588 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3589 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3590 attrsp, foundp, NULL, NULL);
3593 JS_PUBLIC_API(JSBool)
3594 JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3595 uintN *attrsp, JSBool *foundp)
3597 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3598 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3599 attrsp, foundp, NULL, NULL);
3602 JS_PUBLIC_API(JSBool)
3603 JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, const char *name,
3604 uintN *attrsp, JSBool *foundp,
3605 JSPropertyOp *getterp, JSPropertyOp *setterp)
3607 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3608 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3609 attrsp, foundp, getterp, setterp);
3612 JS_PUBLIC_API(JSBool)
3613 JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
3614 const jschar *name, size_t namelen,
3615 uintN *attrsp, JSBool *foundp,
3616 JSPropertyOp *getterp, JSPropertyOp *setterp)
3618 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3619 return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3620 attrsp, foundp, getterp, setterp);
3623 JS_PUBLIC_API(JSBool)
3624 JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3626 CHECK_REQUEST(cx);
3627 return js_GetOwnPropertyDescriptor(cx, obj, id, Valueify(vp));
3630 static JSBool
3631 SetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, uintN attrs, JSBool *foundp)
3633 JSObject *obj2;
3634 JSProperty *prop;
3636 if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
3637 return false;
3638 if (!prop || obj != obj2) {
3639 *foundp = false;
3640 return true;
3642 JSBool ok = obj->isNative()
3643 ? js_SetNativeAttributes(cx, obj, (Shape *) prop, attrs)
3644 : obj->setAttributes(cx, id, &attrs);
3645 if (ok)
3646 *foundp = true;
3647 return ok;
3650 JS_PUBLIC_API(JSBool)
3651 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3652 uintN attrs, JSBool *foundp)
3654 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3655 return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
3658 JS_PUBLIC_API(JSBool)
3659 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3660 uintN attrs, JSBool *foundp)
3662 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3663 return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
3666 JS_PUBLIC_API(JSBool)
3667 JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3669 CHECK_REQUEST(cx);
3670 assertSameCompartment(cx, obj, id);
3671 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3672 return obj->getProperty(cx, id, Valueify(vp));
3675 JS_PUBLIC_API(JSBool)
3676 JS_GetPropertyByIdDefault(JSContext *cx, JSObject *obj, jsid id, jsval def, jsval *vp)
3678 return GetPropertyDefault(cx, obj, id, Valueify(def), Valueify(vp));
3681 JS_PUBLIC_API(JSBool)
3682 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3684 return JS_GetPropertyById(cx, obj, INT_TO_JSID(index), vp);
3687 JS_PUBLIC_API(JSBool)
3688 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3690 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3691 return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3694 JS_PUBLIC_API(JSBool)
3695 JS_GetPropertyDefault(JSContext *cx, JSObject *obj, const char *name, jsval def, jsval *vp)
3697 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3698 return atom && JS_GetPropertyByIdDefault(cx, obj, ATOM_TO_JSID(atom), def, vp);
3701 JS_PUBLIC_API(JSBool)
3702 JS_GetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3704 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3705 return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3708 JS_PUBLIC_API(JSBool)
3709 JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval *vp)
3711 CHECK_REQUEST(cx);
3712 assertSameCompartment(cx, obj, id);
3713 if (!js_GetMethod(cx, obj, id, JSGET_METHOD_BARRIER, Valueify(vp)))
3714 return JS_FALSE;
3715 if (objp)
3716 *objp = obj;
3717 return JS_TRUE;
3720 JS_PUBLIC_API(JSBool)
3721 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, jsval *vp)
3723 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3724 return atom && JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), objp, vp);
3727 JS_PUBLIC_API(JSBool)
3728 JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3730 CHECK_REQUEST(cx);
3731 assertSameCompartment(cx, obj, id);
3732 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
3733 return obj->setProperty(cx, id, Valueify(vp), false);
3736 JS_PUBLIC_API(JSBool)
3737 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3739 return JS_SetPropertyById(cx, obj, INT_TO_JSID(index), vp);
3742 JS_PUBLIC_API(JSBool)
3743 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3745 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3746 return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3749 JS_PUBLIC_API(JSBool)
3750 JS_SetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3752 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3753 return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3756 JS_PUBLIC_API(JSBool)
3757 JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
3759 CHECK_REQUEST(cx);
3760 assertSameCompartment(cx, obj, id);
3761 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3762 return obj->deleteProperty(cx, id, Valueify(rval), false);
3765 JS_PUBLIC_API(JSBool)
3766 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
3768 return JS_DeletePropertyById2(cx, obj, INT_TO_JSID(index), rval);
3771 JS_PUBLIC_API(JSBool)
3772 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name, jsval *rval)
3774 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3775 return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
3778 JS_PUBLIC_API(JSBool)
3779 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *rval)
3781 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3782 return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
3785 JS_PUBLIC_API(JSBool)
3786 JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id)
3788 jsval junk;
3789 return JS_DeletePropertyById2(cx, obj, id, &junk);
3792 JS_PUBLIC_API(JSBool)
3793 JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
3795 jsval junk;
3796 return JS_DeleteElement2(cx, obj, index, &junk);
3799 JS_PUBLIC_API(JSBool)
3800 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
3802 jsval junk;
3803 return JS_DeleteProperty2(cx, obj, name, &junk);
3806 JS_PUBLIC_API(void)
3807 JS_ClearScope(JSContext *cx, JSObject *obj)
3809 CHECK_REQUEST(cx);
3810 assertSameCompartment(cx, obj);
3812 JSFinalizeOp clearOp = obj->getOps()->clear;
3813 if (clearOp)
3814 clearOp(cx, obj);
3816 if (obj->isNative())
3817 js_ClearNative(cx, obj);
3819 /* Clear cached class objects on the global object. */
3820 if (obj->isGlobal()) {
3821 for (int key = JSProto_Null; key < JSProto_LIMIT * 3; key++)
3822 JS_SetReservedSlot(cx, obj, key, JSVAL_VOID);
3825 js_InitRandom(cx);
3828 JS_PUBLIC_API(JSIdArray *)
3829 JS_Enumerate(JSContext *cx, JSObject *obj)
3831 CHECK_REQUEST(cx);
3832 assertSameCompartment(cx, obj);
3834 AutoIdVector props(cx);
3835 JSIdArray *ida;
3836 if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida))
3837 return false;
3838 for (size_t n = 0; n < size_t(ida->length); ++n)
3839 JS_ASSERT(js_CheckForStringIndex(ida->vector[n]) == ida->vector[n]);
3840 return ida;
3844 * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
3845 * prop_iterator_class somehow...
3846 * + preserve the obj->enumerate API while optimizing the native object case
3847 * + native case here uses a Shape *, but that iterates in reverse!
3848 * + so we make non-native match, by reverse-iterating after JS_Enumerating
3850 const uint32 JSSLOT_ITER_INDEX = 0;
3852 static void
3853 prop_iter_finalize(JSContext *cx, JSObject *obj)
3855 void *pdata = obj->getPrivate();
3856 if (!pdata)
3857 return;
3859 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) {
3860 /* Non-native case: destroy the ida enumerated when obj was created. */
3861 JSIdArray *ida = (JSIdArray *) pdata;
3862 JS_DestroyIdArray(cx, ida);
3866 static void
3867 prop_iter_trace(JSTracer *trc, JSObject *obj)
3869 void *pdata = obj->getPrivate();
3870 if (!pdata)
3871 return;
3873 if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
3874 /* Native case: just mark the next property to visit. */
3875 ((Shape *) pdata)->trace(trc);
3876 } else {
3877 /* Non-native case: mark each id in the JSIdArray private. */
3878 JSIdArray *ida = (JSIdArray *) pdata;
3879 MarkIdRange(trc, ida->length, ida->vector, "prop iter");
3883 static Class prop_iter_class = {
3884 "PropertyIterator",
3885 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
3886 JSCLASS_MARK_IS_TRACE,
3887 PropertyStub, /* addProperty */
3888 PropertyStub, /* delProperty */
3889 PropertyStub, /* getProperty */
3890 PropertyStub, /* setProperty */
3891 EnumerateStub,
3892 ResolveStub,
3893 ConvertStub,
3894 prop_iter_finalize,
3895 NULL, /* reserved0 */
3896 NULL, /* checkAccess */
3897 NULL, /* call */
3898 NULL, /* construct */
3899 NULL, /* xdrObject */
3900 NULL, /* hasInstance */
3901 JS_CLASS_TRACE(prop_iter_trace)
3904 JS_PUBLIC_API(JSObject *)
3905 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
3907 JSObject *iterobj;
3908 const void *pdata;
3909 jsint index;
3910 JSIdArray *ida;
3912 CHECK_REQUEST(cx);
3913 assertSameCompartment(cx, obj);
3914 iterobj = NewNonFunction<WithProto::Class>(cx, &prop_iter_class, NULL, obj);
3915 if (!iterobj)
3916 return NULL;
3918 if (obj->isNative()) {
3919 /* Native case: start with the last property in obj. */
3920 pdata = obj->lastProperty();
3921 index = -1;
3922 } else {
3924 * Non-native case: enumerate a JSIdArray and keep it via private.
3926 * Note: we have to make sure that we root obj around the call to
3927 * JS_Enumerate to protect against multiple allocations under it.
3929 AutoObjectRooter tvr(cx, iterobj);
3930 ida = JS_Enumerate(cx, obj);
3931 if (!ida)
3932 return NULL;
3933 pdata = ida;
3934 index = ida->length;
3937 /* iterobj cannot escape to other threads here. */
3938 iterobj->setPrivate(const_cast<void *>(pdata));
3939 iterobj->getSlotRef(JSSLOT_ITER_INDEX).setInt32(index);
3940 return iterobj;
3943 JS_PUBLIC_API(JSBool)
3944 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
3946 jsint i;
3947 const Shape *shape;
3948 JSIdArray *ida;
3950 CHECK_REQUEST(cx);
3951 assertSameCompartment(cx, iterobj);
3952 i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
3953 if (i < 0) {
3954 /* Native case: private data is a property tree node pointer. */
3955 JS_ASSERT(iterobj->getParent()->isNative());
3956 shape = (Shape *) iterobj->getPrivate();
3958 while (shape->previous() && (!shape->enumerable() || shape->isAlias()))
3959 shape = shape->previous();
3961 if (!shape->previous()) {
3962 JS_ASSERT(JSID_IS_EMPTY(shape->id));
3963 *idp = JSID_VOID;
3964 } else {
3965 iterobj->setPrivate(const_cast<Shape *>(shape->previous()));
3966 *idp = shape->id;
3968 } else {
3969 /* Non-native case: use the ida enumerated when iterobj was created. */
3970 ida = (JSIdArray *) iterobj->getPrivate();
3971 JS_ASSERT(i <= ida->length);
3972 STATIC_ASSUME(i <= ida->length);
3973 if (i == 0) {
3974 *idp = JSID_VOID;
3975 } else {
3976 *idp = ida->vector[--i];
3977 iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i));
3980 return JS_TRUE;
3983 JS_PUBLIC_API(JSBool)
3984 JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
3986 CHECK_REQUEST(cx);
3987 assertSameCompartment(cx, obj);
3988 return js_GetReservedSlot(cx, obj, index, Valueify(vp));
3991 JS_PUBLIC_API(JSBool)
3992 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
3994 CHECK_REQUEST(cx);
3995 assertSameCompartment(cx, obj, v);
3996 return js_SetReservedSlot(cx, obj, index, Valueify(v));
3999 JS_PUBLIC_API(JSObject *)
4000 JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
4002 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4003 CHECK_REQUEST(cx);
4004 /* NB: jsuint cast does ToUint32. */
4005 assertSameCompartment(cx, JSValueArray(vector, vector ? (jsuint)length : 0));
4006 return NewDenseCopiedArray(cx, (jsuint)length, Valueify(vector));
4009 JS_PUBLIC_API(JSBool)
4010 JS_IsArrayObject(JSContext *cx, JSObject *obj)
4012 assertSameCompartment(cx, obj);
4013 return obj->isArray() ||
4014 (obj->isWrapper() && JSWrapper::wrappedObject(obj)->isArray());
4017 JS_PUBLIC_API(JSBool)
4018 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
4020 CHECK_REQUEST(cx);
4021 assertSameCompartment(cx, obj);
4022 return js_GetLengthProperty(cx, obj, lengthp);
4025 JS_PUBLIC_API(JSBool)
4026 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
4028 CHECK_REQUEST(cx);
4029 assertSameCompartment(cx, obj);
4030 return js_SetLengthProperty(cx, obj, length);
4033 JS_PUBLIC_API(JSBool)
4034 JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
4036 CHECK_REQUEST(cx);
4037 assertSameCompartment(cx, obj);
4038 return js_HasLengthProperty(cx, obj, lengthp);
4041 JS_PUBLIC_API(JSBool)
4042 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
4043 jsval *vp, uintN *attrsp)
4045 CHECK_REQUEST(cx);
4046 assertSameCompartment(cx, obj, id);
4047 return CheckAccess(cx, obj, id, mode, Valueify(vp), attrsp);
4050 #ifdef JS_THREADSAFE
4051 JS_PUBLIC_API(jsrefcount)
4052 JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
4054 return JS_ATOMIC_INCREMENT(&principals->refcount);
4057 JS_PUBLIC_API(jsrefcount)
4058 JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
4060 jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
4061 if (rc == 0)
4062 principals->destroy(cx, principals);
4063 return rc;
4065 #endif
4067 JS_PUBLIC_API(JSSecurityCallbacks *)
4068 JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks)
4070 JSSecurityCallbacks *oldcallbacks;
4072 oldcallbacks = rt->securityCallbacks;
4073 rt->securityCallbacks = callbacks;
4074 return oldcallbacks;
4077 JS_PUBLIC_API(JSSecurityCallbacks *)
4078 JS_GetRuntimeSecurityCallbacks(JSRuntime *rt)
4080 return rt->securityCallbacks;
4083 JS_PUBLIC_API(JSSecurityCallbacks *)
4084 JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks)
4086 JSSecurityCallbacks *oldcallbacks;
4088 oldcallbacks = cx->securityCallbacks;
4089 cx->securityCallbacks = callbacks;
4090 return oldcallbacks;
4093 JS_PUBLIC_API(JSSecurityCallbacks *)
4094 JS_GetSecurityCallbacks(JSContext *cx)
4096 return cx->securityCallbacks
4097 ? cx->securityCallbacks
4098 : cx->runtime->securityCallbacks;
4101 JS_PUBLIC_API(JSFunction *)
4102 JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
4103 JSObject *parent, const char *name)
4105 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4106 JSAtom *atom;
4108 CHECK_REQUEST(cx);
4109 assertSameCompartment(cx, parent);
4111 if (!name) {
4112 atom = NULL;
4113 } else {
4114 atom = js_Atomize(cx, name, strlen(name), 0);
4115 if (!atom)
4116 return NULL;
4118 return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, atom);
4121 JS_PUBLIC_API(JSFunction *)
4122 JS_NewFunctionById(JSContext *cx, JSNative native, uintN nargs, uintN flags, JSObject *parent,
4123 jsid id)
4125 JS_ASSERT(JSID_IS_STRING(id));
4126 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4127 CHECK_REQUEST(cx);
4128 assertSameCompartment(cx, parent);
4130 return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, JSID_TO_ATOM(id));
4133 JS_PUBLIC_API(JSObject *)
4134 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
4136 CHECK_REQUEST(cx);
4137 assertSameCompartment(cx, parent); // XXX no funobj for now
4138 if (!parent) {
4139 if (cx->hasfp())
4140 parent = GetScopeChain(cx, cx->fp());
4141 if (!parent)
4142 parent = cx->globalObject;
4143 JS_ASSERT(parent);
4146 if (funobj->getClass() != &js_FunctionClass) {
4148 * We cannot clone this object, so fail (we used to return funobj, bad
4149 * idea, but we changed incompatibly to teach any abusers a lesson!).
4151 Value v = ObjectValue(*funobj);
4152 js_ReportIsNotFunction(cx, &v, 0);
4153 return NULL;
4156 JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
4157 if (!FUN_FLAT_CLOSURE(fun))
4158 return CloneFunctionObject(cx, fun, parent);
4161 * A flat closure carries its own environment, so why clone it? In case
4162 * someone wants to mutate its fixed slots or add ad-hoc properties. API
4163 * compatibility suggests we not return funobj and let callers mutate the
4164 * returned object at will.
4166 * But it's worse than that: API compatibility according to the test for
4167 * bug 300079 requires we get "upvars" from parent and its ancestors! So
4168 * we do that (grudgingly!). The scope chain ancestors are searched as if
4169 * they were activations, respecting the skip field in each upvar's cookie
4170 * but looking up the property by name instead of frame slot.
4172 JSObject *clone = js_AllocFlatClosure(cx, fun, parent);
4173 if (!clone)
4174 return NULL;
4176 JSUpvarArray *uva = fun->u.i.script->upvars();
4177 uint32 i = uva->length;
4178 JS_ASSERT(i != 0);
4180 for (Shape::Range r(fun->script()->bindings.lastUpvar()); i-- != 0; r.popFront()) {
4181 JSObject *obj = parent;
4182 int skip = uva->vector[i].level();
4183 while (--skip > 0) {
4184 if (!obj) {
4185 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4186 JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
4187 return NULL;
4189 obj = obj->getParent();
4192 if (!obj->getProperty(cx, r.front().id, clone->getFlatClosureUpvars() + i))
4193 return NULL;
4196 return clone;
4199 JS_PUBLIC_API(JSObject *)
4200 JS_GetFunctionObject(JSFunction *fun)
4202 return FUN_OBJECT(fun);
4205 JS_PUBLIC_API(JSString *)
4206 JS_GetFunctionId(JSFunction *fun)
4208 return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
4211 JS_PUBLIC_API(uintN)
4212 JS_GetFunctionFlags(JSFunction *fun)
4214 return fun->flags;
4217 JS_PUBLIC_API(uint16)
4218 JS_GetFunctionArity(JSFunction *fun)
4220 return fun->nargs;
4223 JS_PUBLIC_API(JSBool)
4224 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
4226 return obj->getClass() == &js_FunctionClass;
4229 JS_PUBLIC_API(JSBool)
4230 JS_ObjectIsCallable(JSContext *cx, JSObject *obj)
4232 return obj->isCallable();
4235 static JSBool
4236 js_generic_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp)
4238 JSFunctionSpec *fs;
4239 JSObject *tmp;
4240 Native native;
4242 fs = (JSFunctionSpec *) vp->toObject().getReservedSlot(0).toPrivate();
4243 JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
4245 if (argc < 1) {
4246 js_ReportMissingArg(cx, *vp, 0);
4247 return JS_FALSE;
4250 if (vp[2].isPrimitive()) {
4252 * Make sure that this is an object or null, as required by the generic
4253 * functions.
4255 if (!js_ValueToObjectOrNull(cx, vp[2], &tmp))
4256 return JS_FALSE;
4257 vp[2].setObjectOrNull(tmp);
4261 * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
4262 * which is almost always the class constructor object, e.g. Array. Then
4263 * call the corresponding prototype native method with our first argument
4264 * passed as |this|.
4266 memmove(vp + 1, vp + 2, argc * sizeof(jsval));
4269 * Follow Function.prototype.apply and .call by using the global object as
4270 * the 'this' param if no args.
4272 if (!ComputeThisFromArgv(cx, vp + 2))
4273 return JS_FALSE;
4275 /* Clear the last parameter in case too few arguments were passed. */
4276 vp[2 + --argc].setUndefined();
4278 native =
4279 #ifdef JS_TRACER
4280 (fs->flags & JSFUN_TRCINFO)
4281 ? JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native
4283 #endif
4284 Valueify(fs->call);
4285 return native(cx, argc, vp);
4288 JS_PUBLIC_API(JSBool)
4289 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
4291 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4292 uintN flags;
4293 JSObject *ctor;
4294 JSFunction *fun;
4296 CHECK_REQUEST(cx);
4297 assertSameCompartment(cx, obj);
4298 ctor = NULL;
4299 for (; fs->name; fs++) {
4300 flags = fs->flags;
4303 * Define a generic arity N+1 static method for the arity N prototype
4304 * method if flags contains JSFUN_GENERIC_NATIVE.
4306 if (flags & JSFUN_GENERIC_NATIVE) {
4307 if (!ctor) {
4308 ctor = JS_GetConstructor(cx, obj);
4309 if (!ctor)
4310 return JS_FALSE;
4313 flags &= ~JSFUN_GENERIC_NATIVE;
4314 fun = JS_DefineFunction(cx, ctor, fs->name,
4315 Jsvalify(js_generic_native_method_dispatcher),
4316 fs->nargs + 1,
4317 flags & ~JSFUN_TRCINFO);
4318 if (!fun)
4319 return JS_FALSE;
4322 * As jsapi.h notes, fs must point to storage that lives as long
4323 * as fun->object lives.
4325 Value priv = PrivateValue(fs);
4326 if (!js_SetReservedSlot(cx, FUN_OBJECT(fun), 0, priv))
4327 return JS_FALSE;
4330 fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
4331 if (!fun)
4332 return JS_FALSE;
4334 return JS_TRUE;
4337 JS_PUBLIC_API(JSFunction *)
4338 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
4339 uintN nargs, uintN attrs)
4341 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4342 CHECK_REQUEST(cx);
4343 assertSameCompartment(cx, obj);
4344 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
4345 if (!atom)
4346 return NULL;
4347 return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs);
4350 JS_PUBLIC_API(JSFunction *)
4351 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
4352 const jschar *name, size_t namelen, JSNative call,
4353 uintN nargs, uintN attrs)
4355 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4356 CHECK_REQUEST(cx);
4357 assertSameCompartment(cx, obj);
4358 JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
4359 if (!atom)
4360 return NULL;
4361 return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs);
4364 extern JS_PUBLIC_API(JSFunction *)
4365 JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call,
4366 uintN nargs, uintN attrs)
4368 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4369 CHECK_REQUEST(cx);
4370 assertSameCompartment(cx, obj);
4371 return js_DefineFunction(cx, obj, id, Valueify(call), nargs, attrs);
4374 inline static void
4375 LAST_FRAME_EXCEPTION_CHECK(JSContext *cx, bool result)
4377 if (!result && !(cx->options & JSOPTION_DONT_REPORT_UNCAUGHT))
4378 js_ReportUncaughtException(cx);
4381 inline static void
4382 LAST_FRAME_CHECKS(JSContext *cx, bool result)
4384 if (!JS_IsRunning(cx)) {
4385 LAST_FRAME_EXCEPTION_CHECK(cx, result);
4389 inline static uint32
4390 JS_OPTIONS_TO_TCFLAGS(JSContext *cx)
4392 return ((cx->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) |
4393 ((cx->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0);
4396 extern JS_PUBLIC_API(JSScript *)
4397 JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4398 JSPrincipals *principals,
4399 const jschar *chars, size_t length,
4400 const char *filename, uintN lineno,
4401 JSVersion version)
4403 AutoVersionAPI avi(cx, version);
4404 return JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno);
4407 JS_PUBLIC_API(JSScript *)
4408 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4409 const jschar *chars, size_t length,
4410 const char *filename, uintN lineno)
4412 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4413 CHECK_REQUEST(cx);
4414 assertSameCompartment(cx, obj, principals);
4416 uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4417 JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
4418 chars, length, filename, lineno);
4419 if (script && !js_NewScriptObject(cx, script)) {
4420 js_DestroyScript(cx, script);
4421 script = NULL;
4423 LAST_FRAME_CHECKS(cx, script);
4424 return script;
4427 JS_PUBLIC_API(JSScript *)
4428 JS_CompileUCScript(JSContext *cx, JSObject *obj, const jschar *chars, size_t length,
4429 const char *filename, uintN lineno)
4431 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4432 return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno);
4435 JS_PUBLIC_API(JSScript *)
4436 JS_CompileScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4437 JSPrincipals *principals,
4438 const char *bytes, size_t length,
4439 const char *filename, uintN lineno,
4440 JSVersion version)
4442 AutoVersionAPI ava(cx, version);
4443 return JS_CompileScriptForPrincipals(cx, obj, principals, bytes, 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 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4453 CHECK_REQUEST(cx);
4455 jschar *chars = js_InflateString(cx, bytes, &length);
4456 if (!chars)
4457 return NULL;
4458 JSScript *script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno);
4459 cx->free(chars);
4460 return script;
4463 JS_PUBLIC_API(JSScript *)
4464 JS_CompileScript(JSContext *cx, JSObject *obj, const char *bytes, size_t length,
4465 const char *filename, uintN lineno)
4467 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4468 return JS_CompileScriptForPrincipals(cx, obj, NULL, bytes, length, filename, lineno);
4471 JS_PUBLIC_API(JSBool)
4472 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, const char *bytes, size_t length)
4474 jschar *chars;
4475 JSBool result;
4476 JSExceptionState *exnState;
4477 JSErrorReporter older;
4479 CHECK_REQUEST(cx);
4480 assertSameCompartment(cx, obj);
4481 chars = js_InflateString(cx, bytes, &length);
4482 if (!chars)
4483 return JS_TRUE;
4486 * Return true on any out-of-memory error, so our caller doesn't try to
4487 * collect more buffered source.
4489 result = JS_TRUE;
4490 exnState = JS_SaveExceptionState(cx);
4492 Parser parser(cx);
4493 if (parser.init(chars, length, NULL, 1)) {
4494 older = JS_SetErrorReporter(cx, NULL);
4495 if (!parser.parse(obj) &&
4496 parser.tokenStream.isUnexpectedEOF()) {
4498 * We ran into an error. If it was because we ran out of
4499 * source, we return false so our caller knows to try to
4500 * collect more buffered source.
4502 result = JS_FALSE;
4504 JS_SetErrorReporter(cx, older);
4507 cx->free(chars);
4508 JS_RestoreExceptionState(cx, exnState);
4509 return result;
4512 /* Use the fastest available getc. */
4513 #if defined(HAVE_GETC_UNLOCKED)
4514 # define fast_getc getc_unlocked
4515 #elif defined(HAVE__GETC_NOLOCK)
4516 # define fast_getc _getc_nolock
4517 #else
4518 # define fast_getc getc
4519 #endif
4521 static JSScript *
4522 CompileFileHelper(JSContext *cx, JSObject *obj, JSPrincipals *principals, uint32 tcflags,
4523 const char* filename, FILE *fp)
4525 struct stat st;
4526 int ok = fstat(fileno(fp), &st);
4527 if (ok != 0)
4528 return NULL;
4530 jschar *buf = NULL;
4531 size_t len = st.st_size;
4532 size_t i = 0;
4533 JSScript *script;
4535 /* Read in the whole file, then compile it. */
4536 if (fp == stdin) {
4537 JS_ASSERT(len == 0);
4538 len = 8; /* start with a small buffer, expand as necessary */
4539 int c;
4540 bool hitEOF = false;
4541 while (!hitEOF) {
4542 len *= 2;
4543 jschar* tmpbuf = (jschar *) cx->realloc(buf, len * sizeof(jschar));
4544 if (!tmpbuf) {
4545 cx->free(buf);
4546 return NULL;
4548 buf = tmpbuf;
4550 while (i < len) {
4551 c = fast_getc(fp);
4552 if (c == EOF) {
4553 hitEOF = true;
4554 break;
4556 buf[i++] = (jschar) (unsigned char) c;
4559 } else {
4560 buf = (jschar *) cx->malloc(len * sizeof(jschar));
4561 if (!buf)
4562 return NULL;
4564 int c;
4565 while ((c = fast_getc(fp)) != EOF)
4566 buf[i++] = (jschar) (unsigned char) c;
4569 JS_ASSERT(i <= len);
4570 len = i;
4571 script = Compiler::compileScript(cx, obj, NULL, principals, tcflags, buf, len, filename, 1);
4572 cx->free(buf);
4573 return script;
4576 JS_PUBLIC_API(JSScript *)
4577 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
4579 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4580 FILE *fp;
4581 uint32 tcflags;
4582 JSScript *script;
4584 CHECK_REQUEST(cx);
4585 assertSameCompartment(cx, obj);
4586 if (!filename || strcmp(filename, "-") == 0) {
4587 fp = stdin;
4588 } else {
4589 fp = fopen(filename, "r");
4590 if (!fp) {
4591 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
4592 filename, "No such file or directory");
4593 return NULL;
4597 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4598 script = CompileFileHelper(cx, obj, NULL, tcflags, filename, fp);
4600 if (fp != stdin)
4601 fclose(fp);
4602 if (script && !js_NewScriptObject(cx, script)) {
4603 js_DestroyScript(cx, script);
4604 script = NULL;
4606 LAST_FRAME_CHECKS(cx, script);
4607 return script;
4610 JS_PUBLIC_API(JSScript *)
4611 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *filename, FILE *file,
4612 JSPrincipals *principals)
4614 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4615 uint32 tcflags;
4616 JSScript *script;
4618 CHECK_REQUEST(cx);
4619 assertSameCompartment(cx, obj, principals);
4620 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4621 script = CompileFileHelper(cx, obj, principals, tcflags, filename, file);
4623 if (script && !js_NewScriptObject(cx, script)) {
4624 js_DestroyScript(cx, script);
4625 script = NULL;
4627 LAST_FRAME_CHECKS(cx, script);
4628 return script;
4631 JS_PUBLIC_API(JSScript *)
4632 JS_CompileFileHandleForPrincipalsVersion(JSContext *cx, JSObject *obj, const char *filename,
4633 FILE *file, JSPrincipals *principals, JSVersion version)
4635 AutoVersionAPI ava(cx, version);
4636 return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, principals);
4639 JS_PUBLIC_API(JSScript *)
4640 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *file)
4642 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4643 return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
4646 JS_PUBLIC_API(JSObject *)
4647 JS_NewScriptObject(JSContext *cx, JSScript *script)
4649 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4650 CHECK_REQUEST(cx);
4651 assertSameCompartment(cx, script);
4652 if (!script)
4653 return NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
4656 * This function should only ever be applied to JSScripts that had
4657 * script objects allocated for them when they were created, as
4658 * described in the comment for JSScript::u.object.
4660 JS_ASSERT(script->u.object);
4661 return script->u.object;
4664 JS_PUBLIC_API(JSObject *)
4665 JS_GetScriptObject(JSScript *script)
4668 * This function should only ever be applied to JSScripts that had
4669 * script objects allocated for them when they were created, as
4670 * described in the comment for JSScript::u.object.
4672 JS_ASSERT(script->u.object);
4673 return script->u.object;
4676 JS_PUBLIC_API(void)
4677 JS_DestroyScript(JSContext *cx, JSScript *script)
4679 CHECK_REQUEST(cx);
4682 * Originally, JSScript lifetimes were managed explicitly, and this function
4683 * was used to free a JSScript. Now, this function does nothing, and the
4684 * garbage collector manages JSScripts; you must root the JSScript's script
4685 * object (obtained via JS_GetScriptObject) to keep it alive.
4687 * However, since the script objects have taken over this responsibility, it
4688 * follows that every script passed here must have a script object.
4690 JS_ASSERT(script->u.object);
4693 JS_PUBLIC_API(JSFunction *)
4694 JS_CompileUCFunctionForPrincipalsVersion(JSContext *cx, JSObject *obj,
4695 JSPrincipals *principals, const char *name,
4696 uintN nargs, const char **argnames,
4697 const jschar *chars, size_t length,
4698 const char *filename, uintN lineno,
4699 JSVersion version)
4701 AutoVersionAPI avi(cx, version);
4702 return JS_CompileUCFunctionForPrincipals(cx, obj, principals, name, nargs, argnames, chars,
4703 length, filename, lineno);
4706 JS_PUBLIC_API(JSFunction *)
4707 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
4708 JSPrincipals *principals, const char *name,
4709 uintN nargs, const char **argnames,
4710 const jschar *chars, size_t length,
4711 const char *filename, uintN lineno)
4713 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4714 JSFunction *fun;
4715 JSAtom *funAtom, *argAtom;
4716 uintN i;
4718 CHECK_REQUEST(cx);
4719 assertSameCompartment(cx, obj, principals);
4720 if (!name) {
4721 funAtom = NULL;
4722 } else {
4723 funAtom = js_Atomize(cx, name, strlen(name), 0);
4724 if (!funAtom) {
4725 fun = NULL;
4726 goto out2;
4730 fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
4731 if (!fun)
4732 goto out2;
4735 AutoObjectRooter tvr(cx, FUN_OBJECT(fun));
4736 MUST_FLOW_THROUGH("out");
4738 Bindings bindings(cx);
4739 AutoBindingsRooter root(cx, bindings);
4740 for (i = 0; i < nargs; i++) {
4741 argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
4742 if (!argAtom) {
4743 fun = NULL;
4744 goto out2;
4747 uint16 dummy;
4748 if (!bindings.addArgument(cx, argAtom, &dummy)) {
4749 fun = NULL;
4750 goto out2;
4754 if (!Compiler::compileFunctionBody(cx, fun, principals, &bindings,
4755 chars, length, filename, lineno)) {
4756 fun = NULL;
4757 goto out2;
4760 if (obj && funAtom &&
4761 !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), ObjectValue(*fun),
4762 NULL, NULL, JSPROP_ENUMERATE)) {
4763 fun = NULL;
4766 #ifdef JS_SCOPE_DEPTH_METER
4767 if (fun && obj) {
4768 JSObject *pobj = obj;
4769 uintN depth = 1;
4771 while ((pobj = pobj->getParent()) != NULL)
4772 ++depth;
4773 JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
4775 #endif
4778 out2:
4779 LAST_FRAME_CHECKS(cx, fun);
4780 return fun;
4783 JS_PUBLIC_API(JSFunction *)
4784 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
4785 uintN nargs, const char **argnames,
4786 const jschar *chars, size_t length,
4787 const char *filename, uintN lineno)
4789 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4790 return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames,
4791 chars, length, filename, lineno);
4794 JS_PUBLIC_API(JSFunction *)
4795 JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
4796 JSPrincipals *principals, const char *name,
4797 uintN nargs, const char **argnames,
4798 const char *bytes, size_t length,
4799 const char *filename, uintN lineno)
4801 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4802 jschar *chars = js_InflateString(cx, bytes, &length);
4803 if (!chars)
4804 return NULL;
4805 JSFunction *fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
4806 nargs, argnames, chars, length,
4807 filename, lineno);
4808 cx->free(chars);
4809 return fun;
4812 JS_PUBLIC_API(JSFunction *)
4813 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
4814 uintN nargs, const char **argnames,
4815 const char *bytes, size_t length,
4816 const char *filename, uintN lineno)
4818 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4819 return JS_CompileFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames, bytes, length,
4820 filename, lineno);
4823 JS_PUBLIC_API(JSString *)
4824 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, uintN indent)
4826 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4827 JSPrinter *jp;
4828 JSString *str;
4830 CHECK_REQUEST(cx);
4831 #ifdef DEBUG
4832 if (cx->compartment != script->compartment)
4833 CompartmentChecker::fail(cx->compartment, script->compartment);
4834 #endif
4835 jp = js_NewPrinter(cx, name, NULL,
4836 indent & ~JS_DONT_PRETTY_PRINT,
4837 !(indent & JS_DONT_PRETTY_PRINT),
4838 false, false);
4839 if (!jp)
4840 return NULL;
4841 if (js_DecompileScript(jp, script))
4842 str = js_GetPrinterOutput(jp);
4843 else
4844 str = NULL;
4845 js_DestroyPrinter(jp);
4846 return str;
4849 JS_PUBLIC_API(JSString *)
4850 JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
4852 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4853 CHECK_REQUEST(cx);
4854 assertSameCompartment(cx, fun);
4855 return js_DecompileToString(cx, "JS_DecompileFunction", fun,
4856 indent & ~JS_DONT_PRETTY_PRINT,
4857 !(indent & JS_DONT_PRETTY_PRINT),
4858 false, false, js_DecompileFunction);
4861 JS_PUBLIC_API(JSString *)
4862 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
4864 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4865 CHECK_REQUEST(cx);
4866 assertSameCompartment(cx, fun);
4867 return js_DecompileToString(cx, "JS_DecompileFunctionBody", fun,
4868 indent & ~JS_DONT_PRETTY_PRINT,
4869 !(indent & JS_DONT_PRETTY_PRINT),
4870 false, false, js_DecompileFunctionBody);
4873 JS_PUBLIC_API(JSBool)
4874 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
4876 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4877 JSBool ok;
4879 CHECK_REQUEST(cx);
4880 assertSameCompartment(cx, obj, script);
4881 /* This should receive only scripts handed out via the JSAPI. */
4882 JS_ASSERT(script->u.object);
4883 ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
4884 LAST_FRAME_CHECKS(cx, ok);
4885 return ok;
4888 JS_PUBLIC_API(JSBool)
4889 JS_ExecuteScriptVersion(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval,
4890 JSVersion version)
4892 AutoVersionAPI ava(cx, version);
4893 return JS_ExecuteScript(cx, obj, script, rval);
4897 JS_PUBLIC_API(JSBool)
4898 JS_EvaluateUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4899 JSPrincipals *principals,
4900 const jschar *chars, uintN length,
4901 const char *filename, uintN lineno,
4902 jsval *rval, JSVersion version)
4904 AutoVersionAPI avi(cx, version);
4905 return JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno,
4906 rval);
4909 JS_PUBLIC_API(JSBool)
4910 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
4911 JSPrincipals *principals,
4912 const jschar *chars, uintN length,
4913 const char *filename, uintN lineno,
4914 jsval *rval)
4916 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4917 JSScript *script;
4918 JSBool ok;
4920 CHECK_REQUEST(cx);
4921 script = Compiler::compileScript(cx, obj, NULL, principals,
4922 !rval
4923 ? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
4924 : TCF_COMPILE_N_GO,
4925 chars, length, filename, lineno);
4926 if (!script) {
4927 LAST_FRAME_CHECKS(cx, script);
4928 return JS_FALSE;
4930 ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
4931 LAST_FRAME_CHECKS(cx, ok);
4932 js_DestroyScript(cx, script);
4933 return ok;
4936 JS_PUBLIC_API(JSBool)
4937 JS_EvaluateUCScript(JSContext *cx, JSObject *obj, const jschar *chars, uintN length,
4938 const char *filename, uintN lineno, jsval *rval)
4940 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4941 return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno, rval);
4944 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
4945 JS_PUBLIC_API(JSBool)
4946 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4947 const char *bytes, uintN nbytes,
4948 const char *filename, uintN lineno, jsval *rval)
4950 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4951 size_t length = nbytes;
4952 jschar *chars = js_InflateString(cx, bytes, &length);
4953 if (!chars)
4954 return JS_FALSE;
4955 JSBool ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
4956 filename, lineno, rval);
4957 cx->free(chars);
4958 return ok;
4961 JS_PUBLIC_API(JSBool)
4962 JS_EvaluateScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4963 const char *bytes, uintN nbytes,
4964 const char *filename, uintN lineno, jsval *rval, JSVersion version)
4966 AutoVersionAPI avi(cx, version);
4967 return JS_EvaluateScriptForPrincipals(cx, obj, principals, bytes, nbytes, filename, lineno,
4968 rval);
4971 JS_PUBLIC_API(JSBool)
4972 JS_EvaluateScript(JSContext *cx, JSObject *obj, const char *bytes, uintN nbytes,
4973 const char *filename, uintN lineno, jsval *rval)
4975 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4976 return JS_EvaluateScriptForPrincipals(cx, obj, NULL, bytes, nbytes, filename, lineno, rval);
4979 JS_PUBLIC_API(JSBool)
4980 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, jsval *argv,
4981 jsval *rval)
4983 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4984 JSBool ok;
4986 CHECK_REQUEST(cx);
4987 assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc));
4988 ok = ExternalInvoke(cx, obj, ObjectValue(*fun), argc, Valueify(argv), Valueify(rval));
4989 LAST_FRAME_CHECKS(cx, ok);
4990 return ok;
4993 JS_PUBLIC_API(JSBool)
4994 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, jsval *argv,
4995 jsval *rval)
4997 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
4998 CHECK_REQUEST(cx);
4999 assertSameCompartment(cx, obj, JSValueArray(argv, argc));
5001 AutoValueRooter tvr(cx);
5002 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
5003 JSBool ok = atom &&
5004 js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, tvr.addr()) &&
5005 ExternalInvoke(cx, obj, tvr.value(), argc, Valueify(argv), Valueify(rval));
5006 LAST_FRAME_CHECKS(cx, ok);
5007 return ok;
5010 JS_PUBLIC_API(JSBool)
5011 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, jsval *argv,
5012 jsval *rval)
5014 JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->defaultCompartment);
5015 JSBool ok;
5017 CHECK_REQUEST(cx);
5018 assertSameCompartment(cx, obj, fval, JSValueArray(argv, argc));
5019 ok = ExternalInvoke(cx, obj, Valueify(fval), argc, Valueify(argv), Valueify(rval));
5020 LAST_FRAME_CHECKS(cx, ok);
5021 return ok;
5024 namespace JS {
5026 JS_PUBLIC_API(bool)
5027 Call(JSContext *cx, jsval thisv, jsval fval, uintN argc, jsval *argv, jsval *rval)
5029 JSBool ok;
5031 CHECK_REQUEST(cx);
5032 assertSameCompartment(cx, thisv, fval, JSValueArray(argv, argc));
5033 ok = ExternalInvoke(cx, Valueify(thisv), Valueify(fval), argc, Valueify(argv), Valueify(rval));
5034 LAST_FRAME_CHECKS(cx, ok);
5035 return ok;
5038 } // namespace JS
5040 JS_PUBLIC_API(JSObject *)
5041 JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv)
5043 CHECK_REQUEST(cx);
5044 assertSameCompartment(cx, ctor, JSValueArray(argv, argc));
5046 // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
5047 // is not a simple variation of JSOP_CALL. We have to determine what class
5048 // of object to create, create it, and clamp the return value to an object,
5049 // among other details. js_InvokeConstructor does the hard work.
5050 InvokeArgsGuard args;
5051 if (!cx->stack().pushInvokeArgs(cx, argc, &args))
5052 return NULL;
5054 args.callee().setObject(*ctor);
5055 args.thisv().setNull();
5056 memcpy(args.argv(), argv, argc * sizeof(jsval));
5058 bool ok = InvokeConstructor(cx, args);
5060 JSObject *obj = NULL;
5061 if (ok) {
5062 if (args.rval().isObject()) {
5063 obj = &args.rval().toObject();
5064 } else {
5066 * Although constructors may return primitives (via proxies), this
5067 * API is asking for an object, so we report an error.
5069 JSAutoByteString bytes;
5070 if (js_ValueToPrintable(cx, args.rval(), &bytes)) {
5071 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_NEW_RESULT,
5072 bytes.ptr());
5077 LAST_FRAME_CHECKS(cx, ok);
5078 return obj;
5081 JS_PUBLIC_API(JSOperationCallback)
5082 JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback)
5084 #ifdef JS_THREADSAFE
5085 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
5086 #endif
5087 JSOperationCallback old = cx->operationCallback;
5088 cx->operationCallback = callback;
5089 return old;
5092 JS_PUBLIC_API(JSOperationCallback)
5093 JS_GetOperationCallback(JSContext *cx)
5095 return cx->operationCallback;
5098 JS_PUBLIC_API(void)
5099 JS_TriggerOperationCallback(JSContext *cx)
5101 #ifdef JS_THREADSAFE
5102 AutoLockGC lock(cx->runtime);
5103 #endif
5104 TriggerOperationCallback(cx);
5107 JS_PUBLIC_API(void)
5108 JS_TriggerAllOperationCallbacks(JSRuntime *rt)
5110 #ifdef JS_THREADSAFE
5111 AutoLockGC lock(rt);
5112 #endif
5113 TriggerAllOperationCallbacks(rt);
5116 JS_PUBLIC_API(JSBool)
5117 JS_IsRunning(JSContext *cx)
5120 * The use of cx->fp below is safe. Rationale: Here we don't care if the
5121 * interpreter state is stale. We just want to know if there *is* any
5122 * interpreter state.
5124 VOUCH_DOES_NOT_REQUIRE_STACK();
5126 #ifdef JS_TRACER
5127 JS_ASSERT_IF(cx->compartment &&
5128 JS_TRACE_MONITOR(cx).tracecx == cx, cx->hasfp());
5129 #endif
5130 JSStackFrame *fp = cx->maybefp();
5131 while (fp && fp->isDummyFrame())
5132 fp = fp->prev();
5133 return fp != NULL;
5136 JS_PUBLIC_API(JSStackFrame *)
5137 JS_SaveFrameChain(JSContext *cx)
5139 CHECK_REQUEST(cx);
5140 JSStackFrame *fp = js_GetTopStackFrame(cx);
5141 if (!fp)
5142 return NULL;
5143 cx->saveActiveSegment();
5144 return fp;
5147 JS_PUBLIC_API(void)
5148 JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
5150 CHECK_REQUEST(cx);
5151 JS_ASSERT_NOT_ON_TRACE(cx);
5152 JS_ASSERT(!cx->hasfp());
5153 if (!fp)
5154 return;
5155 cx->restoreSegment();
5156 cx->resetCompartment();
5159 /************************************************************************/
5160 JS_PUBLIC_API(JSString *)
5161 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
5163 CHECK_REQUEST(cx);
5164 return js_NewStringCopyN(cx, s, n);
5167 JS_PUBLIC_API(JSString *)
5168 JS_NewStringCopyZ(JSContext *cx, const char *s)
5170 size_t n;
5171 jschar *js;
5172 JSString *str;
5174 CHECK_REQUEST(cx);
5175 if (!s)
5176 return cx->runtime->emptyString;
5177 n = strlen(s);
5178 js = js_InflateString(cx, s, &n);
5179 if (!js)
5180 return NULL;
5181 str = js_NewString(cx, js, n);
5182 if (!str)
5183 cx->free(js);
5184 return str;
5187 JS_PUBLIC_API(JSBool)
5188 JS_StringHasBeenInterned(JSString *str)
5190 return str->isAtomized();
5193 JS_PUBLIC_API(JSString *)
5194 JS_InternJSString(JSContext *cx, JSString *str)
5196 CHECK_REQUEST(cx);
5197 JSAtom *atom = js_AtomizeString(cx, str, 0);
5198 if (!atom)
5199 return NULL;
5200 return ATOM_TO_STRING(atom);
5203 JS_PUBLIC_API(JSString *)
5204 JS_InternString(JSContext *cx, const char *s)
5206 JSAtom *atom;
5208 CHECK_REQUEST(cx);
5209 atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
5210 if (!atom)
5211 return NULL;
5212 return ATOM_TO_STRING(atom);
5215 JS_PUBLIC_API(JSString *)
5216 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
5218 CHECK_REQUEST(cx);
5219 return js_NewString(cx, chars, length);
5222 JS_PUBLIC_API(JSString *)
5223 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
5225 CHECK_REQUEST(cx);
5226 return js_NewStringCopyN(cx, s, n);
5229 JS_PUBLIC_API(JSString *)
5230 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
5232 CHECK_REQUEST(cx);
5233 if (!s)
5234 return cx->runtime->emptyString;
5235 return js_NewStringCopyZ(cx, s);
5238 JS_PUBLIC_API(JSString *)
5239 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
5241 JSAtom *atom;
5243 CHECK_REQUEST(cx);
5244 atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
5245 if (!atom)
5246 return NULL;
5247 return ATOM_TO_STRING(atom);
5250 JS_PUBLIC_API(JSString *)
5251 JS_InternUCString(JSContext *cx, const jschar *s)
5253 return JS_InternUCStringN(cx, s, js_strlen(s));
5256 JS_PUBLIC_API(size_t)
5257 JS_GetStringLength(JSString *str)
5259 return str->length();
5262 JS_PUBLIC_API(const jschar *)
5263 JS_GetStringCharsZ(JSContext *cx, JSString *str)
5265 CHECK_REQUEST(cx);
5266 assertSameCompartment(cx, str);
5267 return str->getCharsZ(cx);
5270 JS_PUBLIC_API(const jschar *)
5271 JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength)
5273 CHECK_REQUEST(cx);
5274 assertSameCompartment(cx, str);
5275 *plength = str->length();
5276 return str->getCharsZ(cx);
5279 JS_PUBLIC_API(const jschar *)
5280 JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
5282 CHECK_REQUEST(cx);
5283 assertSameCompartment(cx, str);
5284 *plength = str->length();
5285 return str->getChars(cx);
5288 JS_PUBLIC_API(const jschar *)
5289 JS_GetInternedStringChars(JSString *str)
5291 JS_ASSERT(str->isAtomized());
5292 return str->flatChars();
5295 JS_PUBLIC_API(const jschar *)
5296 JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength)
5298 JS_ASSERT(str->isAtomized());
5299 *plength = str->flatLength();
5300 return str->flatChars();
5303 extern JS_PUBLIC_API(JSFlatString *)
5304 JS_FlattenString(JSContext *cx, JSString *str)
5306 CHECK_REQUEST(cx);
5307 assertSameCompartment(cx, str);
5308 return str->getCharsZ(cx) ? (JSFlatString *)str : NULL;
5311 extern JS_PUBLIC_API(const jschar *)
5312 JS_GetFlatStringChars(JSFlatString *str)
5314 return str->chars();
5317 JS_PUBLIC_API(JSBool)
5318 JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result)
5320 return CompareStrings(cx, str1, str2, result);
5323 JS_PUBLIC_API(JSBool)
5324 JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match)
5326 JSLinearString *linearStr = str->ensureLinear(cx);
5327 if (!linearStr)
5328 return false;
5329 *match = StringEqualsAscii(linearStr, asciiBytes);
5330 return true;
5333 JS_PUBLIC_API(JSBool)
5334 JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes)
5336 return StringEqualsAscii(str, asciiBytes);
5339 JS_PUBLIC_API(size_t)
5340 JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote)
5342 return PutEscapedString(buffer, size, str, quote);
5345 JS_PUBLIC_API(size_t)
5346 JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote)
5348 JSLinearString *linearStr = str->ensureLinear(cx);
5349 if (!linearStr)
5350 return size_t(-1);
5351 return PutEscapedString(buffer, size, linearStr, quote);
5354 JS_PUBLIC_API(JSBool)
5355 JS_FileEscapedString(FILE *fp, JSString *str, char quote)
5357 JSLinearString *linearStr = str->ensureLinear(NULL);
5358 return linearStr && FileEscapedString(fp, linearStr, quote);
5361 JS_PUBLIC_API(JSString *)
5362 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
5364 CHECK_REQUEST(cx);
5365 return js_NewString(cx, chars, length);
5368 JS_PUBLIC_API(JSString *)
5369 JS_NewDependentString(JSContext *cx, JSString *str, size_t start, size_t length)
5371 CHECK_REQUEST(cx);
5372 return js_NewDependentString(cx, str, start, length);
5375 JS_PUBLIC_API(JSString *)
5376 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
5378 CHECK_REQUEST(cx);
5379 return js_ConcatStrings(cx, left, right);
5382 JS_PUBLIC_API(const jschar *)
5383 JS_UndependString(JSContext *cx, JSString *str)
5385 CHECK_REQUEST(cx);
5386 return str->getCharsZ(cx);
5389 JS_PUBLIC_API(JSBool)
5390 JS_MakeStringImmutable(JSContext *cx, JSString *str)
5392 CHECK_REQUEST(cx);
5393 return js_MakeStringImmutable(cx, str);
5396 JS_PUBLIC_API(JSBool)
5397 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, size_t *dstlenp)
5399 size_t n;
5400 if (!dst) {
5401 n = js_GetDeflatedStringLength(cx, src, srclen);
5402 if (n == (size_t)-1) {
5403 *dstlenp = 0;
5404 return JS_FALSE;
5406 *dstlenp = n;
5407 return JS_TRUE;
5410 return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5413 JS_PUBLIC_API(JSBool)
5414 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp)
5416 return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5419 JS_PUBLIC_API(char *)
5420 JS_EncodeString(JSContext *cx, JSString *str)
5422 const jschar *chars = str->getChars(cx);
5423 if (!chars)
5424 return NULL;
5425 return js_DeflateString(cx, chars, str->length());
5428 JS_PUBLIC_API(size_t)
5429 JS_GetStringEncodingLength(JSContext *cx, JSString *str)
5431 const jschar *chars = str->getChars(cx);
5432 if (!chars)
5433 return size_t(-1);
5434 return js_GetDeflatedStringLength(cx, chars, str->length());
5437 JS_PUBLIC_API(size_t)
5438 JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length)
5441 * FIXME bug 612141 - fix js_DeflateStringToBuffer interface so the result
5442 * would allow to distinguish between insufficient buffer and encoding
5443 * error.
5445 size_t writtenLength = length;
5446 const jschar *chars = str->getChars(NULL);
5447 if (!chars)
5448 return size_t(-1);
5449 if (js_DeflateStringToBuffer(NULL, chars, str->length(), buffer, &writtenLength)) {
5450 JS_ASSERT(writtenLength <= length);
5451 return writtenLength;
5453 JS_ASSERT(writtenLength <= length);
5454 size_t necessaryLength = js_GetDeflatedStringLength(NULL, chars, str->length());
5455 if (necessaryLength == size_t(-1))
5456 return size_t(-1);
5457 if (writtenLength != length) {
5458 /* Make sure that the buffer contains only valid UTF-8 sequences. */
5459 JS_ASSERT(js_CStringsAreUTF8);
5460 PodZero(buffer + writtenLength, length - writtenLength);
5462 return necessaryLength;
5465 JS_PUBLIC_API(JSBool)
5466 JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
5467 JSONWriteCallback callback, void *data)
5469 CHECK_REQUEST(cx);
5470 assertSameCompartment(cx, replacer, space);
5471 StringBuffer sb(cx);
5472 if (!js_Stringify(cx, Valueify(vp), replacer, Valueify(space), sb))
5473 return false;
5474 return callback(sb.begin(), sb.length(), data);
5477 JS_PUBLIC_API(JSBool)
5478 JS_TryJSON(JSContext *cx, jsval *vp)
5480 CHECK_REQUEST(cx);
5481 assertSameCompartment(cx, *vp);
5482 return js_TryJSON(cx, Valueify(vp));
5485 JS_PUBLIC_API(JSONParser *)
5486 JS_BeginJSONParse(JSContext *cx, jsval *vp)
5488 CHECK_REQUEST(cx);
5489 return js_BeginJSONParse(cx, Valueify(vp));
5492 JS_PUBLIC_API(JSBool)
5493 JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len)
5495 CHECK_REQUEST(cx);
5496 return js_ConsumeJSONText(cx, jp, data, len);
5499 JS_PUBLIC_API(JSBool)
5500 JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver)
5502 CHECK_REQUEST(cx);
5503 assertSameCompartment(cx, reviver);
5504 return js_FinishJSONParse(cx, jp, Valueify(reviver));
5507 JS_PUBLIC_API(JSBool)
5508 JS_ReadStructuredClone(JSContext *cx, const uint64 *buf, size_t nbytes,
5509 uint32 version, jsval *vp,
5510 const JSStructuredCloneCallbacks *optionalCallbacks,
5511 void *closure)
5513 if (version > JS_STRUCTURED_CLONE_VERSION) {
5514 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CLONE_VERSION);
5515 return false;
5517 const JSStructuredCloneCallbacks *callbacks =
5518 optionalCallbacks ?
5519 optionalCallbacks :
5520 cx->runtime->structuredCloneCallbacks;
5521 return ReadStructuredClone(cx, buf, nbytes, Valueify(vp), callbacks, closure);
5524 JS_PUBLIC_API(JSBool)
5525 JS_WriteStructuredClone(JSContext *cx, jsval v, uint64 **bufp, size_t *nbytesp,
5526 const JSStructuredCloneCallbacks *optionalCallbacks,
5527 void *closure)
5529 const JSStructuredCloneCallbacks *callbacks =
5530 optionalCallbacks ?
5531 optionalCallbacks :
5532 cx->runtime->structuredCloneCallbacks;
5533 return WriteStructuredClone(cx, Valueify(v), (uint64_t **) bufp, nbytesp,
5534 callbacks, closure);
5537 JS_PUBLIC_API(JSBool)
5538 JS_StructuredClone(JSContext *cx, jsval v, jsval *vp,
5539 ReadStructuredCloneOp optionalReadOp,
5540 const JSStructuredCloneCallbacks *optionalCallbacks,
5541 void *closure)
5543 const JSStructuredCloneCallbacks *callbacks =
5544 optionalCallbacks ?
5545 optionalCallbacks :
5546 cx->runtime->structuredCloneCallbacks;
5547 JSAutoStructuredCloneBuffer buf;
5548 return buf.write(cx, v, callbacks, closure) &&
5549 buf.read(vp, cx, callbacks, closure);
5552 JS_PUBLIC_API(void)
5553 JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks)
5555 rt->structuredCloneCallbacks = callbacks;
5558 JS_PUBLIC_API(JSBool)
5559 JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32 *p1, uint32 *p2)
5561 return r->input().readPair((uint32_t *) p1, (uint32_t *) p2);
5564 JS_PUBLIC_API(JSBool)
5565 JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len)
5567 return r->input().readBytes(p, len);
5570 JS_PUBLIC_API(JSBool)
5571 JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32 tag, uint32 data)
5573 return w->output().writePair(tag, data);
5576 JS_PUBLIC_API(JSBool)
5577 JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len)
5579 return w->output().writeBytes(p, len);
5583 * The following determines whether C Strings are to be treated as UTF-8
5584 * or ISO-8859-1. For correct operation, it must be set prior to the
5585 * first call to JS_NewRuntime.
5587 #ifndef JS_C_STRINGS_ARE_UTF8
5588 JSBool js_CStringsAreUTF8 = JS_FALSE;
5589 #endif
5591 JS_PUBLIC_API(JSBool)
5592 JS_CStringsAreUTF8()
5594 return js_CStringsAreUTF8;
5597 JS_PUBLIC_API(void)
5598 JS_SetCStringsAreUTF8()
5600 JS_ASSERT(!js_NewRuntimeWasCalled);
5602 #ifndef JS_C_STRINGS_ARE_UTF8
5603 js_CStringsAreUTF8 = JS_TRUE;
5604 #endif
5607 /************************************************************************/
5609 JS_PUBLIC_API(void)
5610 JS_ReportError(JSContext *cx, const char *format, ...)
5612 va_list ap;
5614 va_start(ap, format);
5615 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
5616 va_end(ap);
5619 JS_PUBLIC_API(void)
5620 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
5621 void *userRef, const uintN errorNumber, ...)
5623 va_list ap;
5625 va_start(ap, errorNumber);
5626 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5627 errorNumber, JS_TRUE, ap);
5628 va_end(ap);
5631 JS_PUBLIC_API(void)
5632 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
5633 void *userRef, const uintN errorNumber, ...)
5635 va_list ap;
5637 va_start(ap, errorNumber);
5638 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5639 errorNumber, JS_FALSE, ap);
5640 va_end(ap);
5643 JS_PUBLIC_API(JSBool)
5644 JS_ReportWarning(JSContext *cx, const char *format, ...)
5646 va_list ap;
5647 JSBool ok;
5649 va_start(ap, format);
5650 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
5651 va_end(ap);
5652 return ok;
5655 JS_PUBLIC_API(JSBool)
5656 JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
5657 JSErrorCallback errorCallback, void *userRef,
5658 const uintN errorNumber, ...)
5660 va_list ap;
5661 JSBool ok;
5663 va_start(ap, errorNumber);
5664 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5665 errorNumber, JS_TRUE, ap);
5666 va_end(ap);
5667 return ok;
5670 JS_PUBLIC_API(JSBool)
5671 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
5672 JSErrorCallback errorCallback, void *userRef,
5673 const uintN errorNumber, ...)
5675 va_list ap;
5676 JSBool ok;
5678 va_start(ap, errorNumber);
5679 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5680 errorNumber, JS_FALSE, ap);
5681 va_end(ap);
5682 return ok;
5685 JS_PUBLIC_API(void)
5686 JS_ReportOutOfMemory(JSContext *cx)
5688 js_ReportOutOfMemory(cx);
5691 JS_PUBLIC_API(void)
5692 JS_ReportAllocationOverflow(JSContext *cx)
5694 js_ReportAllocationOverflow(cx);
5697 JS_PUBLIC_API(JSErrorReporter)
5698 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
5700 JSErrorReporter older;
5702 older = cx->errorReporter;
5703 cx->errorReporter = er;
5704 return older;
5707 /************************************************************************/
5710 * Regular Expressions.
5712 JS_PUBLIC_API(JSObject *)
5713 JS_NewRegExpObject(JSContext *cx, JSObject *obj, char *bytes, size_t length, uintN flags)
5715 CHECK_REQUEST(cx);
5716 jschar *chars = js_InflateString(cx, bytes, &length);
5717 if (!chars)
5718 return NULL;
5719 RegExpStatics *res = RegExpStatics::extractFrom(obj);
5720 JSObject *reobj = RegExp::createObject(cx, res, chars, length, flags);
5721 cx->free(chars);
5722 return reobj;
5725 JS_PUBLIC_API(JSObject *)
5726 JS_NewUCRegExpObject(JSContext *cx, JSObject *obj, jschar *chars, size_t length, uintN flags)
5728 CHECK_REQUEST(cx);
5729 RegExpStatics *res = RegExpStatics::extractFrom(obj);
5730 return RegExp::createObject(cx, res, chars, length, flags);
5733 JS_PUBLIC_API(void)
5734 JS_SetRegExpInput(JSContext *cx, JSObject *obj, JSString *input, JSBool multiline)
5736 CHECK_REQUEST(cx);
5737 assertSameCompartment(cx, input);
5739 RegExpStatics::extractFrom(obj)->reset(input, !!multiline);
5742 JS_PUBLIC_API(void)
5743 JS_ClearRegExpStatics(JSContext *cx, JSObject *obj)
5745 CHECK_REQUEST(cx);
5746 JS_ASSERT(obj);
5748 RegExpStatics::extractFrom(obj)->clear();
5751 JS_PUBLIC_API(JSBool)
5752 JS_ExecuteRegExp(JSContext *cx, JSObject *obj, JSObject *reobj, jschar *chars, size_t length,
5753 size_t *indexp, JSBool test, jsval *rval)
5755 CHECK_REQUEST(cx);
5757 RegExp *re = RegExp::extractFrom(reobj);
5758 if (!re)
5759 return false;
5761 JSString *str = js_NewStringCopyN(cx, chars, length);
5762 if (!str)
5763 return false;
5765 return re->execute(cx, RegExpStatics::extractFrom(obj), str, indexp, test, Valueify(rval));
5768 JS_PUBLIC_API(JSObject *)
5769 JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, uintN flags)
5771 CHECK_REQUEST(cx);
5772 jschar *chars = js_InflateString(cx, bytes, &length);
5773 if (!chars)
5774 return NULL;
5775 JSObject *obj = RegExp::createObjectNoStatics(cx, chars, length, flags);
5776 cx->free(chars);
5777 return obj;
5780 JS_PUBLIC_API(JSObject *)
5781 JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, uintN flags)
5783 CHECK_REQUEST(cx);
5784 return RegExp::createObjectNoStatics(cx, chars, length, flags);
5787 JS_PUBLIC_API(JSBool)
5788 JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *obj, jschar *chars, size_t length,
5789 size_t *indexp, JSBool test, jsval *rval)
5791 CHECK_REQUEST(cx);
5793 RegExp *re = RegExp::extractFrom(obj);
5794 if (!re)
5795 return false;
5797 JSString *str = js_NewStringCopyN(cx, chars, length);
5798 if (!str)
5799 return false;
5801 return re->executeNoStatics(cx, str, indexp, test, Valueify(rval));
5804 /************************************************************************/
5806 JS_PUBLIC_API(void)
5807 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
5809 cx->localeCallbacks = callbacks;
5812 JS_PUBLIC_API(JSLocaleCallbacks *)
5813 JS_GetLocaleCallbacks(JSContext *cx)
5815 return cx->localeCallbacks;
5818 /************************************************************************/
5820 JS_PUBLIC_API(JSBool)
5821 JS_IsExceptionPending(JSContext *cx)
5823 return (JSBool) cx->isExceptionPending();
5826 JS_PUBLIC_API(JSBool)
5827 JS_GetPendingException(JSContext *cx, jsval *vp)
5829 CHECK_REQUEST(cx);
5830 if (!cx->isExceptionPending())
5831 return JS_FALSE;
5832 Valueify(*vp) = cx->getPendingException();
5833 assertSameCompartment(cx, *vp);
5834 return JS_TRUE;
5837 JS_PUBLIC_API(void)
5838 JS_SetPendingException(JSContext *cx, jsval v)
5840 CHECK_REQUEST(cx);
5841 assertSameCompartment(cx, v);
5842 cx->setPendingException(Valueify(v));
5845 JS_PUBLIC_API(void)
5846 JS_ClearPendingException(JSContext *cx)
5848 cx->clearPendingException();
5851 JS_PUBLIC_API(JSBool)
5852 JS_ReportPendingException(JSContext *cx)
5854 JSBool ok;
5855 JSPackedBool save;
5857 CHECK_REQUEST(cx);
5860 * Set cx->generatingError to suppress the standard error-to-exception
5861 * conversion done by all {js,JS}_Report* functions except for OOM. The
5862 * cx->generatingError flag was added to suppress recursive divergence
5863 * under js_ErrorToException, but it serves for our purposes here too.
5865 save = cx->generatingError;
5866 cx->generatingError = JS_TRUE;
5867 ok = js_ReportUncaughtException(cx);
5868 cx->generatingError = save;
5869 return ok;
5872 struct JSExceptionState {
5873 JSBool throwing;
5874 jsval exception;
5877 JS_PUBLIC_API(JSExceptionState *)
5878 JS_SaveExceptionState(JSContext *cx)
5880 JSExceptionState *state;
5882 CHECK_REQUEST(cx);
5883 state = (JSExceptionState *) cx->malloc(sizeof(JSExceptionState));
5884 if (state) {
5885 state->throwing = JS_GetPendingException(cx, &state->exception);
5886 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
5887 js_AddRoot(cx, Valueify(&state->exception), "JSExceptionState.exception");
5889 return state;
5892 JS_PUBLIC_API(void)
5893 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
5895 CHECK_REQUEST(cx);
5896 if (state) {
5897 if (state->throwing)
5898 JS_SetPendingException(cx, state->exception);
5899 else
5900 JS_ClearPendingException(cx);
5901 JS_DropExceptionState(cx, state);
5905 JS_PUBLIC_API(void)
5906 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
5908 CHECK_REQUEST(cx);
5909 if (state) {
5910 if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
5911 assertSameCompartment(cx, state->exception);
5912 JS_RemoveValueRoot(cx, &state->exception);
5914 cx->free(state);
5918 JS_PUBLIC_API(JSErrorReport *)
5919 JS_ErrorFromException(JSContext *cx, jsval v)
5921 CHECK_REQUEST(cx);
5922 assertSameCompartment(cx, v);
5923 return js_ErrorFromException(cx, v);
5926 JS_PUBLIC_API(JSBool)
5927 JS_ThrowReportedError(JSContext *cx, const char *message,
5928 JSErrorReport *reportp)
5930 return JS_IsRunning(cx) &&
5931 js_ErrorToException(cx, message, reportp, NULL, NULL);
5934 JS_PUBLIC_API(JSBool)
5935 JS_ThrowStopIteration(JSContext *cx)
5937 return js_ThrowStopIteration(cx);
5941 * Get the owning thread id of a context. Returns 0 if the context is not
5942 * owned by any thread.
5944 JS_PUBLIC_API(jsword)
5945 JS_GetContextThread(JSContext *cx)
5947 #ifdef JS_THREADSAFE
5948 return reinterpret_cast<jsword>(JS_THREAD_ID(cx));
5949 #else
5950 return 0;
5951 #endif
5955 * Set the current thread as the owning thread of a context. Returns the
5956 * old owning thread id, or -1 if the operation failed.
5958 JS_PUBLIC_API(jsword)
5959 JS_SetContextThread(JSContext *cx)
5961 #ifdef JS_THREADSAFE
5962 JS_ASSERT(!cx->outstandingRequests);
5963 if (cx->thread) {
5964 JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
5965 return reinterpret_cast<jsword>(cx->thread->id);
5968 if (!js_InitContextThread(cx)) {
5969 js_ReportOutOfMemory(cx);
5970 return -1;
5973 /* Here the GC lock is still held after js_InitContextThread took it. */
5974 JS_UNLOCK_GC(cx->runtime);
5975 #endif
5976 return 0;
5979 JS_PUBLIC_API(jsword)
5980 JS_ClearContextThread(JSContext *cx)
5982 #ifdef JS_THREADSAFE
5984 * cx must have exited all requests it entered and, if cx is associated
5985 * with a thread, this must be called only from that thread. If not, this
5986 * is a harmless no-op.
5988 JS_ASSERT(cx->outstandingRequests == 0);
5989 JSThread *t = cx->thread;
5990 if (!t)
5991 return 0;
5992 JS_ASSERT(CURRENT_THREAD_IS_ME(t));
5995 * We must not race with a GC that accesses cx->thread for all threads,
5996 * see bug 476934.
5998 JSRuntime *rt = cx->runtime;
5999 AutoLockGC lock(rt);
6000 js_WaitForGC(rt);
6001 js_ClearContextThread(cx);
6002 JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth);
6005 * We can access t->id as long as the GC lock is held and we cannot race
6006 * with the GC that may delete t.
6008 return reinterpret_cast<jsword>(t->id);
6009 #else
6010 return 0;
6011 #endif
6014 #ifdef MOZ_TRACE_JSCALLS
6015 JS_PUBLIC_API(void)
6016 JS_SetFunctionCallback(JSContext *cx, JSFunctionCallback fcb)
6018 cx->functionCallback = fcb;
6021 JS_PUBLIC_API(JSFunctionCallback)
6022 JS_GetFunctionCallback(JSContext *cx)
6024 return cx->functionCallback;
6026 #endif
6028 #ifdef JS_GC_ZEAL
6029 JS_PUBLIC_API(void)
6030 JS_SetGCZeal(JSContext *cx, uint8 zeal)
6032 cx->runtime->gcZeal = zeal;
6034 #endif
6036 /************************************************************************/
6038 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN) && !defined (WINCE)
6040 #include "jswin.h"
6043 * Initialization routine for the JS DLL.
6045 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
6047 return TRUE;
6050 #endif