Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jsapi.cpp
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sw=4 et tw=78:
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
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/
11  *
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.
16  *
17  * The Original Code is Mozilla Communicator client code, released
18  * March 31, 1998.
19  *
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.
24  *
25  * Contributor(s):
26  *
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.
38  *
39  * ***** END LICENSE BLOCK ***** */
40
41 /*
42  * JavaScript API.
43  */
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 "prmjtime.h"
86 #include "jsstaticcheck.h"
87 #include "jsvector.h"
88 #include "jswrapper.h"
89 #include "jstypedarray.h"
90
91 #include "jsatominlines.h"
92 #include "jscntxtinlines.h"
93 #include "jsinterpinlines.h"
94 #include "jsobjinlines.h"
95 #include "jsscopeinlines.h"
96 #include "jscntxtinlines.h"
97 #include "jsregexpinlines.h"
98 #include "jsscriptinlines.h"
99 #include "jsstrinlines.h"
100 #include "assembler/wtf/Platform.h"
101
102 #if ENABLE_YARR_JIT
103 #include "assembler/jit/ExecutableAllocator.h"
104 #include "methodjit/Logging.h"
105 #endif
106
107 #if JS_HAS_XML_SUPPORT
108 #include "jsxml.h"
109 #endif
110
111 using namespace js;
112 using namespace js::gc;
113
114 /*
115  * This class is a version-establising barrier at the head of a VM entry or
116  * re-entry. It ensures that:
117  *
118  * - |newVersion| is the starting (default) version used for the context.
119  * - The starting version state is not an override.
120  * - Overrides in the VM session are not propagated to the caller.
121  */
122 class AutoVersionAPI
123 {
124     JSContext   * const cx;
125     JSVersion   oldDefaultVersion;
126     bool        oldHasVersionOverride;
127     JSVersion   oldVersionOverride;
128 #ifdef DEBUG
129     uintN       oldCompileOptions;
130 #endif
131     JSVersion   newVersion;
132
133   public:
134     explicit AutoVersionAPI(JSContext *cx, JSVersion newVersion)
135       : cx(cx),
136         oldDefaultVersion(cx->getDefaultVersion()),
137         oldHasVersionOverride(cx->isVersionOverridden()),
138         oldVersionOverride(oldHasVersionOverride ? cx->findVersion() : JSVERSION_UNKNOWN)
139 #ifdef DEBUG
140         , oldCompileOptions(cx->getCompileOptions()) 
141 #endif
142     {
143         /* 
144          * Note: ANONFUNFIX in newVersion is ignored for backwards
145          * compatibility, must be set via JS_SetOptions. (Because of this, we
146          * inherit the current ANONFUNFIX setting from the options.
147          */
148         VersionSetAnonFunFix(&newVersion, OptionsHasAnonFunFix(cx->getCompileOptions()));
149         this->newVersion = newVersion;
150         cx->clearVersionOverride();
151         cx->setDefaultVersion(newVersion);
152     }
153
154     ~AutoVersionAPI() {
155         cx->setDefaultVersion(oldDefaultVersion);
156         if (oldHasVersionOverride)
157             cx->overrideVersion(oldVersionOverride);
158         else
159             cx->clearVersionOverride();
160         JS_ASSERT(oldCompileOptions == cx->getCompileOptions());
161     }
162
163     /* The version that this scoped-entity establishes. */
164     JSVersion version() const { return newVersion; }
165 };
166
167 #ifdef HAVE_VA_LIST_AS_ARRAY
168 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
169 #else
170 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
171 #endif
172
173 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
174 JS_PUBLIC_DATA(jsid) JS_DEFAULT_XML_NAMESPACE_ID = { size_t(JSID_TYPE_DEFAULT_XML_NAMESPACE) };
175 JS_PUBLIC_DATA(jsid) JSID_VOID  = { size_t(JSID_TYPE_VOID) };
176 JS_PUBLIC_DATA(jsid) JSID_EMPTY = { size_t(JSID_TYPE_OBJECT) };
177 #endif
178
179 #ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES
180 JS_PUBLIC_DATA(jsval) JSVAL_NULL  = { BUILD_JSVAL(JSVAL_TAG_NULL,      0) };
181 JS_PUBLIC_DATA(jsval) JSVAL_ZERO  = { BUILD_JSVAL(JSVAL_TAG_INT32,     0) };
182 JS_PUBLIC_DATA(jsval) JSVAL_ONE   = { BUILD_JSVAL(JSVAL_TAG_INT32,     1) };
183 JS_PUBLIC_DATA(jsval) JSVAL_FALSE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN,   JS_FALSE) };
184 JS_PUBLIC_DATA(jsval) JSVAL_TRUE  = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN,   JS_TRUE) };
185 JS_PUBLIC_DATA(jsval) JSVAL_VOID  = { BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0) };
186 #endif
187
188 /* Make sure that jschar is two bytes unsigned integer */
189 JS_STATIC_ASSERT((jschar)-1 > 0);
190 JS_STATIC_ASSERT(sizeof(jschar) == 2);
191
192 JS_PUBLIC_API(int64)
193 JS_Now()
194 {
195     return PRMJ_Now();
196 }
197
198 JS_PUBLIC_API(jsval)
199 JS_GetNaNValue(JSContext *cx)
200 {
201     return Jsvalify(cx->runtime->NaNValue);
202 }
203
204 JS_PUBLIC_API(jsval)
205 JS_GetNegativeInfinityValue(JSContext *cx)
206 {
207     return Jsvalify(cx->runtime->negativeInfinityValue);
208 }
209
210 JS_PUBLIC_API(jsval)
211 JS_GetPositiveInfinityValue(JSContext *cx)
212 {
213     return Jsvalify(cx->runtime->positiveInfinityValue);
214 }
215
216 JS_PUBLIC_API(jsval)
217 JS_GetEmptyStringValue(JSContext *cx)
218 {
219     return STRING_TO_JSVAL(cx->runtime->emptyString);
220 }
221
222 JS_PUBLIC_API(JSString *)
223 JS_GetEmptyString(JSRuntime *rt)
224 {
225     JS_ASSERT(rt->state == JSRTS_UP);
226     return rt->emptyString;
227 }
228
229 static JSBool
230 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, jsval **vpp, va_list *app)
231 {
232     const char *format;
233     JSArgumentFormatMap *map;
234
235     format = *formatp;
236     for (map = cx->argumentFormatMap; map; map = map->next) {
237         if (!strncmp(format, map->format, map->length)) {
238             *formatp = format + map->length;
239             return map->formatter(cx, format, fromJS, vpp, app);
240         }
241     }
242     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
243     return JS_FALSE;
244 }
245
246 JS_PUBLIC_API(JSBool)
247 JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format, ...)
248 {
249     va_list ap;
250     JSBool ok;
251
252     va_start(ap, format);
253     ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
254     va_end(ap);
255     return ok;
256 }
257
258 JS_PUBLIC_API(JSBool)
259 JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format, va_list ap)
260 {
261     jsval *sp;
262     JSBool required;
263     char c;
264     JSFunction *fun;
265     jsdouble d;
266     JSString *str;
267     JSObject *obj;
268
269     CHECK_REQUEST(cx);
270     assertSameCompartment(cx, JSValueArray(argv - 2, argc + 2));
271     sp = argv;
272     required = JS_TRUE;
273     while ((c = *format++) != '\0') {
274         if (isspace(c))
275             continue;
276         if (c == '/') {
277             required = JS_FALSE;
278             continue;
279         }
280         if (sp == argv + argc) {
281             if (required) {
282                 fun = js_ValueToFunction(cx, Valueify(&argv[-2]), 0);
283                 if (fun) {
284                     char numBuf[12];
285                     JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
286                     JSAutoByteString funNameBytes;
287                     if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
288                         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
289                                              name, numBuf, (argc == 1) ? "" : "s");
290                     }
291                 }
292                 return JS_FALSE;
293             }
294             break;
295         }
296         switch (c) {
297           case 'b':
298             *va_arg(ap, JSBool *) = js_ValueToBoolean(Valueify(*sp));
299             break;
300           case 'c':
301             if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
302                 return JS_FALSE;
303             break;
304           case 'i':
305             if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
306                 return JS_FALSE;
307             break;
308           case 'u':
309             if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
310                 return JS_FALSE;
311             break;
312           case 'j':
313             if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
314                 return JS_FALSE;
315             break;
316           case 'd':
317             if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
318                 return JS_FALSE;
319             break;
320           case 'I':
321             if (!JS_ValueToNumber(cx, *sp, &d))
322                 return JS_FALSE;
323             *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
324             break;
325           case 'S':
326           case 'W':
327             str = js_ValueToString(cx, Valueify(*sp));
328             if (!str)
329                 return JS_FALSE;
330             *sp = STRING_TO_JSVAL(str);
331             if (c == 'W') {
332                 const jschar *chars = js_GetStringChars(cx, str);
333                 if (!chars)
334                     return JS_FALSE;
335                 *va_arg(ap, const jschar **) = chars;
336             } else {
337                 *va_arg(ap, JSString **) = str;
338             }
339             break;
340           case 'o':
341             if (!js_ValueToObjectOrNull(cx, Valueify(*sp), &obj))
342                 return JS_FALSE;
343             *sp = OBJECT_TO_JSVAL(obj);
344             *va_arg(ap, JSObject **) = obj;
345             break;
346           case 'f':
347             obj = js_ValueToFunctionObject(cx, Valueify(sp), 0);
348             if (!obj)
349                 return JS_FALSE;
350             *sp = OBJECT_TO_JSVAL(obj);
351             *va_arg(ap, JSFunction **) = GET_FUNCTION_PRIVATE(cx, obj);
352             break;
353           case 'v':
354             *va_arg(ap, jsval *) = *sp;
355             break;
356           case '*':
357             break;
358           default:
359             format--;
360             if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
361                                       JS_ADDRESSOF_VA_LIST(ap))) {
362                 return JS_FALSE;
363             }
364             /* NB: the formatter already updated sp, so we continue here. */
365             continue;
366         }
367         sp++;
368     }
369     return JS_TRUE;
370 }
371
372 JS_PUBLIC_API(JSBool)
373 JS_AddArgumentFormatter(JSContext *cx, const char *format, JSArgumentFormatter formatter)
374 {
375     size_t length;
376     JSArgumentFormatMap **mpp, *map;
377
378     length = strlen(format);
379     mpp = &cx->argumentFormatMap;
380     while ((map = *mpp) != NULL) {
381         /* Insert before any shorter string to match before prefixes. */
382         if (map->length < length)
383             break;
384         if (map->length == length && !strcmp(map->format, format))
385             goto out;
386         mpp = &map->next;
387     }
388     map = (JSArgumentFormatMap *) cx->malloc(sizeof *map);
389     if (!map)
390         return JS_FALSE;
391     map->format = format;
392     map->length = length;
393     map->next = *mpp;
394     *mpp = map;
395 out:
396     map->formatter = formatter;
397     return JS_TRUE;
398 }
399
400 JS_PUBLIC_API(void)
401 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
402 {
403     size_t length;
404     JSArgumentFormatMap **mpp, *map;
405
406     length = strlen(format);
407     mpp = &cx->argumentFormatMap;
408     while ((map = *mpp) != NULL) {
409         if (map->length == length && !strcmp(map->format, format)) {
410             *mpp = map->next;
411             cx->free(map);
412             return;
413         }
414         mpp = &map->next;
415     }
416 }
417
418 JS_PUBLIC_API(JSBool)
419 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
420 {
421     JSBool ok;
422     JSObject *obj;
423     JSString *str;
424     jsdouble d;
425
426     CHECK_REQUEST(cx);
427     assertSameCompartment(cx, v);
428     switch (type) {
429       case JSTYPE_VOID:
430         *vp = JSVAL_VOID;
431         ok = JS_TRUE;
432         break;
433       case JSTYPE_OBJECT:
434         ok = js_ValueToObjectOrNull(cx, Valueify(v), &obj);
435         if (ok)
436             *vp = OBJECT_TO_JSVAL(obj);
437         break;
438       case JSTYPE_FUNCTION:
439         *vp = v;
440         obj = js_ValueToFunctionObject(cx, Valueify(vp), JSV2F_SEARCH_STACK);
441         ok = (obj != NULL);
442         break;
443       case JSTYPE_STRING:
444         str = js_ValueToString(cx, Valueify(v));
445         ok = (str != NULL);
446         if (ok)
447             *vp = STRING_TO_JSVAL(str);
448         break;
449       case JSTYPE_NUMBER:
450         ok = JS_ValueToNumber(cx, v, &d);
451         if (ok)
452             *vp = DOUBLE_TO_JSVAL(d);
453         break;
454       case JSTYPE_BOOLEAN:
455         *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(Valueify(v)));
456         return JS_TRUE;
457       default: {
458         char numBuf[12];
459         JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
460         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE, numBuf);
461         ok = JS_FALSE;
462         break;
463       }
464     }
465     return ok;
466 }
467
468 JS_PUBLIC_API(JSBool)
469 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
470 {
471     CHECK_REQUEST(cx);
472     assertSameCompartment(cx, v);
473     return js_ValueToObjectOrNull(cx, Valueify(v), objp);
474 }
475
476 JS_PUBLIC_API(JSFunction *)
477 JS_ValueToFunction(JSContext *cx, jsval v)
478 {
479     CHECK_REQUEST(cx);
480     assertSameCompartment(cx, v);
481     return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
482 }
483
484 JS_PUBLIC_API(JSFunction *)
485 JS_ValueToConstructor(JSContext *cx, jsval v)
486 {
487     CHECK_REQUEST(cx);
488     assertSameCompartment(cx, v);
489     return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
490 }
491
492 JS_PUBLIC_API(JSString *)
493 JS_ValueToString(JSContext *cx, jsval v)
494 {
495     CHECK_REQUEST(cx);
496     assertSameCompartment(cx, v);
497     return js_ValueToString(cx, Valueify(v));
498 }
499
500 JS_PUBLIC_API(JSString *)
501 JS_ValueToSource(JSContext *cx, jsval v)
502 {
503     CHECK_REQUEST(cx);
504     assertSameCompartment(cx, v);
505     return js_ValueToSource(cx, Valueify(v));
506 }
507
508 JS_PUBLIC_API(JSBool)
509 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
510 {
511     CHECK_REQUEST(cx);
512     assertSameCompartment(cx, v);
513
514     AutoValueRooter tvr(cx, Valueify(v));
515     return ValueToNumber(cx, tvr.value(), dp);
516 }
517
518 JS_PUBLIC_API(JSBool)
519 JS_DoubleIsInt32(jsdouble d, jsint *ip)
520 {
521     return JSDOUBLE_IS_INT32(d, (int32_t *)ip);
522 }
523
524 JS_PUBLIC_API(JSBool)
525 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
526 {
527     CHECK_REQUEST(cx);
528     assertSameCompartment(cx, v);
529
530     AutoValueRooter tvr(cx, Valueify(v));
531     return ValueToECMAInt32(cx, tvr.value(), (int32_t *)ip);
532 }
533
534 JS_PUBLIC_API(JSBool)
535 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
536 {
537     CHECK_REQUEST(cx);
538     assertSameCompartment(cx, v);
539
540     AutoValueRooter tvr(cx, Valueify(v));
541     return ValueToECMAUint32(cx, tvr.value(), (uint32_t *)ip);
542 }
543
544 JS_PUBLIC_API(JSBool)
545 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
546 {
547     CHECK_REQUEST(cx);
548     assertSameCompartment(cx, v);
549
550     AutoValueRooter tvr(cx, Valueify(v));
551     return ValueToInt32(cx, tvr.value(), (int32_t *)ip);
552 }
553
554 JS_PUBLIC_API(JSBool)
555 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
556 {
557     CHECK_REQUEST(cx);
558     assertSameCompartment(cx, v);
559
560     AutoValueRooter tvr(cx, Valueify(v));
561     return ValueToUint16(cx, tvr.value(), (uint16_t *)ip);
562 }
563
564 JS_PUBLIC_API(JSBool)
565 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
566 {
567     CHECK_REQUEST(cx);
568     assertSameCompartment(cx, v);
569     *bp = js_ValueToBoolean(Valueify(v));
570     return JS_TRUE;
571 }
572
573 JS_PUBLIC_API(JSType)
574 JS_TypeOfValue(JSContext *cx, jsval v)
575 {
576     CHECK_REQUEST(cx);
577     assertSameCompartment(cx, v);
578     return TypeOfValue(cx, Valueify(v));
579 }
580
581 JS_PUBLIC_API(const char *)
582 JS_GetTypeName(JSContext *cx, JSType type)
583 {
584     if ((uintN)type >= (uintN)JSTYPE_LIMIT)
585         return NULL;
586     return JS_TYPE_STR(type);
587 }
588
589 JS_PUBLIC_API(JSBool)
590 JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
591 {
592     assertSameCompartment(cx, v1, v2);
593     return StrictlyEqual(cx, Valueify(v1), Valueify(v2), equal);
594 }
595
596 JS_PUBLIC_API(JSBool)
597 JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same)
598 {
599     assertSameCompartment(cx, v1, v2);
600     return SameValue(cx, Valueify(v1), Valueify(v2), same);
601 }
602
603 /************************************************************************/
604
605 /*
606  * Has a new runtime ever been created?  This flag is used to detect unsafe
607  * changes to js_CStringsAreUTF8 after a runtime has been created, and to
608  * ensure that "first checks" on runtime creation are run only once.
609  */
610 #ifdef DEBUG
611 static JSBool js_NewRuntimeWasCalled = JS_FALSE;
612 #endif
613
614 JSRuntime::JSRuntime()
615   : gcChunkAllocator(&defaultGCChunkAllocator)
616 {
617     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
618     JS_INIT_CLIST(&contextList);
619     JS_INIT_CLIST(&trapList);
620     JS_INIT_CLIST(&watchPointList);
621 }
622
623 bool
624 JSRuntime::init(uint32 maxbytes)
625 {
626 #ifdef JS_METHODJIT_SPEW
627     JMCheckLogging();
628 #endif
629
630 #ifdef DEBUG
631     functionMeterFilename = getenv("JS_FUNCTION_STATFILE");
632     if (functionMeterFilename) {
633         if (!methodReadBarrierCountMap.init())
634             return false;
635         if (!unjoinedFunctionCountMap.init())
636             return false;
637     }
638     propTreeStatFilename = getenv("JS_PROPTREE_STATFILE");
639     propTreeDumpFilename = getenv("JS_PROPTREE_DUMPFILE");
640 #endif
641
642     if (!(atomsCompartment = js_new<JSCompartment>(this)) ||
643         !atomsCompartment->init() ||
644         !compartments.append(atomsCompartment)) {
645         return false;
646     }
647
648     if (!js_InitGC(this, maxbytes) || !js_InitAtomState(this))
649         return false;
650
651     wrapObjectCallback = js::TransparentObjectWrapper;
652
653 #ifdef JS_THREADSAFE
654     /* this is asymmetric with JS_ShutDown: */
655     if (!js_SetupLocks(8, 16))
656         return false;
657     rtLock = JS_NEW_LOCK();
658     if (!rtLock)
659         return false;
660     stateChange = JS_NEW_CONDVAR(gcLock);
661     if (!stateChange)
662         return false;
663     debuggerLock = JS_NEW_LOCK();
664     if (!debuggerLock)
665         return false;
666 #endif
667
668     debugMode = JS_FALSE;
669
670     return js_InitThreads(this);
671 }
672
673 JSRuntime::~JSRuntime()
674 {
675 #ifdef DEBUG
676     /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
677     if (!JS_CLIST_IS_EMPTY(&contextList)) {
678         JSContext *cx, *iter = NULL;
679         uintN cxcount = 0;
680         while ((cx = js_ContextIterator(this, JS_TRUE, &iter)) != NULL) {
681             fprintf(stderr,
682 "JS API usage error: found live context at %p\n",
683                     (void *) cx);
684             cxcount++;
685         }
686         fprintf(stderr,
687 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
688                 cxcount, (cxcount == 1) ? "" : "s");
689     }
690 #endif
691
692     js_FinishThreads(this);
693     js_FreeRuntimeScriptState(this);
694     js_FinishAtomState(this);
695
696     js_FinishGC(this);
697 #ifdef JS_THREADSAFE
698     if (gcLock)
699         JS_DESTROY_LOCK(gcLock);
700     if (gcDone)
701         JS_DESTROY_CONDVAR(gcDone);
702     if (requestDone)
703         JS_DESTROY_CONDVAR(requestDone);
704     if (rtLock)
705         JS_DESTROY_LOCK(rtLock);
706     if (stateChange)
707         JS_DESTROY_CONDVAR(stateChange);
708     if (debuggerLock)
709         JS_DESTROY_LOCK(debuggerLock);
710 #endif
711 }
712
713 JS_PUBLIC_API(JSRuntime *)
714 JS_NewRuntime(uint32 maxbytes)
715 {
716 #ifdef DEBUG
717     if (!js_NewRuntimeWasCalled) {
718         /*
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.
723          */
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
729
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;                                                \
737         }                                                                     \
738         JS_ASSERT(count == numfmtspecs);                                      \
739     JS_END_MACRO;
740 #include "js.msg"
741 #undef MSG_DEF
742
743         js_NewRuntimeWasCalled = JS_TRUE;
744     }
745 #endif /* DEBUG */
746
747     void *mem = js_calloc(sizeof(JSRuntime));
748     if (!mem)
749         return NULL;
750
751     JSRuntime *rt = new (mem) JSRuntime();
752     if (!rt->init(maxbytes)) {
753         JS_DestroyRuntime(rt);
754         return NULL;
755     }
756
757     return rt;
758 }
759
760 JS_PUBLIC_API(void)
761 JS_DestroyRuntime(JSRuntime *rt)
762 {
763     rt->~JSRuntime();
764
765     js_free(rt);
766 }
767
768 #ifdef JS_REPRMETER
769 namespace reprmeter {
770     extern void js_DumpReprMeter();
771 }
772 #endif
773
774 JS_PUBLIC_API(void)
775 JS_ShutDown(void)
776 {
777 #ifdef MOZ_TRACEVIS
778     StopTraceVis();
779 #endif
780
781 #ifdef JS_OPMETER
782     extern void js_DumpOpMeters();
783     js_DumpOpMeters();
784 #endif
785
786 #ifdef JS_REPRMETER
787     reprmeter::js_DumpReprMeter();
788 #endif
789
790 #ifdef JS_THREADSAFE
791     js_CleanupLocks();
792 #endif
793     PRMJ_NowShutdown();
794 }
795
796 JS_PUBLIC_API(void *)
797 JS_GetRuntimePrivate(JSRuntime *rt)
798 {
799     return rt->data;
800 }
801
802 JS_PUBLIC_API(void)
803 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
804 {
805     rt->data = data;
806 }
807
808 #ifdef JS_THREADSAFE
809 static void
810 StartRequest(JSContext *cx)
811 {
812     JSThread *t = cx->thread;
813     JS_ASSERT(CURRENT_THREAD_IS_ME(t));
814
815     if (t->data.requestDepth) {
816         t->data.requestDepth++;
817     } else {
818         JSRuntime *rt = cx->runtime;
819         AutoLockGC lock(rt);
820
821         /* Wait until the GC is finished. */
822         if (rt->gcThread != cx->thread) {
823             while (rt->gcThread)
824                 JS_AWAIT_GC_DONE(rt);
825         }
826
827         /* Indicate that a request is running. */
828         rt->requestCount++;
829         t->data.requestDepth = 1;
830
831         /*
832          * Adjust rt->interruptCounter to reflect any interrupts added while the
833          * thread was suspended.
834          */
835         if (t->data.interruptFlags)
836             JS_ATOMIC_INCREMENT(&rt->interruptCounter);
837
838         if (rt->requestCount == 1 && rt->activityCallback)
839             rt->activityCallback(rt->activityCallbackArg, true);
840     }
841 }
842
843 static void
844 StopRequest(JSContext *cx)
845 {
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 */
853
854         t->data.conservativeGC.updateForRequestEnd(t->suspendCount);
855
856         /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
857         JSRuntime *rt = cx->runtime;
858         AutoLockGC lock(rt);
859
860         t->data.requestDepth = 0;
861
862         /*
863          * Adjust rt->interruptCounter to reflect any interrupts added while the
864          * thread still had active requests.
865          */
866         if (t->data.interruptFlags)
867             JS_ATOMIC_DECREMENT(&rt->interruptCounter);
868
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);
876         }
877     }
878 }
879 #endif /* JS_THREADSAFE */
880
881 JS_PUBLIC_API(void)
882 JS_BeginRequest(JSContext *cx)
883 {
884 #ifdef JS_THREADSAFE
885     cx->outstandingRequests++;
886     StartRequest(cx);
887 #endif
888 }
889
890 JS_PUBLIC_API(void)
891 JS_EndRequest(JSContext *cx)
892 {
893 #ifdef JS_THREADSAFE
894     JS_ASSERT(cx->outstandingRequests != 0);
895     cx->outstandingRequests--;
896     StopRequest(cx);
897 #endif
898 }
899
900 /* Yield to pending GC operations, regardless of request depth */
901 JS_PUBLIC_API(void)
902 JS_YieldRequest(JSContext *cx)
903 {
904 #ifdef JS_THREADSAFE
905     CHECK_REQUEST(cx);
906     JS_ResumeRequest(cx, JS_SuspendRequest(cx));
907 #endif
908 }
909
910 JS_PUBLIC_API(jsrefcount)
911 JS_SuspendRequest(JSContext *cx)
912 {
913 #ifdef JS_THREADSAFE
914     JSThread *t = cx->thread;
915     JS_ASSERT(CURRENT_THREAD_IS_ME(t));
916
917     jsrefcount saveDepth = t->data.requestDepth;
918     if (!saveDepth)
919         return 0;
920
921     t->suspendCount++;
922     t->data.requestDepth = 1;
923     StopRequest(cx);
924     return saveDepth;
925 #else
926     return 0;
927 #endif
928 }
929
930 JS_PUBLIC_API(void)
931 JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
932 {
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
945 }
946
947 JS_PUBLIC_API(JSBool)
948 JS_IsInRequest(JSContext *cx)
949 {
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
956 }
957
958 JS_PUBLIC_API(void)
959 JS_Lock(JSRuntime *rt)
960 {
961     JS_LOCK_RUNTIME(rt);
962 }
963
964 JS_PUBLIC_API(void)
965 JS_Unlock(JSRuntime *rt)
966 {
967     JS_UNLOCK_RUNTIME(rt);
968 }
969
970 JS_PUBLIC_API(JSContextCallback)
971 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
972 {
973     JSContextCallback old;
974
975     old = rt->cxCallback;
976     rt->cxCallback = cxCallback;
977     return old;
978 }
979
980 JS_PUBLIC_API(JSContext *)
981 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
982 {
983     return js_NewContext(rt, stackChunkSize);
984 }
985
986 JS_PUBLIC_API(void)
987 JS_DestroyContext(JSContext *cx)
988 {
989     js_DestroyContext(cx, JSDCM_FORCE_GC);
990 }
991
992 JS_PUBLIC_API(void)
993 JS_DestroyContextNoGC(JSContext *cx)
994 {
995     js_DestroyContext(cx, JSDCM_NO_GC);
996 }
997
998 JS_PUBLIC_API(void)
999 JS_DestroyContextMaybeGC(JSContext *cx)
1000 {
1001     js_DestroyContext(cx, JSDCM_MAYBE_GC);
1002 }
1003
1004 JS_PUBLIC_API(void *)
1005 JS_GetContextPrivate(JSContext *cx)
1006 {
1007     return cx->data;
1008 }
1009
1010 JS_PUBLIC_API(void)
1011 JS_SetContextPrivate(JSContext *cx, void *data)
1012 {
1013     cx->data = data;
1014 }
1015
1016 JS_PUBLIC_API(JSRuntime *)
1017 JS_GetRuntime(JSContext *cx)
1018 {
1019     return cx->runtime;
1020 }
1021
1022 JS_PUBLIC_API(JSContext *)
1023 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
1024 {
1025     return js_ContextIterator(rt, JS_TRUE, iterp);
1026 }
1027
1028 JS_PUBLIC_API(JSVersion)
1029 JS_GetVersion(JSContext *cx)
1030 {
1031     return VersionNumber(cx->findVersion());
1032 }
1033
1034 JS_PUBLIC_API(JSVersion)
1035 JS_SetVersion(JSContext *cx, JSVersion newVersion)
1036 {
1037     JS_ASSERT(VersionIsKnown(newVersion));
1038     JS_ASSERT(!VersionHasFlags(newVersion));
1039     JSVersion newVersionNumber = newVersion;
1040
1041 #ifdef DEBUG
1042     uintN coptsBefore = cx->getCompileOptions();
1043 #endif
1044     JSVersion oldVersion = cx->findVersion();
1045     JSVersion oldVersionNumber = VersionNumber(oldVersion);
1046     if (oldVersionNumber == newVersionNumber)
1047         return oldVersionNumber; /* No override actually occurs! */
1048
1049     /* We no longer support 1.4 or below. */
1050     if (newVersionNumber != JSVERSION_DEFAULT && newVersionNumber <= JSVERSION_1_4)
1051         return oldVersionNumber;
1052
1053     VersionCopyFlags(&newVersion, oldVersion);
1054     cx->maybeOverrideVersion(newVersion);
1055     JS_ASSERT(cx->getCompileOptions() == coptsBefore);
1056     return oldVersionNumber;
1057 }
1058
1059 static struct v2smap {
1060     JSVersion   version;
1061     const char  *string;
1062 } v2smap[] = {
1063     {JSVERSION_1_0,     "1.0"},
1064     {JSVERSION_1_1,     "1.1"},
1065     {JSVERSION_1_2,     "1.2"},
1066     {JSVERSION_1_3,     "1.3"},
1067     {JSVERSION_1_4,     "1.4"},
1068     {JSVERSION_ECMA_3,  "ECMAv3"},
1069     {JSVERSION_1_5,     "1.5"},
1070     {JSVERSION_1_6,     "1.6"},
1071     {JSVERSION_1_7,     "1.7"},
1072     {JSVERSION_1_8,     "1.8"},
1073     {JSVERSION_ECMA_5,  "ECMAv5"},
1074     {JSVERSION_DEFAULT, js_default_str},
1075     {JSVERSION_UNKNOWN, NULL},          /* must be last, NULL is sentinel */
1076 };
1077
1078 JS_PUBLIC_API(const char *)
1079 JS_VersionToString(JSVersion version)
1080 {
1081     int i;
1082
1083     for (i = 0; v2smap[i].string; i++)
1084         if (v2smap[i].version == version)
1085             return v2smap[i].string;
1086     return "unknown";
1087 }
1088
1089 JS_PUBLIC_API(JSVersion)
1090 JS_StringToVersion(const char *string)
1091 {
1092     int i;
1093
1094     for (i = 0; v2smap[i].string; i++)
1095         if (strcmp(v2smap[i].string, string) == 0)
1096             return v2smap[i].version;
1097     return JSVERSION_UNKNOWN;
1098 }
1099
1100 JS_PUBLIC_API(uint32)
1101 JS_GetOptions(JSContext *cx)
1102 {
1103     /*
1104      * Can't check option/version synchronization here.
1105      * We may have been synchronized with a script version that was formerly on
1106      * the stack, but has now been popped.
1107      */
1108     return cx->allOptions();
1109 }
1110
1111 static uintN
1112 SetOptionsCommon(JSContext *cx, uintN options)
1113 {
1114     JS_ASSERT((options & JSALLOPTION_MASK) == options);
1115     uintN oldopts = cx->allOptions();
1116     uintN newropts = options & JSRUNOPTION_MASK;
1117     uintN newcopts = options & JSCOMPILEOPTION_MASK;
1118     cx->setRunOptions(newropts);
1119     cx->setCompileOptions(newcopts);
1120     cx->updateJITEnabled();
1121     return oldopts;
1122 }
1123
1124 JS_PUBLIC_API(uint32)
1125 JS_SetOptions(JSContext *cx, uint32 options)
1126 {
1127     AutoLockGC lock(cx->runtime);
1128     return SetOptionsCommon(cx, options);
1129 }
1130
1131 JS_PUBLIC_API(uint32)
1132 JS_ToggleOptions(JSContext *cx, uint32 options)
1133 {
1134     AutoLockGC lock(cx->runtime);
1135     uintN oldopts = cx->allOptions();
1136     uintN newopts = oldopts ^ options;
1137     return SetOptionsCommon(cx, newopts);
1138 }
1139
1140 JS_PUBLIC_API(const char *)
1141 JS_GetImplementationVersion(void)
1142 {
1143     return "JavaScript-C 1.8.5 2011-03-31";
1144 }
1145
1146 JS_PUBLIC_API(JSCompartmentCallback)
1147 JS_SetCompartmentCallback(JSRuntime *rt, JSCompartmentCallback callback)
1148 {
1149     JSCompartmentCallback old = rt->compartmentCallback;
1150     rt->compartmentCallback = callback;
1151     return old;
1152 }
1153
1154 JS_PUBLIC_API(JSWrapObjectCallback)
1155 JS_SetWrapObjectCallbacks(JSRuntime *rt,
1156                           JSWrapObjectCallback callback,
1157                           JSPreWrapCallback precallback)
1158 {
1159     JSWrapObjectCallback old = rt->wrapObjectCallback;
1160     rt->wrapObjectCallback = callback;
1161     rt->preWrapObjectCallback = precallback;
1162     return old;
1163 }
1164
1165 JS_PUBLIC_API(JSCrossCompartmentCall *)
1166 JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target)
1167 {
1168     CHECK_REQUEST(cx);
1169
1170     JS_ASSERT(target);
1171     AutoCompartment *call = js_new<AutoCompartment>(cx, target);
1172     if (!call)
1173         return NULL;
1174     if (!call->enter()) {
1175         js_delete(call);
1176         return NULL;
1177     }
1178     return reinterpret_cast<JSCrossCompartmentCall *>(call);
1179 }
1180
1181 JS_PUBLIC_API(JSCrossCompartmentCall *)
1182 JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
1183 {
1184     static JSClass dummy_class = {
1185         "jdummy",
1186         JSCLASS_GLOBAL_FLAGS,
1187         JS_PropertyStub,  JS_PropertyStub,
1188         JS_PropertyStub,  JS_StrictPropertyStub,
1189         JS_EnumerateStub, JS_ResolveStub,
1190         JS_ConvertStub,   NULL,
1191         JSCLASS_NO_OPTIONAL_MEMBERS
1192     };
1193
1194     CHECK_REQUEST(cx);
1195
1196     JS_ASSERT(target);
1197     JSObject *scriptObject = target->u.object;
1198     if (!scriptObject) {
1199         SwitchToCompartment sc(cx, target->compartment);
1200         scriptObject = JS_NewGlobalObject(cx, &dummy_class);
1201         if (!scriptObject)
1202             return NULL;        
1203     }
1204     return JS_EnterCrossCompartmentCall(cx, scriptObject);
1205 }
1206
1207 JS_PUBLIC_API(void)
1208 JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
1209 {
1210     AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
1211     CHECK_REQUEST(realcall->context);
1212     realcall->leave();
1213     js_delete(realcall);
1214 }
1215
1216 bool
1217 JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target)
1218 {
1219     JS_ASSERT(!call);
1220     if (cx->compartment == target->getCompartment()) {
1221         call = reinterpret_cast<JSCrossCompartmentCall*>(1);
1222         return true;
1223     }
1224     call = JS_EnterCrossCompartmentCall(cx, target);
1225     return call != NULL;
1226 }
1227
1228 void
1229 JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target)
1230 {
1231     (void) enter(cx, target);
1232 }
1233
1234 namespace JS {
1235
1236 bool
1237 AutoEnterScriptCompartment::enter(JSContext *cx, JSScript *target)
1238 {
1239     JS_ASSERT(!call);
1240     if (cx->compartment == target->compartment) {
1241         call = reinterpret_cast<JSCrossCompartmentCall*>(1);
1242         return true;
1243     }
1244     call = JS_EnterCrossCompartmentCallScript(cx, target);
1245     return call != NULL;    
1246 }
1247
1248 } /* namespace JS */
1249
1250 JS_PUBLIC_API(void *)
1251 JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data)
1252 {
1253     CHECK_REQUEST(cx);
1254     void *old = compartment->data;
1255     compartment->data = data;
1256     return old;
1257 }
1258
1259 JS_PUBLIC_API(void *)
1260 JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment)
1261 {
1262     CHECK_REQUEST(cx);
1263     return compartment->data;
1264 }
1265
1266 JS_PUBLIC_API(JSBool)
1267 JS_WrapObject(JSContext *cx, JSObject **objp)
1268 {
1269     CHECK_REQUEST(cx);
1270     return cx->compartment->wrap(cx, objp);
1271 }
1272
1273 JS_PUBLIC_API(JSBool)
1274 JS_WrapValue(JSContext *cx, jsval *vp)
1275 {
1276     CHECK_REQUEST(cx);
1277     return cx->compartment->wrap(cx, Valueify(vp));
1278 }
1279
1280 JS_PUBLIC_API(JSObject *)
1281 JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target)
1282 {
1283      // This function is called when an object moves between two
1284      // different compartments. In that case, we need to "move" the
1285      // window from origobj's compartment to target's compartment.
1286     JSCompartment *destination = target->getCompartment();
1287     WrapperMap &map = destination->crossCompartmentWrappers;
1288     Value origv = ObjectValue(*origobj);
1289     JSObject *obj;
1290
1291     if (origobj->getCompartment() == destination) {
1292         // If the original object is in the same compartment as the
1293         // destination, then we know that we won't find wrapper in the
1294         // destination's cross compartment map and that the same
1295         // object will continue to work.  Note the rare case where
1296         // |origobj == target|. In that case, we can just treat this
1297         // as a same compartment navigation. The effect is to clear
1298         // all of the wrappers and their holders if they have
1299         // them. This would be cleaner as a separate API.
1300         if (origobj != target && !origobj->swap(cx, target))
1301             return NULL;
1302         obj = origobj;
1303     } else if (WrapperMap::Ptr p = map.lookup(origv)) {
1304         // There might already be a wrapper for the original object in
1305         // the new compartment. If there is, make it the primary outer
1306         // window proxy around the inner (accomplished by swapping
1307         // target's innards with the old, possibly security wrapper,
1308         // innards).
1309         obj = &p->value.toObject();
1310         map.remove(p);
1311         if (!obj->swap(cx, target))
1312             return NULL;
1313     } else {
1314         // Otherwise, this is going to be our outer window proxy in
1315         // the new compartment.
1316         obj = target;
1317     }
1318
1319     // Now, iterate through other scopes looking for references to the
1320     // old outer window. They need to be updated to point at the new
1321     // outer window.  They also might transition between different
1322     // types of security wrappers based on whether the new compartment
1323     // is same origin with them.
1324     Value targetv = ObjectValue(*obj);
1325     WrapperVector &vector = cx->runtime->compartments;
1326     AutoValueVector toTransplant(cx);
1327     toTransplant.reserve(vector.length());
1328
1329     for (JSCompartment **p = vector.begin(), **end = vector.end(); p != end; ++p) {
1330         WrapperMap &pmap = (*p)->crossCompartmentWrappers;
1331         if (WrapperMap::Ptr wp = pmap.lookup(origv)) {
1332             // We found a wrapper. Remember and root it.
1333             toTransplant.append(wp->value);
1334         }
1335     }
1336
1337     for (Value *begin = toTransplant.begin(), *end = toTransplant.end(); begin != end; ++begin) {
1338         JSObject *wobj = &begin->toObject();
1339         JSCompartment *wcompartment = wobj->compartment();
1340         WrapperMap &pmap = wcompartment->crossCompartmentWrappers;
1341         JS_ASSERT(pmap.lookup(origv));
1342         pmap.remove(origv);
1343
1344         // First, we wrap it in the new compartment. This will return
1345         // a new wrapper.
1346         AutoCompartment ac(cx, wobj);
1347         JSObject *tobj = obj;
1348         if (!ac.enter() || !wcompartment->wrap(cx, &tobj))
1349             return NULL;
1350
1351         // Now, because we need to maintain object identity, we do a
1352         // brain transplant on the old object. At the same time, we
1353         // update the entry in the compartment's wrapper map to point
1354         // to the old wrapper.
1355         JS_ASSERT(tobj != wobj);
1356         if (!wobj->swap(cx, tobj))
1357             return NULL;
1358         pmap.put(targetv, ObjectValue(*wobj));
1359     }
1360
1361     // Lastly, update the original object to point to the new one.
1362     if (origobj->getCompartment() != destination) {
1363         AutoCompartment ac(cx, origobj);
1364         JSObject *tobj = obj;
1365         if (!ac.enter() || !JS_WrapObject(cx, &tobj))
1366             return NULL;
1367         if (!origobj->swap(cx, tobj))
1368             return NULL;
1369         origobj->getCompartment()->crossCompartmentWrappers.put(targetv, origv);
1370     }
1371
1372     return obj;
1373 }
1374
1375 /*
1376  * The location object is special. There is the location object itself and
1377  * then the location object wrapper. Because there are no direct references to
1378  * the location object itself, we don't want the old obj (|origobj| here) to
1379  * become the new wrapper but the wrapper itself instead. This leads to very
1380  * subtle differences between js_TransplantObjectWithWrapper and
1381  * JS_TransplantObject.
1382  */
1383 JS_FRIEND_API(JSObject *)
1384 js_TransplantObjectWithWrapper(JSContext *cx,
1385                                JSObject *origobj,
1386                                JSObject *origwrapper,
1387                                JSObject *targetobj,
1388                                JSObject *targetwrapper)
1389 {
1390     JSObject *obj;
1391     JSCompartment *destination = targetobj->getCompartment();
1392     WrapperMap &map = destination->crossCompartmentWrappers;
1393
1394     // |origv| is the map entry we're looking up. The map entries are going to
1395     // be for the location object itself.
1396     Value origv = ObjectValue(*origobj);
1397
1398     // There might already be a wrapper for the original object in the new
1399     // compartment.
1400     if (WrapperMap::Ptr p = map.lookup(origv)) {
1401         // There is. Make the existing wrapper a same compartment location
1402         // wrapper (swapping it with the given new wrapper).
1403         obj = &p->value.toObject();
1404         map.remove(p);
1405         if (!obj->swap(cx, targetwrapper))
1406             return NULL;
1407     } else {
1408         // Otherwise, use the passed-in wrapper as the same compartment
1409         // location wrapper.
1410         obj = targetwrapper;
1411     }
1412
1413     // Now, iterate through other scopes looking for references to the old
1414     // location object. Note that the entries in the maps are for |origobj|
1415     // and not |origwrapper|. They need to be updated to point at the new
1416     // location object.
1417     Value targetv = ObjectValue(*targetobj);
1418     WrapperVector &vector = cx->runtime->compartments;
1419     AutoValueVector toTransplant(cx);
1420     toTransplant.reserve(vector.length());
1421
1422     for (JSCompartment **p = vector.begin(), **end = vector.end(); p != end; ++p) {
1423         WrapperMap &pmap = (*p)->crossCompartmentWrappers;
1424         if (WrapperMap::Ptr wp = pmap.lookup(origv)) {
1425             // We found a wrapper. Remember and root it.
1426             toTransplant.append(wp->value);
1427         }
1428     }
1429
1430     for (Value *begin = toTransplant.begin(), *end = toTransplant.end(); begin != end; ++begin) {
1431         JSObject *wobj = &begin->toObject();
1432         JSCompartment *wcompartment = wobj->compartment();
1433         WrapperMap &pmap = wcompartment->crossCompartmentWrappers;
1434         JS_ASSERT(pmap.lookup(origv));
1435         pmap.remove(origv);
1436
1437         // First, we wrap it in the new compartment. This will return a
1438         // new wrapper.
1439         AutoCompartment ac(cx, wobj);
1440
1441         JSObject *tobj = targetobj;
1442         if (!ac.enter() || !wcompartment->wrap(cx, &tobj))
1443             return NULL;
1444
1445         // Now, because we need to maintain object identity, we do a brain
1446         // transplant on the old object. At the same time, we update the
1447         // entry in the compartment's wrapper map to point to the old
1448         // wrapper.
1449         JS_ASSERT(tobj != wobj);
1450         if (!wobj->swap(cx, tobj))
1451             return NULL;
1452         pmap.put(targetv, ObjectValue(*wobj));
1453     }
1454
1455     // Lastly, update the original object to point to the new one. However, as
1456     // mentioned above, we do the transplant on the wrapper, not the object
1457     // itself, since all of the references are to the object itself.
1458     {
1459         AutoCompartment ac(cx, origobj);
1460         JSObject *tobj = obj;
1461         if (!ac.enter() || !JS_WrapObject(cx, &tobj))
1462             return NULL;
1463         if (!origwrapper->swap(cx, tobj))
1464             return NULL;
1465         origwrapper->getCompartment()->crossCompartmentWrappers.put(targetv,
1466                                                                     ObjectValue(*origwrapper));
1467     }
1468
1469     return obj;
1470 }
1471
1472 JS_PUBLIC_API(JSObject *)
1473 JS_GetGlobalObject(JSContext *cx)
1474 {
1475     return cx->globalObject;
1476 }
1477
1478 JS_PUBLIC_API(void)
1479 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1480 {
1481     CHECK_REQUEST(cx);
1482
1483     cx->globalObject = obj;
1484     if (!cx->hasfp())
1485         cx->resetCompartment();
1486 }
1487
1488 class AutoResolvingEntry {
1489 public:
1490     AutoResolvingEntry() : entry(NULL) {}
1491
1492     /*
1493      * Returns false on error. But N.B. if obj[id] was already being resolved,
1494      * this is a no-op, and we silently treat that as success.
1495      */
1496     bool start(JSContext *cx, JSObject *obj, jsid id, uint32 flag) {
1497         JS_ASSERT(!entry);
1498         this->cx = cx;
1499         key.obj = obj;
1500         key.id = id;
1501         this->flag = flag;
1502         bool ok = !!js_StartResolving(cx, &key, flag, &entry);
1503         JS_ASSERT_IF(!ok, !entry);
1504         return ok;
1505     }
1506
1507     ~AutoResolvingEntry() {
1508         if (entry)
1509             js_StopResolving(cx, &key, flag, NULL, 0);
1510     }
1511
1512 private:
1513     JSContext *cx;
1514     JSResolvingKey key;
1515     uint32 flag;
1516     JSResolvingEntry *entry;
1517 };
1518
1519 JSObject *
1520 js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1521 {
1522     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
1523     JSObject *fun_proto, *obj_proto;
1524
1525     /* If cx has no global object, use obj so prototypes can be found. */
1526     if (!cx->globalObject)
1527         JS_SetGlobalObject(cx, obj);
1528
1529     /* Record Function and Object in cx->resolvingTable. */
1530     AutoResolvingEntry e1, e2;
1531     JSAtom **classAtoms = cx->runtime->atomState.classAtoms;
1532     if (!e1.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Function]), JSRESFLAG_LOOKUP) ||
1533         !e2.start(cx, obj, ATOM_TO_JSID(classAtoms[JSProto_Object]), JSRESFLAG_LOOKUP)) {
1534         return NULL;
1535     }
1536
1537     /* Initialize the function class first so constructors can be made. */
1538     if (!js_GetClassPrototype(cx, obj, JSProto_Function, &fun_proto))
1539         return NULL;
1540     if (!fun_proto) {
1541         fun_proto = js_InitFunctionClass(cx, obj);
1542         if (!fun_proto)
1543             return NULL;
1544     } else {
1545         JSObject *ctor;
1546
1547         ctor = JS_GetConstructor(cx, fun_proto);
1548         if (!ctor)
1549             return NULL;
1550         if (!obj->defineProperty(cx, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
1551                                  ObjectValue(*ctor), 0, 0, 0)) {
1552             return NULL;
1553         }
1554     }
1555
1556     /* Initialize the object class next so Object.prototype works. */
1557     if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto))
1558         return NULL;
1559     if (!obj_proto)
1560         obj_proto = js_InitObjectClass(cx, obj);
1561     if (!obj_proto)
1562         return NULL;
1563
1564     /* Function.prototype and the global object delegate to Object.prototype. */
1565     fun_proto->setProto(obj_proto);
1566     if (!obj->getProto())
1567         obj->setProto(obj_proto);
1568
1569     return fun_proto;
1570 }
1571
1572 JS_PUBLIC_API(JSBool)
1573 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1574 {
1575     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
1576     CHECK_REQUEST(cx);
1577
1578     /*
1579      * JS_SetGlobalObject might or might not change cx's compartment, so call
1580      * it before assertSameCompartment. (The API contract is that *after* this,
1581      * cx and obj must be in the same compartment.)
1582      */
1583     if (!cx->globalObject)
1584         JS_SetGlobalObject(cx, obj);
1585     assertSameCompartment(cx, obj);
1586
1587     /* Define a top-level property 'undefined' with the undefined value. */
1588     JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1589     if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1590                              PropertyStub, StrictPropertyStub,
1591                              JSPROP_PERMANENT | JSPROP_READONLY)) {
1592         return JS_FALSE;
1593     }
1594
1595     /* Function and Object require cooperative bootstrapping magic. */
1596     if (!js_InitFunctionAndObjectClasses(cx, obj))
1597         return JS_FALSE;
1598
1599     /* Initialize the rest of the standard objects and functions. */
1600     return js_InitArrayClass(cx, obj) &&
1601            js_InitBooleanClass(cx, obj) &&
1602            js_InitExceptionClasses(cx, obj) &&
1603            js_InitMathClass(cx, obj) &&
1604            js_InitNumberClass(cx, obj) &&
1605            js_InitJSONClass(cx, obj) &&
1606            js_InitRegExpClass(cx, obj) &&
1607            js_InitStringClass(cx, obj) &&
1608            js_InitTypedArrayClasses(cx, obj) &&
1609 #if JS_HAS_XML_SUPPORT
1610            js_InitXMLClasses(cx, obj) &&
1611 #endif
1612 #if JS_HAS_GENERATORS
1613            js_InitIteratorClasses(cx, obj) &&
1614 #endif
1615            js_InitDateClass(cx, obj) &&
1616            js_InitProxyClass(cx, obj);
1617 }
1618
1619 #define CLASP(name)                 (&js_##name##Class)
1620 #define TYPED_ARRAY_CLASP(type)     (&TypedArray::fastClasses[TypedArray::type])
1621 #define EAGER_ATOM(name)            ATOM_OFFSET(name), NULL
1622 #define EAGER_CLASS_ATOM(name)      CLASS_ATOM_OFFSET(name), NULL
1623 #define EAGER_ATOM_AND_CLASP(name)  EAGER_CLASS_ATOM(name), CLASP(name)
1624 #define LAZY_ATOM(name)             ATOM_OFFSET(lazy.name), js_##name##_str
1625
1626 typedef struct JSStdName {
1627     JSObjectOp  init;
1628     size_t      atomOffset;     /* offset of atom pointer in JSAtomState */
1629     const char  *name;          /* null if atom is pre-pinned, else name */
1630     Class       *clasp;
1631 } JSStdName;
1632
1633 static JSAtom *
1634 StdNameToAtom(JSContext *cx, JSStdName *stdn)
1635 {
1636     size_t offset;
1637     JSAtom *atom;
1638     const char *name;
1639
1640     offset = stdn->atomOffset;
1641     atom = OFFSET_TO_ATOM(cx->runtime, offset);
1642     if (!atom) {
1643         name = stdn->name;
1644         if (name) {
1645             atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1646             OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1647         }
1648     }
1649     return atom;
1650 }
1651
1652 /*
1653  * Table of class initializers and their atom offsets in rt->atomState.
1654  * If you add a "standard" class, remember to update this table.
1655  */
1656 static JSStdName standard_class_atoms[] = {
1657     {js_InitFunctionAndObjectClasses,   EAGER_ATOM_AND_CLASP(Function)},
1658     {js_InitFunctionAndObjectClasses,   EAGER_ATOM_AND_CLASP(Object)},
1659     {js_InitArrayClass,                 EAGER_ATOM_AND_CLASP(Array)},
1660     {js_InitBooleanClass,               EAGER_ATOM_AND_CLASP(Boolean)},
1661     {js_InitDateClass,                  EAGER_ATOM_AND_CLASP(Date)},
1662     {js_InitMathClass,                  EAGER_ATOM_AND_CLASP(Math)},
1663     {js_InitNumberClass,                EAGER_ATOM_AND_CLASP(Number)},
1664     {js_InitStringClass,                EAGER_ATOM_AND_CLASP(String)},
1665     {js_InitExceptionClasses,           EAGER_ATOM_AND_CLASP(Error)},
1666     {js_InitRegExpClass,                EAGER_ATOM_AND_CLASP(RegExp)},
1667 #if JS_HAS_XML_SUPPORT
1668     {js_InitXMLClass,                   EAGER_ATOM_AND_CLASP(XML)},
1669     {js_InitNamespaceClass,             EAGER_ATOM_AND_CLASP(Namespace)},
1670     {js_InitQNameClass,                 EAGER_ATOM_AND_CLASP(QName)},
1671 #endif
1672 #if JS_HAS_GENERATORS
1673     {js_InitIteratorClasses,            EAGER_ATOM_AND_CLASP(StopIteration)},
1674 #endif
1675     {js_InitJSONClass,                  EAGER_ATOM_AND_CLASP(JSON)},
1676     {js_InitTypedArrayClasses,          EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
1677     {NULL,                              0, NULL, NULL}
1678 };
1679
1680 /*
1681  * Table of top-level function and constant names and their init functions.
1682  * If you add a "standard" global function or property, remember to update
1683  * this table.
1684  */
1685 static JSStdName standard_class_names[] = {
1686     {js_InitObjectClass,        EAGER_ATOM(eval), CLASP(Object)},
1687
1688     /* Global properties and functions defined by the Number class. */
1689     {js_InitNumberClass,        EAGER_ATOM(NaN), CLASP(Number)},
1690     {js_InitNumberClass,        EAGER_ATOM(Infinity), CLASP(Number)},
1691     {js_InitNumberClass,        LAZY_ATOM(isNaN), CLASP(Number)},
1692     {js_InitNumberClass,        LAZY_ATOM(isFinite), CLASP(Number)},
1693     {js_InitNumberClass,        LAZY_ATOM(parseFloat), CLASP(Number)},
1694     {js_InitNumberClass,        LAZY_ATOM(parseInt), CLASP(Number)},
1695
1696     /* String global functions. */
1697     {js_InitStringClass,        LAZY_ATOM(escape), CLASP(String)},
1698     {js_InitStringClass,        LAZY_ATOM(unescape), CLASP(String)},
1699     {js_InitStringClass,        LAZY_ATOM(decodeURI), CLASP(String)},
1700     {js_InitStringClass,        LAZY_ATOM(encodeURI), CLASP(String)},
1701     {js_InitStringClass,        LAZY_ATOM(decodeURIComponent), CLASP(String)},
1702     {js_InitStringClass,        LAZY_ATOM(encodeURIComponent), CLASP(String)},
1703 #if JS_HAS_UNEVAL
1704     {js_InitStringClass,        LAZY_ATOM(uneval), CLASP(String)},
1705 #endif
1706
1707     /* Exception constructors. */
1708     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(Error), CLASP(Error)},
1709     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
1710     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
1711     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
1712     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
1713     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
1714     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
1715     {js_InitExceptionClasses,   EAGER_CLASS_ATOM(URIError), CLASP(Error)},
1716
1717 #if JS_HAS_XML_SUPPORT
1718     {js_InitXMLClass,           LAZY_ATOM(XMLList), CLASP(XML)},
1719     {js_InitXMLClass,           LAZY_ATOM(isXMLName), CLASP(XML)},
1720 #endif
1721
1722 #if JS_HAS_GENERATORS
1723     {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Iterator)},
1724     {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Generator)},
1725 #endif
1726
1727     /* Typed Arrays */
1728     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
1729     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int8Array),    TYPED_ARRAY_CLASP(TYPE_INT8)},
1730     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint8Array),   TYPED_ARRAY_CLASP(TYPE_UINT8)},
1731     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int16Array),   TYPED_ARRAY_CLASP(TYPE_INT16)},
1732     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint16Array),  TYPED_ARRAY_CLASP(TYPE_UINT16)},
1733     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int32Array),   TYPED_ARRAY_CLASP(TYPE_INT32)},
1734     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint32Array),  TYPED_ARRAY_CLASP(TYPE_UINT32)},
1735     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Float32Array), TYPED_ARRAY_CLASP(TYPE_FLOAT32)},
1736     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
1737     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint8ClampedArray),
1738                                 TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
1739
1740     {js_InitProxyClass,         EAGER_ATOM_AND_CLASP(Proxy)},
1741
1742     {NULL,                      0, NULL, NULL}
1743 };
1744
1745 static JSStdName object_prototype_names[] = {
1746     /* Object.prototype properties (global delegates to Object.prototype). */
1747     {js_InitObjectClass,        EAGER_ATOM(proto), CLASP(Object)},
1748 #if JS_HAS_TOSOURCE
1749     {js_InitObjectClass,        EAGER_ATOM(toSource), CLASP(Object)},
1750 #endif
1751     {js_InitObjectClass,        EAGER_ATOM(toString), CLASP(Object)},
1752     {js_InitObjectClass,        EAGER_ATOM(toLocaleString), CLASP(Object)},
1753     {js_InitObjectClass,        EAGER_ATOM(valueOf), CLASP(Object)},
1754 #if JS_HAS_OBJ_WATCHPOINT
1755     {js_InitObjectClass,        LAZY_ATOM(watch), CLASP(Object)},
1756     {js_InitObjectClass,        LAZY_ATOM(unwatch), CLASP(Object)},
1757 #endif
1758     {js_InitObjectClass,        LAZY_ATOM(hasOwnProperty), CLASP(Object)},
1759     {js_InitObjectClass,        LAZY_ATOM(isPrototypeOf), CLASP(Object)},
1760     {js_InitObjectClass,        LAZY_ATOM(propertyIsEnumerable), CLASP(Object)},
1761 #if OLD_GETTER_SETTER_METHODS
1762     {js_InitObjectClass,        LAZY_ATOM(defineGetter), CLASP(Object)},
1763     {js_InitObjectClass,        LAZY_ATOM(defineSetter), CLASP(Object)},
1764     {js_InitObjectClass,        LAZY_ATOM(lookupGetter), CLASP(Object)},
1765     {js_InitObjectClass,        LAZY_ATOM(lookupSetter), CLASP(Object)},
1766 #endif
1767
1768     {NULL,                      0, NULL, NULL}
1769 };
1770
1771 JS_PUBLIC_API(JSBool)
1772 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
1773 {
1774     JSString *idstr;
1775     JSRuntime *rt;
1776     JSAtom *atom;
1777     JSStdName *stdnm;
1778     uintN i;
1779
1780     CHECK_REQUEST(cx);
1781     assertSameCompartment(cx, obj, id);
1782     *resolved = JS_FALSE;
1783
1784     rt = cx->runtime;
1785     JS_ASSERT(rt->state != JSRTS_DOWN);
1786     if (rt->state == JSRTS_LANDING || !JSID_IS_ATOM(id))
1787         return JS_TRUE;
1788
1789     idstr = JSID_TO_STRING(id);
1790
1791     /* Check whether we're resolving 'undefined', and define it if so. */
1792     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1793     if (idstr == ATOM_TO_STRING(atom)) {
1794         *resolved = JS_TRUE;
1795         return obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1796                                    PropertyStub, StrictPropertyStub,
1797                                    JSPROP_PERMANENT | JSPROP_READONLY);
1798     }
1799
1800     /* Try for class constructors/prototypes named by well-known atoms. */
1801     stdnm = NULL;
1802     for (i = 0; standard_class_atoms[i].init; i++) {
1803         JS_ASSERT(standard_class_atoms[i].clasp);
1804         atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1805         if (idstr == ATOM_TO_STRING(atom)) {
1806             stdnm = &standard_class_atoms[i];
1807             break;
1808         }
1809     }
1810
1811     if (!stdnm) {
1812         /* Try less frequently used top-level functions and constants. */
1813         for (i = 0; standard_class_names[i].init; i++) {
1814             JS_ASSERT(standard_class_names[i].clasp);
1815             atom = StdNameToAtom(cx, &standard_class_names[i]);
1816             if (!atom)
1817                 return JS_FALSE;
1818             if (idstr == ATOM_TO_STRING(atom)) {
1819                 stdnm = &standard_class_names[i];
1820                 break;
1821             }
1822         }
1823
1824         if (!stdnm && !obj->getProto()) {
1825             /*
1826              * Try even less frequently used names delegated from the global
1827              * object to Object.prototype, but only if the Object class hasn't
1828              * yet been initialized.
1829              */
1830             for (i = 0; object_prototype_names[i].init; i++) {
1831                 JS_ASSERT(object_prototype_names[i].clasp);
1832                 atom = StdNameToAtom(cx, &object_prototype_names[i]);
1833                 if (!atom)
1834                     return JS_FALSE;
1835                 if (idstr == ATOM_TO_STRING(atom)) {
1836                     stdnm = &object_prototype_names[i];
1837                     break;
1838                 }
1839             }
1840         }
1841     }
1842
1843     if (stdnm) {
1844         /*
1845          * If this standard class is anonymous, then we don't want to resolve
1846          * by name.
1847          */
1848         JS_ASSERT(obj->isGlobal());
1849         if (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS)
1850             return JS_TRUE;
1851
1852         JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(stdnm->clasp);
1853         if (obj->getReservedSlot(key).isObject())
1854             return JS_TRUE;
1855
1856         if (!stdnm->init(cx, obj))
1857             return JS_FALSE;
1858         *resolved = JS_TRUE;
1859     }
1860     return JS_TRUE;
1861 }
1862
1863 JS_PUBLIC_API(JSBool)
1864 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1865 {
1866     JSRuntime *rt;
1867     JSAtom *atom;
1868     uintN i;
1869
1870     CHECK_REQUEST(cx);
1871     assertSameCompartment(cx, obj);
1872     rt = cx->runtime;
1873
1874     /* Check whether we need to bind 'undefined' and define it if so. */
1875     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1876     if (!obj->nativeContains(ATOM_TO_JSID(atom)) &&
1877         !obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
1878                              PropertyStub, StrictPropertyStub,
1879                              JSPROP_PERMANENT | JSPROP_READONLY)) {
1880         return JS_FALSE;
1881     }
1882
1883     /* Initialize any classes that have not been resolved yet. */
1884     for (i = 0; standard_class_atoms[i].init; i++) {
1885         atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1886         if (!obj->nativeContains(ATOM_TO_JSID(atom)) &&
1887             !standard_class_atoms[i].init(cx, obj)) {
1888             return JS_FALSE;
1889         }
1890     }
1891
1892     return JS_TRUE;
1893 }
1894
1895 namespace js {
1896
1897 JSIdArray *
1898 NewIdArray(JSContext *cx, jsint length)
1899 {
1900     JSIdArray *ida;
1901
1902     ida = (JSIdArray *)
1903         cx->calloc(offsetof(JSIdArray, vector) + length * sizeof(jsval));
1904     if (ida)
1905         ida->length = length;
1906     return ida;
1907 }
1908
1909 }
1910
1911 /*
1912  * Unlike realloc(3), this function frees ida on failure.
1913  */
1914 static JSIdArray *
1915 SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
1916 {
1917     JSIdArray *rida;
1918
1919     rida = (JSIdArray *)
1920            JS_realloc(cx, ida,
1921                       offsetof(JSIdArray, vector) + length * sizeof(jsval));
1922     if (!rida) {
1923         JS_DestroyIdArray(cx, ida);
1924     } else {
1925         rida->length = length;
1926     }
1927     return rida;
1928 }
1929
1930 static JSIdArray *
1931 AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1932 {
1933     jsint i, length;
1934
1935     i = *ip;
1936     length = ida->length;
1937     if (i >= length) {
1938         ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
1939         if (!ida)
1940             return NULL;
1941         JS_ASSERT(i < ida->length);
1942     }
1943     ida->vector[i] = ATOM_TO_JSID(atom);
1944     *ip = i + 1;
1945     return ida;
1946 }
1947
1948 static JSIdArray *
1949 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
1950                     jsint *ip, JSBool *foundp)
1951 {
1952     *foundp = obj->nativeContains(ATOM_TO_JSID(atom));
1953     if (*foundp)
1954         ida = AddAtomToArray(cx, atom, ida, ip);
1955     return ida;
1956 }
1957
1958 JS_PUBLIC_API(JSIdArray *)
1959 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, JSIdArray *ida)
1960 {
1961     JSRuntime *rt;
1962     jsint i, j, k;
1963     JSAtom *atom;
1964     JSBool found;
1965     JSObjectOp init;
1966
1967     CHECK_REQUEST(cx);
1968     assertSameCompartment(cx, obj, ida);
1969     rt = cx->runtime;
1970     if (ida) {
1971         i = ida->length;
1972     } else {
1973         ida = NewIdArray(cx, 8);
1974         if (!ida)
1975             return NULL;
1976         i = 0;
1977     }
1978
1979     /* Check whether 'undefined' has been resolved and enumerate it if so. */
1980     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1981     ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1982     if (!ida)
1983         return NULL;
1984
1985     /* Enumerate only classes that *have* been resolved. */
1986     for (j = 0; standard_class_atoms[j].init; j++) {
1987         atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
1988         ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1989         if (!ida)
1990             return NULL;
1991
1992         if (found) {
1993             init = standard_class_atoms[j].init;
1994
1995             for (k = 0; standard_class_names[k].init; k++) {
1996                 if (standard_class_names[k].init == init) {
1997                     atom = StdNameToAtom(cx, &standard_class_names[k]);
1998                     ida = AddAtomToArray(cx, atom, ida, &i);
1999                     if (!ida)
2000                         return NULL;
2001                 }
2002             }
2003
2004             if (init == js_InitObjectClass) {
2005                 for (k = 0; object_prototype_names[k].init; k++) {
2006                     atom = StdNameToAtom(cx, &object_prototype_names[k]);
2007                     ida = AddAtomToArray(cx, atom, ida, &i);
2008                     if (!ida)
2009                         return NULL;
2010                 }
2011             }
2012         }
2013     }
2014
2015     /* Trim to exact length. */
2016     return SetIdArrayLength(cx, ida, i);
2017 }
2018
2019 #undef CLASP
2020 #undef EAGER_ATOM
2021 #undef EAGER_CLASS_ATOM
2022 #undef EAGER_ATOM_CLASP
2023 #undef LAZY_ATOM
2024
2025 JS_PUBLIC_API(JSBool)
2026 JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp)
2027 {
2028     CHECK_REQUEST(cx);
2029     assertSameCompartment(cx, obj);
2030     return js_GetClassObject(cx, obj, key, objp);
2031 }
2032
2033 JS_PUBLIC_API(JSObject *)
2034 JS_GetScopeChain(JSContext *cx)
2035 {
2036     CHECK_REQUEST(cx);
2037     return GetScopeChain(cx);
2038 }
2039
2040 JS_PUBLIC_API(JSObject *)
2041 JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
2042 {
2043     assertSameCompartment(cx, obj);
2044     return obj->getGlobal();
2045 }
2046
2047 JS_PUBLIC_API(JSObject *)
2048 JS_GetGlobalForScopeChain(JSContext *cx)
2049 {
2050     CHECK_REQUEST(cx);
2051     return GetGlobalForScopeChain(cx);
2052 }
2053
2054 JS_PUBLIC_API(jsval)
2055 JS_ComputeThis(JSContext *cx, jsval *vp)
2056 {
2057     assertSameCompartment(cx, JSValueArray(vp, 2));
2058     return BoxThisForVp(cx, Valueify(vp)) ? vp[1] : JSVAL_NULL;
2059 }
2060
2061 JS_PUBLIC_API(void *)
2062 JS_malloc(JSContext *cx, size_t nbytes)
2063 {
2064     return cx->malloc(nbytes);
2065 }
2066
2067 JS_PUBLIC_API(void *)
2068 JS_realloc(JSContext *cx, void *p, size_t nbytes)
2069 {
2070     return cx->realloc(p, nbytes);
2071 }
2072
2073 JS_PUBLIC_API(void)
2074 JS_free(JSContext *cx, void *p)
2075 {
2076     return cx->free(p);
2077 }
2078
2079 JS_PUBLIC_API(void)
2080 JS_updateMallocCounter(JSContext *cx, size_t nbytes)
2081 {
2082     return cx->runtime->updateMallocCounter(nbytes);
2083 }
2084
2085 JS_PUBLIC_API(char *)
2086 JS_strdup(JSContext *cx, const char *s)
2087 {
2088     size_t n;
2089     void *p;
2090
2091     n = strlen(s) + 1;
2092     p = cx->malloc(n);
2093     if (!p)
2094         return NULL;
2095     return (char *)memcpy(p, s, n);
2096 }
2097
2098 JS_PUBLIC_API(JSBool)
2099 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
2100 {
2101     d = JS_CANONICALIZE_NAN(d);
2102     Valueify(rval)->setNumber(d);
2103     return JS_TRUE;
2104 }
2105
2106 #undef JS_AddRoot
2107
2108 JS_PUBLIC_API(JSBool)
2109 JS_AddValueRoot(JSContext *cx, jsval *vp)
2110 {
2111     CHECK_REQUEST(cx);
2112     return js_AddRoot(cx, Valueify(vp), NULL);
2113 }
2114
2115 JS_PUBLIC_API(JSBool)
2116 JS_AddStringRoot(JSContext *cx, JSString **rp)
2117 {
2118     CHECK_REQUEST(cx);
2119     return js_AddGCThingRoot(cx, (void **)rp, NULL);
2120 }
2121
2122 JS_PUBLIC_API(JSBool)
2123 JS_AddObjectRoot(JSContext *cx, JSObject **rp)
2124 {
2125     CHECK_REQUEST(cx);
2126     return js_AddGCThingRoot(cx, (void **)rp, NULL);
2127 }
2128
2129 JS_PUBLIC_API(JSBool)
2130 JS_AddGCThingRoot(JSContext *cx, void **rp)
2131 {
2132     CHECK_REQUEST(cx);
2133     return js_AddGCThingRoot(cx, (void **)rp, NULL);
2134 }
2135
2136 JS_PUBLIC_API(JSBool)
2137 JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name)
2138 {
2139     CHECK_REQUEST(cx);
2140     return js_AddRoot(cx, Valueify(vp), name);
2141 }
2142
2143 JS_PUBLIC_API(JSBool)
2144 JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name)
2145 {
2146     CHECK_REQUEST(cx);
2147     return js_AddGCThingRoot(cx, (void **)rp, name);
2148 }
2149
2150 JS_PUBLIC_API(JSBool)
2151 JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name)
2152 {
2153     CHECK_REQUEST(cx);
2154     return js_AddGCThingRoot(cx, (void **)rp, name);
2155 }
2156
2157 JS_PUBLIC_API(JSBool)
2158 JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name)
2159 {
2160     CHECK_REQUEST(cx);
2161     return js_AddGCThingRoot(cx, (void **)rp, name);
2162 }
2163
2164 JS_PUBLIC_API(JSBool)
2165 JS_RemoveValueRoot(JSContext *cx, jsval *vp)
2166 {
2167     CHECK_REQUEST(cx);
2168     return js_RemoveRoot(cx->runtime, (void *)vp);
2169 }
2170
2171 JS_PUBLIC_API(JSBool)
2172 JS_RemoveStringRoot(JSContext *cx, JSString **rp)
2173 {
2174     CHECK_REQUEST(cx);
2175     return js_RemoveRoot(cx->runtime, (void *)rp);
2176 }
2177
2178 JS_PUBLIC_API(JSBool)
2179 JS_RemoveObjectRoot(JSContext *cx, JSObject **rp)
2180 {
2181     CHECK_REQUEST(cx);
2182     return js_RemoveRoot(cx->runtime, (void *)rp);
2183 }
2184
2185 JS_PUBLIC_API(JSBool)
2186 JS_RemoveGCThingRoot(JSContext *cx, void **rp)
2187 {
2188     CHECK_REQUEST(cx);
2189     return js_RemoveRoot(cx->runtime, (void *)rp);
2190 }
2191
2192 JS_NEVER_INLINE JS_PUBLIC_API(void)
2193 JS_AnchorPtr(void *p)
2194 {
2195 }
2196
2197 #ifdef DEBUG
2198
2199 JS_PUBLIC_API(void)
2200 JS_DumpNamedRoots(JSRuntime *rt,
2201                   void (*dump)(const char *name, void *rp, JSGCRootType type, void *data),
2202                   void *data)
2203 {
2204     js_DumpNamedRoots(rt, dump, data);
2205 }
2206
2207 #endif /* DEBUG */
2208
2209 JS_PUBLIC_API(uint32)
2210 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
2211 {
2212     return js_MapGCRoots(rt, map, data);
2213 }
2214
2215 JS_PUBLIC_API(JSBool)
2216 JS_LockGCThing(JSContext *cx, void *thing)
2217 {
2218     JSBool ok;
2219
2220     CHECK_REQUEST(cx);
2221     ok = js_LockGCThingRT(cx->runtime, thing);
2222     if (!ok)
2223         JS_ReportOutOfMemory(cx);
2224     return ok;
2225 }
2226
2227 JS_PUBLIC_API(JSBool)
2228 JS_LockGCThingRT(JSRuntime *rt, void *thing)
2229 {
2230     return js_LockGCThingRT(rt, thing);
2231 }
2232
2233 JS_PUBLIC_API(JSBool)
2234 JS_UnlockGCThing(JSContext *cx, void *thing)
2235 {
2236     CHECK_REQUEST(cx);
2237     js_UnlockGCThingRT(cx->runtime, thing);
2238     return true;
2239 }
2240
2241 JS_PUBLIC_API(JSBool)
2242 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
2243 {
2244     js_UnlockGCThingRT(rt, thing);
2245     return true;
2246 }
2247
2248 JS_PUBLIC_API(void)
2249 JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
2250 {
2251     rt->gcExtraRootsTraceOp = traceOp;
2252     rt->gcExtraRootsData = data;
2253 }
2254
2255 JS_PUBLIC_API(void)
2256 JS_TraceRuntime(JSTracer *trc)
2257 {
2258     TraceRuntime(trc);
2259 }
2260
2261 JS_PUBLIC_API(void)
2262 JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
2263 {
2264     JS_ASSERT(thing);
2265     MarkKind(trc, thing, kind);
2266 }
2267
2268 #ifdef DEBUG
2269
2270 #ifdef HAVE_XPCONNECT
2271 #include "dump_xpc.h"
2272 #endif
2273
2274 JS_PUBLIC_API(void)
2275 JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, uint32 kind,
2276                        JSBool details)
2277 {
2278     const char *name;
2279     size_t n;
2280
2281     if (bufsize == 0)
2282         return;
2283
2284     switch (kind) {
2285       case JSTRACE_OBJECT:
2286       {
2287         JSObject *obj = (JSObject *)thing;
2288         Class *clasp = obj->getClass();
2289
2290         name = clasp->name;
2291 #ifdef HAVE_XPCONNECT
2292         if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
2293             void *privateThing = obj->getPrivate();
2294             if (privateThing) {
2295                 const char *xpcClassName = GetXPCObjectClassName(privateThing);
2296                 if (xpcClassName)
2297                     name = xpcClassName;
2298             }
2299         }
2300 #endif
2301         break;
2302       }
2303
2304       case JSTRACE_STRING:
2305         name = ((JSString *)thing)->isDependent()
2306                ? "substring"
2307                : "string";
2308         break;
2309
2310 #if JS_HAS_XML_SUPPORT
2311       case JSTRACE_XML:
2312         name = "xml";
2313         break;
2314 #endif
2315       default:
2316         JS_ASSERT(0);
2317         return;
2318         break;
2319     }
2320
2321     n = strlen(name);
2322     if (n > bufsize - 1)
2323         n = bufsize - 1;
2324     memcpy(buf, name, n + 1);
2325     buf += n;
2326     bufsize -= n;
2327
2328     if (details && bufsize > 2) {
2329         *buf++ = ' ';
2330         bufsize--;
2331
2332         switch (kind) {
2333           case JSTRACE_OBJECT:
2334           {
2335             JSObject  *obj = (JSObject *)thing;
2336             Class *clasp = obj->getClass();
2337             if (clasp == &js_FunctionClass) {
2338                 JSFunction *fun = GET_FUNCTION_PRIVATE(trc->context, obj);
2339                 if (!fun) {
2340                     JS_snprintf(buf, bufsize, "<newborn>");
2341                 } else if (FUN_OBJECT(fun) != obj) {
2342                     JS_snprintf(buf, bufsize, "%p", fun);
2343                 } else {
2344                     if (fun->atom)
2345                         PutEscapedString(buf, bufsize, ATOM_TO_STRING(fun->atom), 0);
2346                 }
2347             } else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
2348                 JS_snprintf(buf, bufsize, "%p", obj->getPrivate());
2349             } else {
2350                 JS_snprintf(buf, bufsize, "<no private>");
2351             }
2352             break;
2353           }
2354
2355           case JSTRACE_STRING:
2356           {
2357             JSString *str = (JSString *)thing;
2358             if (str->isLinear())
2359                 PutEscapedString(buf, bufsize, str->assertIsLinear(), 0);
2360             else
2361                 JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
2362             break;
2363           }
2364
2365 #if JS_HAS_XML_SUPPORT
2366           case JSTRACE_XML:
2367           {
2368             extern const char *js_xml_class_str[];
2369             JSXML *xml = (JSXML *)thing;
2370
2371             JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]);
2372             break;
2373           }
2374 #endif
2375           default:
2376             JS_ASSERT(0);
2377             break;
2378         }
2379     }
2380     buf[bufsize - 1] = '\0';
2381 }
2382
2383 typedef struct JSHeapDumpNode JSHeapDumpNode;
2384
2385 struct JSHeapDumpNode {
2386     void            *thing;
2387     uint32          kind;
2388     JSHeapDumpNode  *next;          /* next sibling */
2389     JSHeapDumpNode  *parent;        /* node with the thing that refer to thing
2390                                        from this node */
2391     char            edgeName[1];    /* name of the edge from parent->thing
2392                                        into thing */
2393 };
2394
2395 typedef struct JSDumpingTracer {
2396     JSTracer            base;
2397     JSDHashTable        visited;
2398     JSBool              ok;
2399     void                *startThing;
2400     void                *thingToFind;
2401     void                *thingToIgnore;
2402     JSHeapDumpNode      *parentNode;
2403     JSHeapDumpNode      **lastNodep;
2404     char                buffer[200];
2405 } JSDumpingTracer;
2406
2407 static void
2408 DumpNotify(JSTracer *trc, void *thing, uint32 kind)
2409 {
2410     JSDumpingTracer *dtrc;
2411     JSContext *cx;
2412     JSDHashEntryStub *entry;
2413     JSHeapDumpNode *node;
2414     const char *edgeName;
2415     size_t edgeNameSize;
2416
2417     JS_ASSERT(trc->callback == DumpNotify);
2418     dtrc = (JSDumpingTracer *)trc;
2419
2420     if (!dtrc->ok || thing == dtrc->thingToIgnore)
2421         return;
2422
2423     cx = trc->context;
2424
2425     /*
2426      * Check if we have already seen thing unless it is thingToFind to include
2427      * it to the graph each time we reach it and print all live things that
2428      * refer to thingToFind.
2429      *
2430      * This does not print all possible paths leading to thingToFind since
2431      * when a thing A refers directly or indirectly to thingToFind and A is
2432      * present several times in the graph, we will print only the first path
2433      * leading to A and thingToFind, other ways to reach A will be ignored.
2434      */
2435     if (dtrc->thingToFind != thing) {
2436         /*
2437          * The startThing check allows to avoid putting startThing into the
2438          * hash table before tracing startThing in JS_DumpHeap.
2439          */
2440         if (thing == dtrc->startThing)
2441             return;
2442         entry = (JSDHashEntryStub *)
2443             JS_DHashTableOperate(&dtrc->visited, thing, JS_DHASH_ADD);
2444         if (!entry) {
2445             JS_ReportOutOfMemory(cx);
2446             dtrc->ok = JS_FALSE;
2447             return;
2448         }
2449         if (entry->key)
2450             return;
2451         entry->key = thing;
2452     }
2453
2454     if (dtrc->base.debugPrinter) {
2455         dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer));
2456         edgeName = dtrc->buffer;
2457     } else if (dtrc->base.debugPrintIndex != (size_t)-1) {
2458         JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]",
2459                     (const char *)dtrc->base.debugPrintArg,
2460                     dtrc->base.debugPrintIndex);
2461         edgeName = dtrc->buffer;
2462     } else {
2463         edgeName = (const char*)dtrc->base.debugPrintArg;
2464     }
2465
2466     edgeNameSize = strlen(edgeName) + 1;
2467     node = (JSHeapDumpNode *) js_malloc(offsetof(JSHeapDumpNode, edgeName) + edgeNameSize);
2468     if (!node) {
2469         dtrc->ok = JS_FALSE;
2470         return;
2471     }
2472
2473     node->thing = thing;
2474     node->kind = kind;
2475     node->next = NULL;
2476     node->parent = dtrc->parentNode;
2477     memcpy(node->edgeName, edgeName, edgeNameSize);
2478
2479     JS_ASSERT(!*dtrc->lastNodep);
2480     *dtrc->lastNodep = node;
2481     dtrc->lastNodep = &node->next;
2482 }
2483
2484 /* Dump node and the chain that leads to thing it contains. */
2485 static JSBool
2486 DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
2487 {
2488     JSHeapDumpNode *prev, *following;
2489     size_t chainLimit;
2490     JSBool ok;
2491     enum { MAX_PARENTS_TO_PRINT = 10 };
2492
2493     JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2494                            &dtrc->base, node->thing, node->kind, JS_TRUE);
2495     if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
2496         return JS_FALSE;
2497
2498     /*
2499      * We need to print the parent chain in the reverse order. To do it in
2500      * O(N) time where N is the chain length we first reverse the chain while
2501      * searching for the top and then print each node while restoring the
2502      * chain order.
2503      */
2504     chainLimit = MAX_PARENTS_TO_PRINT;
2505     prev = NULL;
2506     for (;;) {
2507         following = node->parent;
2508         node->parent = prev;
2509         prev = node;
2510         node = following;
2511         if (!node)
2512             break;
2513         if (chainLimit == 0) {
2514             if (fputs("...", fp) < 0)
2515                 return JS_FALSE;
2516             break;
2517         }
2518         --chainLimit;
2519     }
2520
2521     node = prev;
2522     prev = following;
2523     ok = JS_TRUE;
2524     do {
2525         /* Loop must continue even when !ok to restore the parent chain. */
2526         if (ok) {
2527             if (!prev) {
2528                 /* Print edge from some runtime root or startThing. */
2529                 if (fputs(node->edgeName, fp) < 0)
2530                     ok = JS_FALSE;
2531             } else {
2532                 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2533                                        &dtrc->base, prev->thing, prev->kind,
2534                                        JS_FALSE);
2535                 if (fprintf(fp, "(%p %s).%s",
2536                            prev->thing, dtrc->buffer, node->edgeName) < 0) {
2537                     ok = JS_FALSE;
2538                 }
2539             }
2540         }
2541         following = node->parent;
2542         node->parent = prev;
2543         prev = node;
2544         node = following;
2545     } while (node);
2546
2547     return ok && putc('\n', fp) >= 0;
2548 }
2549
2550 JS_PUBLIC_API(JSBool)
2551 JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind,
2552             void *thingToFind, size_t maxDepth, void *thingToIgnore)
2553 {
2554     JSDumpingTracer dtrc;
2555     JSHeapDumpNode *node, *children, *next, *parent;
2556     size_t depth;
2557     JSBool thingToFindWasTraced;
2558
2559     if (maxDepth == 0)
2560         return JS_TRUE;
2561
2562     JS_TRACER_INIT(&dtrc.base, cx, DumpNotify);
2563     if (!JS_DHashTableInit(&dtrc.visited, JS_DHashGetStubOps(),
2564                            NULL, sizeof(JSDHashEntryStub),
2565                            JS_DHASH_DEFAULT_CAPACITY(100))) {
2566         JS_ReportOutOfMemory(cx);
2567         return JS_FALSE;
2568     }
2569     dtrc.ok = JS_TRUE;
2570     dtrc.startThing = startThing;
2571     dtrc.thingToFind = thingToFind;
2572     dtrc.thingToIgnore = thingToIgnore;
2573     dtrc.parentNode = NULL;
2574     node = NULL;
2575     dtrc.lastNodep = &node;
2576     if (!startThing) {
2577         JS_ASSERT(startKind == 0);
2578         TraceRuntime(&dtrc.base);
2579     } else {
2580         JS_TraceChildren(&dtrc.base, startThing, startKind);
2581     }
2582
2583     depth = 1;
2584     if (!node)
2585         goto dump_out;
2586
2587     thingToFindWasTraced = thingToFind && thingToFind == startThing;
2588     for (;;) {
2589         /*
2590          * Loop must continue even when !dtrc.ok to free all nodes allocated
2591          * so far.
2592          */
2593         if (dtrc.ok) {
2594             if (thingToFind == NULL || thingToFind == node->thing)
2595                 dtrc.ok = DumpNode(&dtrc, fp, node);
2596
2597             /* Descend into children. */
2598             if (dtrc.ok &&
2599                 depth < maxDepth &&
2600                 (thingToFind != node->thing || !thingToFindWasTraced)) {
2601                 dtrc.parentNode = node;
2602                 children = NULL;
2603                 dtrc.lastNodep = &children;
2604                 JS_TraceChildren(&dtrc.base, node->thing, node->kind);
2605                 if (thingToFind == node->thing)
2606                     thingToFindWasTraced = JS_TRUE;
2607                 if (children != NULL) {
2608                     ++depth;
2609                     node = children;
2610                     continue;
2611                 }
2612             }
2613         }
2614
2615         /* Move to next or parents next and free the node. */
2616         for (;;) {
2617             next = node->next;
2618             parent = node->parent;
2619             js_free(node);
2620             node = next;
2621             if (node)
2622                 break;
2623             if (!parent)
2624                 goto dump_out;
2625             JS_ASSERT(depth > 1);
2626             --depth;
2627             node = parent;
2628         }
2629     }
2630
2631   dump_out:
2632     JS_ASSERT(depth == 1);
2633     JS_DHashTableFinish(&dtrc.visited);
2634     return dtrc.ok;
2635 }
2636
2637 #endif /* DEBUG */
2638
2639 JS_PUBLIC_API(void)
2640 JS_MarkGCThing(JSContext *cx, jsval v, const char *name, void *arg)
2641 {
2642     JSTracer *trc;
2643
2644     trc = (JSTracer *)arg;
2645     if (!trc)
2646         trc = cx->runtime->gcMarkingTracer;
2647     else
2648         JS_ASSERT(trc == cx->runtime->gcMarkingTracer);
2649
2650 #ifdef JS_THREADSAFE
2651     JS_ASSERT(cx->runtime->gcThread == trc->context->thread);
2652 #endif
2653     MarkValue(trc, Valueify(v), name ? name : "unknown");
2654 }
2655
2656 extern JS_PUBLIC_API(JSBool)
2657 JS_IsGCMarkingTracer(JSTracer *trc)
2658 {
2659     return IS_GC_MARKING_TRACER(trc);
2660 }
2661
2662 JS_PUBLIC_API(void)
2663 JS_GC(JSContext *cx)
2664 {
2665     LeaveTrace(cx);
2666
2667     /* Don't nuke active arenas if executing or compiling. */
2668     if (cx->tempPool.current == &cx->tempPool.first)
2669         JS_FinishArenaPool(&cx->tempPool);
2670     js_GC(cx, NULL, GC_NORMAL);
2671 }
2672
2673 JS_PUBLIC_API(void)
2674 JS_MaybeGC(JSContext *cx)
2675 {
2676     LeaveTrace(cx);
2677
2678     /* Don't nuke active arenas if executing or compiling. */
2679     if (cx->tempPool.current == &cx->tempPool.first)
2680         JS_FinishArenaPool(&cx->tempPool);
2681
2682     MaybeGC(cx);
2683 }
2684
2685 JS_PUBLIC_API(JSGCCallback)
2686 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
2687 {
2688     CHECK_REQUEST(cx);
2689     return JS_SetGCCallbackRT(cx->runtime, cb);
2690 }
2691
2692 JS_PUBLIC_API(JSGCCallback)
2693 JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
2694 {
2695     JSGCCallback oldcb;
2696
2697     oldcb = rt->gcCallback;
2698     rt->gcCallback = cb;
2699     return oldcb;
2700 }
2701
2702 JS_PUBLIC_API(JSBool)
2703 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
2704 {
2705     JS_ASSERT(thing);
2706     JS_ASSERT(!cx->runtime->gcMarkingTracer);
2707     return IsAboutToBeFinalized(cx, thing);
2708 }
2709
2710 JS_PUBLIC_API(void)
2711 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
2712 {
2713     switch (key) {
2714       case JSGC_MAX_BYTES:
2715         rt->gcMaxBytes = value;
2716         break;
2717       case JSGC_MAX_MALLOC_BYTES:
2718         rt->setGCMaxMallocBytes(value);
2719         break;
2720       case JSGC_STACKPOOL_LIFESPAN:
2721         rt->gcEmptyArenaPoolLifespan = value;
2722         break;
2723       case JSGC_MODE:
2724         rt->gcMode = JSGCMode(value);
2725         JS_ASSERT(rt->gcMode == JSGC_MODE_GLOBAL ||
2726                   rt->gcMode == JSGC_MODE_COMPARTMENT);
2727         break;
2728       default:
2729         JS_ASSERT(key == JSGC_TRIGGER_FACTOR);
2730         JS_ASSERT(value >= 100);
2731         rt->setGCTriggerFactor(value);
2732         return;
2733     }
2734 }
2735
2736 JS_PUBLIC_API(uint32)
2737 JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
2738 {
2739     switch (key) {
2740       case JSGC_MAX_BYTES:
2741         return rt->gcMaxBytes;
2742       case JSGC_MAX_MALLOC_BYTES:
2743         return rt->gcMaxMallocBytes;
2744       case JSGC_STACKPOOL_LIFESPAN:
2745         return rt->gcEmptyArenaPoolLifespan;
2746       case JSGC_TRIGGER_FACTOR:
2747         return rt->gcTriggerFactor;
2748       case JSGC_BYTES:
2749         return rt->gcBytes;
2750       case JSGC_MODE:
2751         return uint32(rt->gcMode);
2752       case JSGC_UNUSED_CHUNKS:
2753         return uint32(rt->gcChunksWaitingToExpire);
2754       default:
2755         JS_ASSERT(key == JSGC_NUMBER);
2756         return rt->gcNumber;
2757     }
2758 }
2759
2760 JS_PUBLIC_API(void)
2761 JS_SetGCParameterForThread(JSContext *cx, JSGCParamKey key, uint32 value)
2762 {
2763     JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2764 #ifdef JS_TRACER
2765     SetMaxCodeCacheBytes(cx, value);
2766 #endif
2767 }
2768
2769 JS_PUBLIC_API(uint32)
2770 JS_GetGCParameterForThread(JSContext *cx, JSGCParamKey key)
2771 {
2772     JS_ASSERT(key == JSGC_MAX_CODE_CACHE_BYTES);
2773 #ifdef JS_TRACER
2774     return JS_THREAD_DATA(cx)->maxCodeCacheBytes;
2775 #else
2776     return 0;
2777 #endif
2778 }
2779
2780 JS_PUBLIC_API(void)
2781 JS_FlushCaches(JSContext *cx)
2782 {
2783 #ifdef JS_TRACER
2784     FlushJITCache(cx, &cx->compartment->traceMonitor);
2785 #endif
2786 }
2787
2788 JS_PUBLIC_API(intN)
2789 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
2790 {
2791     return JSExternalString::changeFinalizer(NULL, finalizer);
2792 }
2793
2794 JS_PUBLIC_API(intN)
2795 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
2796 {
2797     return JSExternalString::changeFinalizer(finalizer, NULL);
2798 }
2799
2800 JS_PUBLIC_API(JSString *)
2801 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
2802 {
2803     CHECK_REQUEST(cx);
2804     JS_ASSERT(uintN(type) < JSExternalString::TYPE_LIMIT);
2805
2806     JSExternalString *str = js_NewGCExternalString(cx, uintN(type));
2807     if (!str)
2808         return NULL;
2809     str->initFlat(chars, length);
2810     str->externalStringType = type;
2811     cx->runtime->updateMallocCounter((length + 1) * sizeof(jschar));
2812     return str;
2813 }
2814
2815 JS_PUBLIC_API(intN)
2816 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
2817 {
2818     /*
2819      * No need to test this in js_GetExternalStringGCType, which asserts its
2820      * inverse instead of wasting cycles on testing a condition we can ensure
2821      * by auditing in-VM calls to the js_... helper.
2822      */
2823     if (JSString::isStatic(str))
2824         return -1;
2825
2826     return js_GetExternalStringGCType(str);
2827 }
2828
2829 JS_PUBLIC_API(void)
2830 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
2831 {
2832 #if JS_STACK_GROWTH_DIRECTION > 0
2833     if (limitAddr == 0)
2834         limitAddr = jsuword(-1);
2835 #endif
2836     cx->stackLimit = limitAddr;
2837 }
2838
2839 JS_PUBLIC_API(void)
2840 JS_SetNativeStackQuota(JSContext *cx, size_t stackSize)
2841 {
2842 #ifdef JS_THREADSAFE
2843     JS_ASSERT(cx->thread);
2844 #endif
2845
2846 #if JS_STACK_GROWTH_DIRECTION > 0
2847     if (stackSize == 0) {
2848         cx->stackLimit = jsuword(-1);
2849     } else {
2850         jsuword stackBase = reinterpret_cast<jsuword>(JS_THREAD_DATA(cx)->nativeStackBase);
2851         JS_ASSERT(stackBase <= size_t(-1) - stackSize);
2852         cx->stackLimit = stackBase + stackSize - 1;
2853     }
2854 #else
2855     if (stackSize == 0) {
2856         cx->stackLimit = 0;
2857     } else {
2858         jsuword stackBase = reinterpret_cast<jsuword>(JS_THREAD_DATA(cx)->nativeStackBase);
2859         JS_ASSERT(stackBase >= stackSize);
2860         cx->stackLimit = stackBase - (stackSize - 1);
2861     }
2862 #endif
2863 }
2864
2865 JS_PUBLIC_API(void)
2866 JS_SetScriptStackQuota(JSContext *cx, size_t quota)
2867 {
2868     cx->scriptStackQuota = quota;
2869 }
2870
2871 /************************************************************************/
2872
2873 JS_PUBLIC_API(void)
2874 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
2875 {
2876     cx->free(ida);
2877 }
2878
2879 JS_PUBLIC_API(JSBool)
2880 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
2881 {
2882     CHECK_REQUEST(cx);
2883     assertSameCompartment(cx, v);
2884     return ValueToId(cx, Valueify(v), idp);
2885 }
2886
2887 JS_PUBLIC_API(JSBool)
2888 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
2889 {
2890     CHECK_REQUEST(cx);
2891     *vp = IdToJsval(id);
2892     assertSameCompartment(cx, *vp);
2893     return JS_TRUE;
2894 }
2895
2896 JS_PUBLIC_API(JSBool)
2897 JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
2898 {
2899     return JS_TRUE;
2900 }
2901
2902 JS_PUBLIC_API(JSBool)
2903 JS_StrictPropertyStub(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
2904 {
2905     return JS_TRUE;
2906 }
2907
2908 JS_PUBLIC_API(JSBool)
2909 JS_EnumerateStub(JSContext *cx, JSObject *obj)
2910 {
2911     return JS_TRUE;
2912 }
2913
2914 JS_PUBLIC_API(JSBool)
2915 JS_ResolveStub(JSContext *cx, JSObject *obj, jsid id)
2916 {
2917     return JS_TRUE;
2918 }
2919
2920 JS_PUBLIC_API(JSBool)
2921 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
2922 {
2923     JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION);
2924     return js_TryValueOf(cx, obj, type, Valueify(vp));
2925 }
2926
2927 JS_PUBLIC_API(void)
2928 JS_FinalizeStub(JSContext *cx, JSObject *obj)
2929 {}
2930
2931 JS_PUBLIC_API(JSObject *)
2932 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
2933              JSClass *clasp, JSNative constructor, uintN nargs,
2934              JSPropertySpec *ps, JSFunctionSpec *fs,
2935              JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
2936 {
2937     CHECK_REQUEST(cx);
2938     assertSameCompartment(cx, obj, parent_proto);
2939     return js_InitClass(cx, obj, parent_proto, Valueify(clasp),
2940                         Valueify(constructor), nargs,
2941                         ps, fs, static_ps, static_fs);
2942 }
2943
2944 #ifdef JS_THREADSAFE
2945 JS_PUBLIC_API(JSClass *)
2946 JS_GetClass(JSContext *cx, JSObject *obj)
2947 {
2948     return Jsvalify(obj->getClass());
2949 }
2950 #else
2951 JS_PUBLIC_API(JSClass *)
2952 JS_GetClass(JSObject *obj)
2953 {
2954     return Jsvalify(obj->getClass());
2955 }
2956 #endif
2957
2958 JS_PUBLIC_API(JSBool)
2959 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2960 {
2961     CHECK_REQUEST(cx);
2962     assertSameCompartment(cx, obj);
2963     return InstanceOf(cx, obj, Valueify(clasp), Valueify(argv));
2964 }
2965
2966 JS_PUBLIC_API(JSBool)
2967 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
2968 {
2969     assertSameCompartment(cx, obj, v);
2970     return HasInstance(cx, obj, Valueify(&v), bp);
2971 }
2972
2973 JS_PUBLIC_API(void *)
2974 JS_GetPrivate(JSContext *cx, JSObject *obj)
2975 {
2976     return obj->getPrivate();
2977 }
2978
2979 JS_PUBLIC_API(JSBool)
2980 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2981 {
2982     obj->setPrivate(data);
2983     return true;
2984 }
2985
2986 JS_PUBLIC_API(void *)
2987 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2988 {
2989     if (!InstanceOf(cx, obj, Valueify(clasp), Valueify(argv)))
2990         return NULL;
2991     return obj->getPrivate();
2992 }
2993
2994 JS_PUBLIC_API(JSObject *)
2995 JS_GetPrototype(JSContext *cx, JSObject *obj)
2996 {
2997     JSObject *proto;
2998
2999     CHECK_REQUEST(cx);
3000     assertSameCompartment(cx, obj);
3001     proto = obj->getProto();
3002
3003     /* Beware ref to dead object (we may be called from obj's finalizer). */
3004     return proto && proto->map ? proto : NULL;
3005 }
3006
3007 JS_PUBLIC_API(JSBool)
3008 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
3009 {
3010     CHECK_REQUEST(cx);
3011     assertSameCompartment(cx, obj, proto);
3012     return SetProto(cx, obj, proto, JS_FALSE);
3013 }
3014
3015 JS_PUBLIC_API(JSObject *)
3016 JS_GetParent(JSContext *cx, JSObject *obj)
3017 {
3018     assertSameCompartment(cx, obj);
3019     JSObject *parent = obj->getParent();
3020
3021     /* Beware ref to dead object (we may be called from obj's finalizer). */
3022     return parent && parent->map ? parent : NULL;
3023 }
3024
3025 JS_PUBLIC_API(JSBool)
3026 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
3027 {
3028     CHECK_REQUEST(cx);
3029     JS_ASSERT(parent || !obj->getParent());
3030     assertSameCompartment(cx, obj, parent);
3031     obj->setParent(parent);
3032     return true;
3033 }
3034
3035 JS_PUBLIC_API(JSObject *)
3036 JS_GetConstructor(JSContext *cx, JSObject *proto)
3037 {
3038     Value cval;
3039
3040     CHECK_REQUEST(cx);
3041     assertSameCompartment(cx, proto);
3042     {
3043         JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3044
3045         if (!proto->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), &cval))
3046             return NULL;
3047     }
3048     JSObject *funobj;
3049     if (!IsFunctionObject(cval, &funobj)) {
3050         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
3051                              proto->getClass()->name);
3052         return NULL;
3053     }
3054     return &cval.toObject();
3055 }
3056
3057 JS_PUBLIC_API(JSBool)
3058 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
3059 {
3060     assertSameCompartment(cx, obj);
3061     *idp = OBJECT_TO_JSID(obj);
3062     return JS_TRUE;
3063 }
3064
3065 JS_PUBLIC_API(JSObject *)
3066 JS_NewGlobalObject(JSContext *cx, JSClass *clasp)
3067 {
3068     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
3069     CHECK_REQUEST(cx);
3070     JS_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
3071     JSObject *obj = NewNonFunction<WithProto::Given>(cx, Valueify(clasp), NULL, NULL);
3072     if (!obj)
3073         return NULL;
3074
3075     obj->syncSpecialEquality();
3076
3077     /* Construct a regexp statics object for this global object. */
3078     JSObject *res = regexp_statics_construct(cx, obj);
3079     if (!res ||
3080         !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_REGEXP_STATICS, ObjectValue(*res)) ||
3081         !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_FLAGS, Int32Value(0))) {
3082         return NULL;
3083     }
3084
3085     return obj;
3086 }
3087
3088 JS_PUBLIC_API(JSObject *)
3089 JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals)
3090 {
3091     CHECK_REQUEST(cx);
3092     JSCompartment *compartment = NewCompartment(cx, principals);
3093     if (!compartment)
3094         return NULL;
3095
3096     JSCompartment *saved = cx->compartment;
3097     cx->compartment = compartment;
3098     JSObject *obj = JS_NewGlobalObject(cx, clasp);
3099     cx->compartment = saved;
3100
3101     return obj;
3102 }
3103
3104 JS_PUBLIC_API(JSObject *)
3105 JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
3106 {
3107     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
3108     CHECK_REQUEST(cx);
3109     assertSameCompartment(cx, proto, parent);
3110
3111     Class *clasp = Valueify(jsclasp);
3112     if (!clasp)
3113         clasp = &js_ObjectClass;    /* default class is Object */
3114
3115     JS_ASSERT(clasp != &js_FunctionClass);
3116     JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
3117
3118     JSObject *obj = NewNonFunction<WithProto::Class>(cx, clasp, proto, parent);
3119     if (obj)
3120         obj->syncSpecialEquality();
3121
3122     JS_ASSERT_IF(obj, obj->getParent());
3123     return obj;
3124 }
3125
3126 JS_PUBLIC_API(JSObject *)
3127 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
3128 {
3129     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
3130     CHECK_REQUEST(cx);
3131     assertSameCompartment(cx, proto, parent);
3132
3133     Class *clasp = Valueify(jsclasp);
3134     if (!clasp)
3135         clasp = &js_ObjectClass;    /* default class is Object */
3136
3137     JS_ASSERT(clasp != &js_FunctionClass);
3138     JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
3139
3140     JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
3141     if (obj)
3142         obj->syncSpecialEquality();
3143     return obj;
3144 }
3145
3146 JS_PUBLIC_API(JSObject *)
3147 JS_NewObjectForConstructor(JSContext *cx, const jsval *vp)
3148 {
3149     CHECK_REQUEST(cx);
3150     assertSameCompartment(cx, *vp);
3151
3152     return js_CreateThis(cx, JSVAL_TO_OBJECT(*vp));
3153 }
3154
3155 JS_PUBLIC_API(JSBool)
3156 JS_IsExtensible(JSObject *obj)
3157 {
3158     return obj->isExtensible();
3159 }
3160
3161 JS_PUBLIC_API(JSBool)
3162 JS_FreezeObject(JSContext *cx, JSObject *obj)
3163 {
3164     CHECK_REQUEST(cx);
3165     assertSameCompartment(cx, obj);
3166
3167     return obj->freeze(cx);
3168 }
3169
3170 JS_PUBLIC_API(JSBool)
3171 JS_DeepFreezeObject(JSContext *cx, JSObject *obj)
3172 {
3173     CHECK_REQUEST(cx);
3174     assertSameCompartment(cx, obj);
3175
3176     /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */
3177     if (!obj->isExtensible())
3178         return true;
3179
3180     if (!obj->freeze(cx))
3181         return false;
3182
3183     /* Walk slots in obj and if any value is a non-null object, seal it. */
3184     for (uint32 i = 0, n = obj->slotSpan(); i < n; ++i) {
3185         const Value &v = obj->getSlot(i);
3186         if (v.isPrimitive())
3187             continue;
3188         if (!JS_DeepFreezeObject(cx, &v.toObject()))
3189             return false;
3190     }
3191
3192     return true;
3193 }
3194
3195 JS_PUBLIC_API(JSObject *)
3196 JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
3197 {
3198     CHECK_REQUEST(cx);
3199     assertSameCompartment(cx, proto, parent);
3200     Class *clasp = Valueify(jsclasp);
3201     if (!clasp)
3202         clasp = &js_ObjectClass;    /* default class is Object */
3203     return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
3204 }
3205
3206 JS_PUBLIC_API(JSObject *)
3207 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *proto,
3208                                 JSObject *parent, uintN argc, jsval *argv)
3209 {
3210     CHECK_REQUEST(cx);
3211     assertSameCompartment(cx, proto, parent, JSValueArray(argv, argc));
3212     Class *clasp = Valueify(jsclasp);
3213     if (!clasp)
3214         clasp = &js_ObjectClass;    /* default class is Object */
3215     return js_ConstructObject(cx, clasp, proto, parent, argc, Valueify(argv));
3216 }
3217
3218 static JSBool
3219 LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3220                    JSObject **objp, JSProperty **propp)
3221 {
3222     CHECK_REQUEST(cx);
3223     assertSameCompartment(cx, obj, id);
3224
3225     JSAutoResolveFlags rf(cx, flags);
3226     id = js_CheckForStringIndex(id);
3227     return obj->lookupProperty(cx, id, objp, propp);
3228 }
3229
3230 #define AUTO_NAMELEN(s,n)   (((n) == (size_t)-1) ? js_strlen(s) : (n))
3231
3232 static JSBool
3233 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, jsid id,
3234              JSProperty *prop, Value *vp)
3235 {
3236     if (!prop) {
3237         /* XXX bad API: no way to tell "not defined" from "void value" */
3238         vp->setUndefined();
3239         return JS_TRUE;
3240     }
3241
3242     if (obj2->isNative()) {
3243         Shape *shape = (Shape *) prop;
3244
3245         if (shape->isMethod()) {
3246             AutoShapeRooter root(cx, shape);
3247             vp->setObject(shape->methodObject());
3248             return !!obj2->methodReadBarrier(cx, *shape, vp);
3249         }
3250
3251         /* Peek at the native property's slot value, without doing a Get. */
3252         if (obj2->containsSlot(shape->slot)) {
3253             *vp = obj2->nativeGetSlot(shape->slot);
3254             return true;
3255         }
3256     } else {
3257         if (obj2->isDenseArray())
3258             return js_GetDenseArrayElementValue(cx, obj2, id, vp);
3259         if (obj2->isProxy()) {
3260             AutoPropertyDescriptorRooter desc(cx);
3261             if (!JSProxy::getPropertyDescriptor(cx, obj2, id, false, &desc))
3262                 return false;
3263             if (!(desc.attrs & JSPROP_SHARED)) {
3264                 *vp = desc.value;
3265                 return true;
3266             }
3267         }
3268     }
3269
3270     /* XXX bad API: no way to return "defined but value unknown" */
3271     vp->setBoolean(true);
3272     return true;
3273 }
3274
3275 JS_PUBLIC_API(JSBool)
3276 JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3277 {
3278     JSObject *obj2;
3279     JSProperty *prop;
3280     return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) &&
3281            LookupResult(cx, obj, obj2, id, prop, Valueify(vp));
3282 }
3283
3284 JS_PUBLIC_API(JSBool)
3285 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3286 {
3287     return JS_LookupPropertyById(cx, obj, INT_TO_JSID(index), vp);
3288 }
3289
3290 JS_PUBLIC_API(JSBool)
3291 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3292 {
3293     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3294     return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3295 }
3296
3297 JS_PUBLIC_API(JSBool)
3298 JS_LookupUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3299 {
3300     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3301     return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3302 }
3303
3304 JS_PUBLIC_API(JSBool)
3305 JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3306                                JSObject **objp, jsval *vp)
3307 {
3308     JSBool ok;
3309     JSProperty *prop;
3310
3311     CHECK_REQUEST(cx);
3312     assertSameCompartment(cx, obj, id);
3313     ok = obj->isNative()
3314          ? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0
3315          : obj->lookupProperty(cx, id, objp, &prop);
3316     return ok && LookupResult(cx, obj, *objp, id, prop, Valueify(vp));
3317 }
3318
3319 JS_PUBLIC_API(JSBool)
3320 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, uintN flags, jsval *vp)
3321 {
3322     JSObject *obj2;
3323     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3324     return atom && JS_LookupPropertyWithFlagsById(cx, obj, ATOM_TO_JSID(atom), flags, &obj2, vp);
3325 }
3326
3327 JS_PUBLIC_API(JSBool)
3328 JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3329 {
3330     JSObject *obj2;
3331     JSProperty *prop;
3332     JSBool ok = LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3333                                    &obj2, &prop);
3334     *foundp = (prop != NULL);
3335     return ok;
3336 }
3337
3338 JS_PUBLIC_API(JSBool)
3339 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3340 {
3341     return JS_HasPropertyById(cx, obj, INT_TO_JSID(index), foundp);
3342 }
3343
3344 JS_PUBLIC_API(JSBool)
3345 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3346 {
3347     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3348     return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3349 }
3350
3351 JS_PUBLIC_API(JSBool)
3352 JS_HasUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, JSBool *foundp)
3353 {
3354     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3355     return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3356 }
3357
3358 JS_PUBLIC_API(JSBool)
3359 JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3360 {
3361     CHECK_REQUEST(cx);
3362     assertSameCompartment(cx, obj, id);
3363
3364     if (!obj->isNative()) {
3365         JSObject *obj2;
3366         JSProperty *prop;
3367
3368         if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3369                                 &obj2, &prop)) {
3370             return JS_FALSE;
3371         }
3372         *foundp = (obj == obj2);
3373         return JS_TRUE;
3374     }
3375
3376     *foundp = obj->nativeContains(id);
3377     return JS_TRUE;
3378 }
3379
3380 JS_PUBLIC_API(JSBool)
3381 JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3382 {
3383     return JS_AlreadyHasOwnPropertyById(cx, obj, INT_TO_JSID(index), foundp);
3384 }
3385
3386 JS_PUBLIC_API(JSBool)
3387 JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3388 {
3389     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3390     return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3391 }
3392
3393 JS_PUBLIC_API(JSBool)
3394 JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3395                            JSBool *foundp)
3396 {
3397     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3398     return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
3399 }
3400
3401 static JSBool
3402 DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value,
3403                    PropertyOp getter, StrictPropertyOp setter, uintN attrs,
3404                    uintN flags, intN tinyid)
3405 {
3406     CHECK_REQUEST(cx);
3407     assertSameCompartment(cx, obj, id, value,
3408                             (attrs & JSPROP_GETTER)
3409                             ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
3410                             : NULL,
3411                             (attrs & JSPROP_SETTER)
3412                             ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
3413                             : NULL);
3414
3415     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
3416     if (flags != 0 && obj->isNative()) {
3417         return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter,
3418                                          attrs, flags, tinyid, NULL);
3419     }
3420     return obj->defineProperty(cx, id, value, getter, setter, attrs);
3421 }
3422
3423 JS_PUBLIC_API(JSBool)
3424 JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
3425                       JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
3426 {
3427     return DefinePropertyById(cx, obj, id, Valueify(value), Valueify(getter),
3428                               Valueify(setter), attrs, 0, 0);
3429 }
3430
3431 JS_PUBLIC_API(JSBool)
3432 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
3433                  JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
3434 {
3435     return DefinePropertyById(cx, obj, INT_TO_JSID(index), Valueify(value),
3436                               Valueify(getter), Valueify(setter), attrs, 0, 0);
3437 }
3438
3439 static JSBool
3440 DefineProperty(JSContext *cx, JSObject *obj, const char *name, const Value &value,
3441                PropertyOp getter, StrictPropertyOp setter, uintN attrs,
3442                uintN flags, intN tinyid)
3443 {
3444     jsid id;
3445     JSAtom *atom;
3446
3447     if (attrs & JSPROP_INDEX) {
3448         id = INT_TO_JSID(intptr_t(name));
3449         atom = NULL;
3450         attrs &= ~JSPROP_INDEX;
3451     } else {
3452         atom = js_Atomize(cx, name, strlen(name), 0);
3453         if (!atom)
3454             return JS_FALSE;
3455         id = ATOM_TO_JSID(atom);
3456     }
3457     return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid);
3458 }
3459
3460 JS_PUBLIC_API(JSBool)
3461 JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
3462                   JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
3463 {
3464     return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter),
3465                           Valueify(setter), attrs, 0, 0);
3466 }
3467
3468 JS_PUBLIC_API(JSBool)
3469 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, int8 tinyid,
3470                             jsval value, JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
3471 {
3472     return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter),
3473                           Valueify(setter), attrs, Shape::HAS_SHORTID, tinyid);
3474 }
3475
3476 static JSBool
3477 DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3478                  const Value &value, PropertyOp getter, StrictPropertyOp setter, uintN attrs,
3479                  uintN flags, intN tinyid)
3480 {
3481     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3482     return atom && DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs,
3483                                       flags, tinyid);
3484 }
3485
3486 JS_PUBLIC_API(JSBool)
3487 JS_DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3488                     jsval value, JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
3489 {
3490     return DefineUCProperty(cx, obj, name, namelen, Valueify(value),
3491                             Valueify(getter), Valueify(setter), attrs, 0, 0);
3492 }
3493
3494 JS_PUBLIC_API(JSBool)
3495 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3496                               int8 tinyid, jsval value,
3497                               JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
3498 {
3499     return DefineUCProperty(cx, obj, name, namelen, Valueify(value), Valueify(getter),
3500                             Valueify(setter), attrs, Shape::HAS_SHORTID, tinyid);
3501 }
3502
3503 JS_PUBLIC_API(JSBool)
3504 JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp)
3505 {
3506     CHECK_REQUEST(cx);
3507     assertSameCompartment(cx, obj, id, descriptor);
3508     return js_DefineOwnProperty(cx, obj, id, Valueify(descriptor), bp);
3509 }
3510
3511 JS_PUBLIC_API(JSObject *)
3512 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp,
3513                 JSObject *proto, uintN attrs)
3514 {
3515     CHECK_REQUEST(cx);
3516     assertSameCompartment(cx, obj, proto);
3517
3518     Class *clasp = Valueify(jsclasp);
3519     if (!clasp)
3520         clasp = &js_ObjectClass;    /* default class is Object */
3521
3522     JSObject *nobj = NewObject<WithProto::Class>(cx, clasp, proto, obj);
3523     if (!nobj)
3524         return NULL;
3525
3526     nobj->syncSpecialEquality();
3527
3528     if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
3529         return NULL;
3530
3531     return nobj;
3532 }
3533
3534 JS_PUBLIC_API(JSBool)
3535 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
3536 {
3537     JSBool ok;
3538     uintN attrs;
3539
3540     CHECK_REQUEST(cx);
3541     for (ok = JS_TRUE; cds->name; cds++) {
3542         Value value = DoubleValue(cds->dval);
3543         attrs = cds->flags;
3544         if (!attrs)
3545             attrs = JSPROP_READONLY | JSPROP_PERMANENT;
3546         ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
3547         if (!ok)
3548             break;
3549     }
3550     return ok;
3551 }
3552
3553 JS_PUBLIC_API(JSBool)
3554 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
3555 {
3556     JSBool ok;
3557
3558     for (ok = true; ps->name; ps++) {
3559         ok = DefineProperty(cx, obj, ps->name, UndefinedValue(),
3560                             Valueify(ps->getter), Valueify(ps->setter),
3561                             ps->flags, Shape::HAS_SHORTID, ps->tinyid);
3562         if (!ok)
3563             break;
3564     }
3565     return ok;
3566 }
3567
3568 JS_PUBLIC_API(JSBool)
3569 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *alias)
3570 {
3571     JSObject *obj2;
3572     JSProperty *prop;
3573     JSBool ok;
3574     Shape *shape;
3575
3576     CHECK_REQUEST(cx);
3577     assertSameCompartment(cx, obj);
3578
3579     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3580     if (!atom)
3581         return JS_FALSE;
3582     if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
3583         return JS_FALSE;
3584     if (!prop) {
3585         js_ReportIsNotDefined(cx, name);
3586         return JS_FALSE;
3587     }
3588     if (obj2 != obj || !obj->isNative()) {
3589         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3590                              alias, name, obj2->getClass()->name);
3591         return JS_FALSE;
3592     }
3593     atom = js_Atomize(cx, alias, strlen(alias), 0);
3594     if (!atom) {
3595         ok = JS_FALSE;
3596     } else {
3597         shape = (Shape *)prop;
3598         ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
3599                                    shape->getter(), shape->setter(), shape->slot,
3600                                    shape->attributes(), shape->getFlags() | Shape::ALIAS,
3601                                    shape->shortid)
3602               != NULL);
3603     }
3604     return ok;
3605 }
3606
3607 JS_PUBLIC_API(JSBool)
3608 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
3609 {
3610     JSObject *obj2;
3611     JSProperty *prop;
3612     Shape *shape;
3613
3614     CHECK_REQUEST(cx);
3615     assertSameCompartment(cx, obj);
3616
3617     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3618     if (!atom)
3619         return JS_FALSE;
3620     if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
3621         return JS_FALSE;
3622     if (!prop) {
3623         js_ReportIsNotDefined(cx, name);
3624         return JS_FALSE;
3625     }
3626     if (obj2 != obj || !obj->isNative()) {
3627         char numBuf[12];
3628         JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
3629         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3630                              numBuf, name, obj2->getClass()->name);
3631         return JS_FALSE;
3632     }
3633     shape = (Shape *)prop;
3634     return js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
3635                                 shape->getter(), shape->setter(), shape->slot,
3636                                 shape->attributes(), shape->getFlags() | Shape::ALIAS,
3637                                 shape->shortid)
3638            != NULL;
3639 }
3640
3641 static JSBool
3642 GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3643                           JSBool own, PropertyDescriptor *desc)
3644 {
3645     JSObject *obj2;
3646     JSProperty *prop;
3647
3648     if (!LookupPropertyById(cx, obj, id, flags, &obj2, &prop))
3649         return JS_FALSE;
3650
3651     if (!prop || (own && obj != obj2)) {
3652         desc->obj = NULL;
3653         desc->attrs = 0;
3654         desc->getter = NULL;
3655         desc->setter = NULL;
3656         desc->value.setUndefined();
3657         return JS_TRUE;
3658     }
3659
3660     desc->obj = obj2;
3661     if (obj2->isNative()) {
3662         Shape *shape = (Shape *) prop;
3663         desc->attrs = shape->attributes();
3664
3665         if (shape->isMethod()) {
3666             desc->getter = PropertyStub;
3667             desc->setter = StrictPropertyStub;
3668             desc->value.setObject(shape->methodObject());
3669         } else {
3670             desc->getter = shape->getter();
3671             desc->setter = shape->setter();
3672             if (obj2->containsSlot(shape->slot))
3673                 desc->value = obj2->nativeGetSlot(shape->slot);
3674             else
3675                 desc->value.setUndefined();
3676         }
3677     } else {
3678         if (obj2->isProxy()) {
3679             JSAutoResolveFlags rf(cx, flags);
3680             return own
3681                    ? JSProxy::getOwnPropertyDescriptor(cx, obj2, id, false, desc)
3682                    : JSProxy::getPropertyDescriptor(cx, obj2, id, false, desc);
3683         }
3684         if (!obj2->getAttributes(cx, id, &desc->attrs))
3685             return false;
3686         desc->getter = NULL;
3687         desc->setter = NULL;
3688         desc->value.setUndefined();
3689     }
3690     return true;
3691 }
3692
3693 JS_PUBLIC_API(JSBool)
3694 JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3695                              JSPropertyDescriptor *desc)
3696 {
3697     return GetPropertyDescriptorById(cx, obj, id, flags, JS_FALSE, Valueify(desc));
3698 }
3699
3700 JS_PUBLIC_API(JSBool)
3701 JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *obj, jsid id,
3702                                        uintN *attrsp, JSBool *foundp,
3703                                        JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
3704 {
3705     PropertyDescriptor desc;
3706     if (!GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, JS_FALSE, &desc))
3707         return false;
3708
3709     *attrsp = desc.attrs;
3710     *foundp = (desc.obj != NULL);
3711     if (getterp)
3712         *getterp = Jsvalify(desc.getter);
3713     if (setterp)
3714         *setterp = Jsvalify(desc.setter);
3715     return true;
3716 }
3717
3718 JS_PUBLIC_API(JSBool)
3719 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3720                          uintN *attrsp, JSBool *foundp)
3721 {
3722     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3723     return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3724                                                           attrsp, foundp, NULL, NULL);
3725 }
3726
3727 JS_PUBLIC_API(JSBool)
3728 JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3729                            uintN *attrsp, JSBool *foundp)
3730 {
3731     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3732     return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3733                                                           attrsp, foundp, NULL, NULL);
3734 }
3735
3736 JS_PUBLIC_API(JSBool)
3737 JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, const char *name,
3738                                    uintN *attrsp, JSBool *foundp,
3739                                    JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
3740 {
3741     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3742     return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3743                                                           attrsp, foundp, getterp, setterp);
3744 }
3745
3746 JS_PUBLIC_API(JSBool)
3747 JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
3748                                      const jschar *name, size_t namelen,
3749                                      uintN *attrsp, JSBool *foundp,
3750                                      JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
3751 {
3752     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3753     return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
3754                                                           attrsp, foundp, getterp, setterp);
3755 }
3756
3757 JS_PUBLIC_API(JSBool)
3758 JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3759 {
3760     CHECK_REQUEST(cx);
3761     return js_GetOwnPropertyDescriptor(cx, obj, id, Valueify(vp));
3762 }
3763
3764 static JSBool
3765 SetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, uintN attrs, JSBool *foundp)
3766 {
3767     JSObject *obj2;
3768     JSProperty *prop;
3769
3770     if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
3771         return false;
3772     if (!prop || obj != obj2) {
3773         *foundp = false;
3774         return true;
3775     }
3776     JSBool ok = obj->isNative()
3777                 ? js_SetNativeAttributes(cx, obj, (Shape *) prop, attrs)
3778                 : obj->setAttributes(cx, id, &attrs);
3779     if (ok)
3780         *foundp = true;
3781     return ok;
3782 }
3783
3784 JS_PUBLIC_API(JSBool)
3785 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3786                          uintN attrs, JSBool *foundp)
3787 {
3788     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3789     return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
3790 }
3791
3792 JS_PUBLIC_API(JSBool)
3793 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
3794                            uintN attrs, JSBool *foundp)
3795 {
3796     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3797     return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
3798 }
3799
3800 JS_PUBLIC_API(JSBool)
3801 JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3802 {
3803     CHECK_REQUEST(cx);
3804     assertSameCompartment(cx, obj, id);
3805     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3806     return obj->getProperty(cx, id, Valueify(vp));
3807 }
3808
3809 JS_PUBLIC_API(JSBool)
3810 JS_GetPropertyByIdDefault(JSContext *cx, JSObject *obj, jsid id, jsval def, jsval *vp)
3811 {
3812     return GetPropertyDefault(cx, obj, id, Valueify(def), Valueify(vp));
3813 }
3814
3815 JS_PUBLIC_API(JSBool)
3816 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3817 {
3818     return JS_GetPropertyById(cx, obj, INT_TO_JSID(index), vp);
3819 }
3820
3821 JS_PUBLIC_API(JSBool)
3822 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3823 {
3824     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3825     return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3826 }
3827
3828 JS_PUBLIC_API(JSBool)
3829 JS_GetPropertyDefault(JSContext *cx, JSObject *obj, const char *name, jsval def, jsval *vp)
3830 {
3831     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3832     return atom && JS_GetPropertyByIdDefault(cx, obj, ATOM_TO_JSID(atom), def, vp);
3833 }
3834
3835 JS_PUBLIC_API(JSBool)
3836 JS_GetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3837 {
3838     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3839     return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3840 }
3841
3842 JS_PUBLIC_API(JSBool)
3843 JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval *vp)
3844 {
3845     CHECK_REQUEST(cx);
3846     assertSameCompartment(cx, obj, id);
3847     if (!js_GetMethod(cx, obj, id, JSGET_METHOD_BARRIER, Valueify(vp)))
3848         return JS_FALSE;
3849     if (objp)
3850         *objp = obj;
3851     return JS_TRUE;
3852 }
3853
3854 JS_PUBLIC_API(JSBool)
3855 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, jsval *vp)
3856 {
3857     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3858     return atom && JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), objp, vp);
3859 }
3860
3861 JS_PUBLIC_API(JSBool)
3862 JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3863 {
3864     CHECK_REQUEST(cx);
3865     assertSameCompartment(cx, obj, id);
3866     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
3867     return obj->setProperty(cx, id, Valueify(vp), false);
3868 }
3869
3870 JS_PUBLIC_API(JSBool)
3871 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3872 {
3873     return JS_SetPropertyById(cx, obj, INT_TO_JSID(index), vp);
3874 }
3875
3876 JS_PUBLIC_API(JSBool)
3877 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3878 {
3879     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3880     return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3881 }
3882
3883 JS_PUBLIC_API(JSBool)
3884 JS_SetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
3885 {
3886     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3887     return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
3888 }
3889
3890 JS_PUBLIC_API(JSBool)
3891 JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
3892 {
3893     CHECK_REQUEST(cx);
3894     assertSameCompartment(cx, obj, id);
3895     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3896     return obj->deleteProperty(cx, id, Valueify(rval), false);
3897 }
3898
3899 JS_PUBLIC_API(JSBool)
3900 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
3901 {
3902     return JS_DeletePropertyById2(cx, obj, INT_TO_JSID(index), rval);
3903 }
3904
3905 JS_PUBLIC_API(JSBool)
3906 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name, jsval *rval)
3907 {
3908     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
3909     return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
3910 }
3911
3912 JS_PUBLIC_API(JSBool)
3913 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *rval)
3914 {
3915     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3916     return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
3917 }
3918
3919 JS_PUBLIC_API(JSBool)
3920 JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id)
3921 {
3922     jsval junk;
3923     return JS_DeletePropertyById2(cx, obj, id, &junk);
3924 }
3925
3926 JS_PUBLIC_API(JSBool)
3927 JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
3928 {
3929     jsval junk;
3930     return JS_DeleteElement2(cx, obj, index, &junk);
3931 }
3932
3933 JS_PUBLIC_API(JSBool)
3934 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
3935 {
3936     jsval junk;
3937     return JS_DeleteProperty2(cx, obj, name, &junk);
3938 }
3939
3940 JS_PUBLIC_API(void)
3941 JS_ClearScope(JSContext *cx, JSObject *obj)
3942 {
3943     CHECK_REQUEST(cx);
3944     assertSameCompartment(cx, obj);
3945
3946     JSFinalizeOp clearOp = obj->getOps()->clear;
3947     if (clearOp)
3948         clearOp(cx, obj);
3949
3950     if (obj->isNative())
3951         js_ClearNative(cx, obj);
3952
3953     /* Clear cached class objects on the global object. */
3954     if (obj->isGlobal()) {
3955         /* This can return false but that doesn't mean it failed. */
3956         obj->unbrand(cx);
3957
3958         for (int key = JSProto_Null; key < JSProto_LIMIT * 3; key++)
3959             JS_SetReservedSlot(cx, obj, key, JSVAL_VOID);
3960
3961         /* Clear regexp statics. */
3962         RegExpStatics::extractFrom(obj)->clear();
3963
3964         /* Clear the CSP eval-is-allowed cache. */
3965         JS_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_EVAL_ALLOWED, JSVAL_VOID);
3966
3967         /*
3968          * Mark global as cleared. If we try to execute any compile-and-go
3969          * scripts from here on, we will throw.
3970          */
3971         int32 flags = obj->getReservedSlot(JSRESERVED_GLOBAL_FLAGS).toInt32();
3972         flags |= JSGLOBAL_FLAGS_CLEARED;
3973         JS_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_FLAGS, Jsvalify(Int32Value(flags)));
3974     }
3975
3976     js_InitRandom(cx);
3977 }
3978
3979 JS_PUBLIC_API(JSIdArray *)
3980 JS_Enumerate(JSContext *cx, JSObject *obj)
3981 {
3982     CHECK_REQUEST(cx);
3983     assertSameCompartment(cx, obj);
3984
3985     AutoIdVector props(cx);
3986     JSIdArray *ida;
3987     if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida))
3988         return false;
3989     for (size_t n = 0; n < size_t(ida->length); ++n)
3990         JS_ASSERT(js_CheckForStringIndex(ida->vector[n]) == ida->vector[n]);
3991     return ida;
3992 }
3993
3994 /*
3995  * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
3996  *     prop_iterator_class somehow...
3997  * + preserve the obj->enumerate API while optimizing the native object case
3998  * + native case here uses a Shape *, but that iterates in reverse!
3999  * + so we make non-native match, by reverse-iterating after JS_Enumerating
4000  */
4001 const uint32 JSSLOT_ITER_INDEX = 0;
4002
4003 static void
4004 prop_iter_finalize(JSContext *cx, JSObject *obj)
4005 {
4006     void *pdata = obj->getPrivate();
4007     if (!pdata)
4008         return;
4009
4010     if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) {
4011         /* Non-native case: destroy the ida enumerated when obj was created. */
4012         JSIdArray *ida = (JSIdArray *) pdata;
4013         JS_DestroyIdArray(cx, ida);
4014     }
4015 }
4016
4017 static void
4018 prop_iter_trace(JSTracer *trc, JSObject *obj)
4019 {
4020     void *pdata = obj->getPrivate();
4021     if (!pdata)
4022         return;
4023
4024     if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
4025         /* Native case: just mark the next property to visit. */
4026         ((Shape *) pdata)->trace(trc);
4027     } else {
4028         /* Non-native case: mark each id in the JSIdArray private. */
4029         JSIdArray *ida = (JSIdArray *) pdata;
4030         MarkIdRange(trc, ida->length, ida->vector, "prop iter");
4031     }
4032 }
4033
4034 static Class prop_iter_class = {
4035     "PropertyIterator",
4036     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
4037     JSCLASS_MARK_IS_TRACE,
4038     PropertyStub,         /* addProperty */
4039     PropertyStub,         /* delProperty */
4040     PropertyStub,         /* getProperty */
4041     StrictPropertyStub,   /* setProperty */
4042     EnumerateStub,
4043     ResolveStub,
4044     ConvertStub,
4045     prop_iter_finalize,
4046     NULL,           /* reserved0   */
4047     NULL,           /* checkAccess */
4048     NULL,           /* call        */
4049     NULL,           /* construct   */
4050     NULL,           /* xdrObject   */
4051     NULL,           /* hasInstance */
4052     JS_CLASS_TRACE(prop_iter_trace)
4053 };
4054
4055 JS_PUBLIC_API(JSObject *)
4056 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
4057 {
4058     JSObject *iterobj;
4059     const void *pdata;
4060     jsint index;
4061     JSIdArray *ida;
4062
4063     CHECK_REQUEST(cx);
4064     assertSameCompartment(cx, obj);
4065     iterobj = NewNonFunction<WithProto::Class>(cx, &prop_iter_class, NULL, obj);
4066     if (!iterobj)
4067         return NULL;
4068
4069     if (obj->isNative()) {
4070         /* Native case: start with the last property in obj. */
4071         pdata = obj->lastProperty();
4072         index = -1;
4073     } else {
4074         /*
4075          * Non-native case: enumerate a JSIdArray and keep it via private.
4076          *
4077          * Note: we have to make sure that we root obj around the call to
4078          * JS_Enumerate to protect against multiple allocations under it.
4079          */
4080         AutoObjectRooter tvr(cx, iterobj);
4081         ida = JS_Enumerate(cx, obj);
4082         if (!ida)
4083             return NULL;
4084         pdata = ida;
4085         index = ida->length;
4086     }
4087
4088     /* iterobj cannot escape to other threads here. */
4089     iterobj->setPrivate(const_cast<void *>(pdata));
4090     iterobj->getSlotRef(JSSLOT_ITER_INDEX).setInt32(index);
4091     return iterobj;
4092 }
4093
4094 JS_PUBLIC_API(JSBool)
4095 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
4096 {
4097     jsint i;
4098     const Shape *shape;
4099     JSIdArray *ida;
4100
4101     CHECK_REQUEST(cx);
4102     assertSameCompartment(cx, iterobj);
4103     i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
4104     if (i < 0) {
4105         /* Native case: private data is a property tree node pointer. */
4106         JS_ASSERT(iterobj->getParent()->isNative());
4107         shape = (Shape *) iterobj->getPrivate();
4108
4109         while (shape->previous() && (!shape->enumerable() || shape->isAlias()))
4110             shape = shape->previous();
4111
4112         if (!shape->previous()) {
4113             JS_ASSERT(JSID_IS_EMPTY(shape->id));
4114             *idp = JSID_VOID;
4115         } else {
4116             iterobj->setPrivate(const_cast<Shape *>(shape->previous()));
4117             *idp = shape->id;
4118         }
4119     } else {
4120         /* Non-native case: use the ida enumerated when iterobj was created. */
4121         ida = (JSIdArray *) iterobj->getPrivate();
4122         JS_ASSERT(i <= ida->length);
4123         STATIC_ASSUME(i <= ida->length);
4124         if (i == 0) {
4125             *idp = JSID_VOID;
4126         } else {
4127             *idp = ida->vector[--i];
4128             iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i));
4129         }
4130     }
4131     return JS_TRUE;
4132 }
4133
4134 JS_PUBLIC_API(JSBool)
4135 JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
4136 {
4137     CHECK_REQUEST(cx);
4138     assertSameCompartment(cx, obj);
4139     return js_GetReservedSlot(cx, obj, index, Valueify(vp));
4140 }
4141
4142 JS_PUBLIC_API(JSBool)
4143 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
4144 {
4145     CHECK_REQUEST(cx);
4146     assertSameCompartment(cx, obj, v);
4147     return js_SetReservedSlot(cx, obj, index, Valueify(v));
4148 }
4149
4150 JS_PUBLIC_API(JSObject *)
4151 JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
4152 {
4153     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4154     CHECK_REQUEST(cx);
4155     /* NB: jsuint cast does ToUint32. */
4156     assertSameCompartment(cx, JSValueArray(vector, vector ? (jsuint)length : 0));
4157     return NewDenseCopiedArray(cx, (jsuint)length, Valueify(vector));
4158 }
4159
4160 JS_PUBLIC_API(JSBool)
4161 JS_IsArrayObject(JSContext *cx, JSObject *obj)
4162 {
4163     assertSameCompartment(cx, obj);
4164     return obj->isArray() ||
4165            (obj->isWrapper() && JSWrapper::wrappedObject(obj)->isArray());
4166 }
4167
4168 JS_PUBLIC_API(JSBool)
4169 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
4170 {
4171     CHECK_REQUEST(cx);
4172     assertSameCompartment(cx, obj);
4173     return js_GetLengthProperty(cx, obj, lengthp);
4174 }
4175
4176 JS_PUBLIC_API(JSBool)
4177 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
4178 {
4179     CHECK_REQUEST(cx);
4180     assertSameCompartment(cx, obj);
4181     return js_SetLengthProperty(cx, obj, length);
4182 }
4183
4184 JS_PUBLIC_API(JSBool)
4185 JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
4186 {
4187     CHECK_REQUEST(cx);
4188     assertSameCompartment(cx, obj);
4189     return js_HasLengthProperty(cx, obj, lengthp);
4190 }
4191
4192 JS_PUBLIC_API(JSBool)
4193 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
4194                jsval *vp, uintN *attrsp)
4195 {
4196     CHECK_REQUEST(cx);
4197     assertSameCompartment(cx, obj, id);
4198     return CheckAccess(cx, obj, id, mode, Valueify(vp), attrsp);
4199 }
4200
4201 #ifdef JS_THREADSAFE
4202 JS_PUBLIC_API(jsrefcount)
4203 JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
4204 {
4205     return JS_ATOMIC_INCREMENT(&principals->refcount);
4206 }
4207
4208 JS_PUBLIC_API(jsrefcount)
4209 JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
4210 {
4211     jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
4212     if (rc == 0)
4213         principals->destroy(cx, principals);
4214     return rc;
4215 }
4216 #endif
4217
4218 JS_PUBLIC_API(JSSecurityCallbacks *)
4219 JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks)
4220 {
4221     JSSecurityCallbacks *oldcallbacks;
4222
4223     oldcallbacks = rt->securityCallbacks;
4224     rt->securityCallbacks = callbacks;
4225     return oldcallbacks;
4226 }
4227
4228 JS_PUBLIC_API(JSSecurityCallbacks *)
4229 JS_GetRuntimeSecurityCallbacks(JSRuntime *rt)
4230 {
4231   return rt->securityCallbacks;
4232 }
4233
4234 JS_PUBLIC_API(JSSecurityCallbacks *)
4235 JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks)
4236 {
4237     JSSecurityCallbacks *oldcallbacks;
4238
4239     oldcallbacks = cx->securityCallbacks;
4240     cx->securityCallbacks = callbacks;
4241     return oldcallbacks;
4242 }
4243
4244 JS_PUBLIC_API(JSSecurityCallbacks *)
4245 JS_GetSecurityCallbacks(JSContext *cx)
4246 {
4247   return cx->securityCallbacks
4248          ? cx->securityCallbacks
4249          : cx->runtime->securityCallbacks;
4250 }
4251
4252 JS_PUBLIC_API(JSFunction *)
4253 JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
4254                JSObject *parent, const char *name)
4255 {
4256     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4257     JSAtom *atom;
4258
4259     CHECK_REQUEST(cx);
4260     assertSameCompartment(cx, parent);
4261
4262     if (!name) {
4263         atom = NULL;
4264     } else {
4265         atom = js_Atomize(cx, name, strlen(name), 0);
4266         if (!atom)
4267             return NULL;
4268     }
4269     return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, atom);
4270 }
4271
4272 JS_PUBLIC_API(JSFunction *)
4273 JS_NewFunctionById(JSContext *cx, JSNative native, uintN nargs, uintN flags, JSObject *parent,
4274                    jsid id)
4275 {
4276     JS_ASSERT(JSID_IS_STRING(id));
4277     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4278     CHECK_REQUEST(cx);
4279     assertSameCompartment(cx, parent);
4280
4281     return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, JSID_TO_ATOM(id));
4282 }
4283
4284 JS_PUBLIC_API(JSObject *)
4285 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
4286 {
4287     CHECK_REQUEST(cx);
4288     assertSameCompartment(cx, parent);  // XXX no funobj for now
4289     if (!parent) {
4290         if (cx->hasfp())
4291             parent = GetScopeChain(cx, cx->fp());
4292         if (!parent)
4293             parent = cx->globalObject;
4294         JS_ASSERT(parent);
4295     }
4296
4297     if (funobj->getClass() != &js_FunctionClass) {
4298         /*
4299          * We cannot clone this object, so fail (we used to return funobj, bad
4300          * idea, but we changed incompatibly to teach any abusers a lesson!).
4301          */
4302         Value v = ObjectValue(*funobj);
4303         js_ReportIsNotFunction(cx, &v, 0);
4304         return NULL;
4305     }
4306
4307     JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
4308     if (!FUN_FLAT_CLOSURE(fun))
4309         return CloneFunctionObject(cx, fun, parent);
4310
4311     /*
4312      * A flat closure carries its own environment, so why clone it? In case
4313      * someone wants to mutate its fixed slots or add ad-hoc properties. API
4314      * compatibility suggests we not return funobj and let callers mutate the
4315      * returned object at will.
4316      *
4317      * But it's worse than that: API compatibility according to the test for
4318      * bug 300079 requires we get "upvars" from parent and its ancestors! So
4319      * we do that (grudgingly!). The scope chain ancestors are searched as if
4320      * they were activations, respecting the skip field in each upvar's cookie
4321      * but looking up the property by name instead of frame slot.
4322      */
4323     JSObject *clone = js_AllocFlatClosure(cx, fun, parent);
4324     if (!clone)
4325         return NULL;
4326
4327     JSUpvarArray *uva = fun->u.i.script->upvars();
4328     uint32 i = uva->length;
4329     JS_ASSERT(i != 0);
4330
4331     for (Shape::Range r(fun->script()->bindings.lastUpvar()); i-- != 0; r.popFront()) {
4332         JSObject *obj = parent;
4333         int skip = uva->vector[i].level();
4334         while (--skip > 0) {
4335             if (!obj) {
4336                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4337                                      JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
4338                 return NULL;
4339             }
4340             obj = obj->getParent();
4341         }
4342
4343         if (!obj->getProperty(cx, r.front().id, clone->getFlatClosureUpvars() + i))
4344             return NULL;
4345     }
4346
4347     return clone;
4348 }
4349
4350 JS_PUBLIC_API(JSObject *)
4351 JS_GetFunctionObject(JSFunction *fun)
4352 {
4353     return FUN_OBJECT(fun);
4354 }
4355
4356 JS_PUBLIC_API(JSString *)
4357 JS_GetFunctionId(JSFunction *fun)
4358 {
4359     return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
4360 }
4361
4362 JS_PUBLIC_API(uintN)
4363 JS_GetFunctionFlags(JSFunction *fun)
4364 {
4365     return fun->flags;
4366 }
4367
4368 JS_PUBLIC_API(uint16)
4369 JS_GetFunctionArity(JSFunction *fun)
4370 {
4371     return fun->nargs;
4372 }
4373
4374 JS_PUBLIC_API(JSBool)
4375 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
4376 {
4377     return obj->getClass() == &js_FunctionClass;
4378 }
4379
4380 JS_PUBLIC_API(JSBool)
4381 JS_ObjectIsCallable(JSContext *cx, JSObject *obj)
4382 {
4383     return obj->isCallable();
4384 }
4385
4386 static JSBool
4387 js_generic_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp)
4388 {
4389     JSFunctionSpec *fs = (JSFunctionSpec *) vp->toObject().getReservedSlot(0).toPrivate();
4390     JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
4391
4392     if (argc < 1) {
4393         js_ReportMissingArg(cx, *vp, 0);
4394         return JS_FALSE;
4395     }
4396
4397     /*
4398      * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
4399      * which is almost always the class constructor object, e.g. Array.  Then
4400      * call the corresponding prototype native method with our first argument
4401      * passed as |this|.
4402      */
4403     memmove(vp + 1, vp + 2, argc * sizeof(jsval));
4404
4405     /* Clear the last parameter in case too few arguments were passed. */
4406     vp[2 + --argc].setUndefined();
4407
4408     Native native =
4409 #ifdef JS_TRACER
4410                     (fs->flags & JSFUN_TRCINFO)
4411                     ? JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native
4412                     :
4413 #endif
4414                       Valueify(fs->call);
4415     return native(cx, argc, vp);
4416 }
4417
4418 JS_PUBLIC_API(JSBool)
4419 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
4420 {
4421     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4422     uintN flags;
4423     JSObject *ctor;
4424     JSFunction *fun;
4425
4426     CHECK_REQUEST(cx);
4427     assertSameCompartment(cx, obj);
4428     ctor = NULL;
4429     for (; fs->name; fs++) {
4430         flags = fs->flags;
4431
4432         /*
4433          * Define a generic arity N+1 static method for the arity N prototype
4434          * method if flags contains JSFUN_GENERIC_NATIVE.
4435          */
4436         if (flags & JSFUN_GENERIC_NATIVE) {
4437             if (!ctor) {
4438                 ctor = JS_GetConstructor(cx, obj);
4439                 if (!ctor)
4440                     return JS_FALSE;
4441             }
4442
4443             flags &= ~JSFUN_GENERIC_NATIVE;
4444             fun = JS_DefineFunction(cx, ctor, fs->name,
4445                                     Jsvalify(js_generic_native_method_dispatcher),
4446                                     fs->nargs + 1,
4447                                     flags & ~JSFUN_TRCINFO);
4448             if (!fun)
4449                 return JS_FALSE;
4450
4451             /*
4452              * As jsapi.h notes, fs must point to storage that lives as long
4453              * as fun->object lives.
4454              */
4455             Value priv = PrivateValue(fs);
4456             if (!js_SetReservedSlot(cx, FUN_OBJECT(fun), 0, priv))
4457                 return JS_FALSE;
4458         }
4459
4460         fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
4461         if (!fun)
4462             return JS_FALSE;
4463     }
4464     return JS_TRUE;
4465 }
4466
4467 JS_PUBLIC_API(JSFunction *)
4468 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
4469                   uintN nargs, uintN attrs)
4470 {
4471     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4472     CHECK_REQUEST(cx);
4473     assertSameCompartment(cx, obj);
4474     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
4475     if (!atom)
4476         return NULL;
4477     return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs);
4478 }
4479
4480 JS_PUBLIC_API(JSFunction *)
4481 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
4482                     const jschar *name, size_t namelen, JSNative call,
4483                     uintN nargs, uintN attrs)
4484 {
4485     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4486     CHECK_REQUEST(cx);
4487     assertSameCompartment(cx, obj);
4488     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
4489     if (!atom)
4490         return NULL;
4491     return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs);
4492 }
4493
4494 extern JS_PUBLIC_API(JSFunction *)
4495 JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call,
4496                     uintN nargs, uintN attrs)
4497 {
4498     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4499     CHECK_REQUEST(cx);
4500     assertSameCompartment(cx, obj);
4501     return js_DefineFunction(cx, obj, id, Valueify(call), nargs, attrs);
4502 }
4503
4504 inline static void
4505 LAST_FRAME_EXCEPTION_CHECK(JSContext *cx, bool result)
4506 {
4507     if (!result && !cx->hasRunOption(JSOPTION_DONT_REPORT_UNCAUGHT))
4508         js_ReportUncaughtException(cx);
4509 }
4510
4511 inline static void
4512 LAST_FRAME_CHECKS(JSContext *cx, bool result)
4513 {
4514     if (!JS_IsRunning(cx)) {
4515         LAST_FRAME_EXCEPTION_CHECK(cx, result);
4516     }
4517 }
4518
4519 inline static uint32
4520 JS_OPTIONS_TO_TCFLAGS(JSContext *cx)
4521 {
4522     return (cx->hasRunOption(JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) |
4523            (cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0);
4524 }
4525
4526 static JSObject *
4527 CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4528                                       const jschar *chars, size_t length,
4529                                       const char *filename, uintN lineno, JSVersion version)
4530 {
4531     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4532     CHECK_REQUEST(cx);
4533     assertSameCompartment(cx, obj, principals);
4534
4535     uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4536     JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
4537                                                chars, length, filename, lineno, version);
4538     JSObject *scriptObj = NULL;
4539     if (script) {
4540         scriptObj = js_NewScriptObject(cx, script);
4541         if (!scriptObj)
4542             js_DestroyScript(cx, script);
4543     }
4544     LAST_FRAME_CHECKS(cx, scriptObj);
4545     return scriptObj;
4546 }
4547
4548 extern JS_PUBLIC_API(JSObject *)
4549 JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4550                                        JSPrincipals *principals,
4551                                        const jschar *chars, size_t length,
4552                                        const char *filename, uintN lineno,
4553                                        JSVersion version)
4554 {
4555     AutoVersionAPI avi(cx, version);
4556     return CompileUCScriptForPrincipalsCommon(cx, obj, principals, chars, length, filename, lineno,
4557                                               avi.version());
4558 }
4559
4560 JS_PUBLIC_API(JSObject *)
4561 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4562                                 const jschar *chars, size_t length,
4563                                 const char *filename, uintN lineno)
4564 {
4565     return CompileUCScriptForPrincipalsCommon(cx, obj, principals, chars, length, filename, lineno,
4566                                               cx->findVersion());
4567 }
4568
4569 JS_PUBLIC_API(JSObject *)
4570 JS_CompileUCScript(JSContext *cx, JSObject *obj, const jschar *chars, size_t length,
4571                    const char *filename, uintN lineno)
4572 {
4573     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4574     return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno);
4575 }
4576
4577 JS_PUBLIC_API(JSObject *)
4578 JS_CompileScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
4579                                      JSPrincipals *principals,
4580                                      const char *bytes, size_t length,
4581                                      const char *filename, uintN lineno,
4582                                      JSVersion version)
4583 {
4584     AutoVersionAPI ava(cx, version);
4585     return JS_CompileScriptForPrincipals(cx, obj, principals, bytes, length, filename, lineno);
4586 }
4587
4588 JS_PUBLIC_API(JSObject *)
4589 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
4590                               JSPrincipals *principals,
4591                               const char *bytes, size_t length,
4592                               const char *filename, uintN lineno)
4593 {
4594     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4595     CHECK_REQUEST(cx);
4596
4597     jschar *chars = js_InflateString(cx, bytes, &length);
4598     if (!chars)
4599         return NULL;
4600     JSObject *scriptObj =
4601         JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length, filename, lineno);
4602     cx->free(chars);
4603     return scriptObj;
4604 }
4605
4606 JS_PUBLIC_API(JSObject *)
4607 JS_CompileScript(JSContext *cx, JSObject *obj, const char *bytes, size_t length,
4608                  const char *filename, uintN lineno)
4609 {
4610     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4611     return JS_CompileScriptForPrincipals(cx, obj, NULL, bytes, length, filename, lineno);
4612 }
4613
4614 JS_PUBLIC_API(JSBool)
4615 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, const char *bytes, size_t length)
4616 {
4617     jschar *chars;
4618     JSBool result;
4619     JSExceptionState *exnState;
4620     JSErrorReporter older;
4621
4622     CHECK_REQUEST(cx);
4623     assertSameCompartment(cx, obj);
4624     chars = js_InflateString(cx, bytes, &length);
4625     if (!chars)
4626         return JS_TRUE;
4627
4628     /*
4629      * Return true on any out-of-memory error, so our caller doesn't try to
4630      * collect more buffered source.
4631      */
4632     result = JS_TRUE;
4633     exnState = JS_SaveExceptionState(cx);
4634     {
4635         Parser parser(cx);
4636         if (parser.init(chars, length, NULL, 1, cx->findVersion())) {
4637             older = JS_SetErrorReporter(cx, NULL);
4638             if (!parser.parse(obj) &&
4639                 parser.tokenStream.isUnexpectedEOF()) {
4640                 /*
4641                  * We ran into an error. If it was because we ran out of
4642                  * source, we return false so our caller knows to try to
4643                  * collect more buffered source.
4644                  */
4645                 result = JS_FALSE;
4646             }
4647             JS_SetErrorReporter(cx, older);
4648         }
4649     }
4650     cx->free(chars);
4651     JS_RestoreExceptionState(cx, exnState);
4652     return result;
4653 }
4654
4655 /* Use the fastest available getc. */
4656 #if defined(HAVE_GETC_UNLOCKED)
4657 # define fast_getc getc_unlocked
4658 #elif defined(HAVE__GETC_NOLOCK)
4659 # define fast_getc _getc_nolock
4660 #else
4661 # define fast_getc getc
4662 #endif
4663
4664 static JSObject *
4665 CompileFileHelper(JSContext *cx, JSObject *obj, JSPrincipals *principals,
4666                   const char* filename, FILE *fp)
4667 {
4668     struct stat st;
4669     int ok = fstat(fileno(fp), &st);
4670     if (ok != 0)
4671         return NULL;
4672
4673     jschar *buf = NULL;
4674     size_t len = st.st_size;
4675     size_t i = 0;
4676     JSScript *script;
4677
4678     /* Read in the whole file, then compile it. */
4679     if (fp == stdin) {
4680         JS_ASSERT(len == 0);
4681         len = 8;  /* start with a small buffer, expand as necessary */
4682         int c;
4683         bool hitEOF = false;
4684         while (!hitEOF) {
4685             len *= 2;
4686             jschar* tmpbuf = (jschar *) js_realloc(buf, len * sizeof(jschar));
4687             if (!tmpbuf) {
4688                 cx->free(buf);
4689                 return NULL;
4690             }
4691             buf = tmpbuf;
4692
4693             while (i < len) {
4694                 c = fast_getc(fp);
4695                 if (c == EOF) {
4696                     hitEOF = true;
4697                     break;
4698                 }
4699                 buf[i++] = (jschar) (unsigned char) c;
4700             }
4701         }
4702     } else {
4703         buf = (jschar *) js_malloc(len * sizeof(jschar));
4704         if (!buf)
4705             return NULL;
4706
4707         int c;
4708         while ((c = fast_getc(fp)) != EOF)
4709             buf[i++] = (jschar) (unsigned char) c;
4710     }
4711
4712     JS_ASSERT(i <= len);
4713     len = i;
4714     uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
4715     script = Compiler::compileScript(cx, obj, NULL, principals, tcflags, buf, len, filename, 1,
4716                                      cx->findVersion());
4717     js_free(buf);
4718     if (!script)
4719         return NULL;
4720
4721     JSObject *scriptObj = js_NewScriptObject(cx, script);
4722     if (!scriptObj)
4723         js_DestroyScript(cx, script);
4724     
4725     return scriptObj;
4726 }
4727
4728 JS_PUBLIC_API(JSObject *)
4729 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
4730 {
4731     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4732
4733     CHECK_REQUEST(cx);
4734     assertSameCompartment(cx, obj);
4735     JSObject *scriptObj = NULL;
4736     do {
4737         FILE *fp;
4738         if (!filename || strcmp(filename, "-") == 0) {
4739             fp = stdin;
4740         } else {
4741             fp = fopen(filename, "r");
4742             if (!fp) {
4743                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
4744                                      filename, "No such file or directory");
4745                 break;
4746             }
4747         }
4748
4749         scriptObj = CompileFileHelper(cx, obj, NULL, filename, fp);
4750         if (fp != stdin)
4751             fclose(fp);
4752     } while (false);
4753     
4754     LAST_FRAME_CHECKS(cx, scriptObj);
4755     return scriptObj;
4756 }
4757
4758 JS_PUBLIC_API(JSObject *)
4759 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *filename,
4760                                   FILE *file, JSPrincipals *principals)
4761 {
4762     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4763
4764     CHECK_REQUEST(cx);
4765     assertSameCompartment(cx, obj, principals);
4766     JSObject *scriptObj = CompileFileHelper(cx, obj, principals, filename, file);
4767     LAST_FRAME_CHECKS(cx, scriptObj);
4768     return scriptObj;
4769 }
4770
4771 JS_PUBLIC_API(JSObject *)
4772 JS_CompileFileHandleForPrincipalsVersion(JSContext *cx, JSObject *obj, const char *filename,
4773                                          FILE *file, JSPrincipals *principals, JSVersion version)
4774 {
4775     AutoVersionAPI ava(cx, version);
4776     return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, principals);
4777 }
4778
4779 JS_PUBLIC_API(JSObject *)
4780 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *file)
4781 {
4782     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4783     return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
4784 }
4785
4786 JS_PUBLIC_API(JSScript *)
4787 JS_GetScriptFromObject(JSObject *scriptObj)
4788 {
4789     JS_ASSERT(scriptObj->isScript());
4790
4791     return (JSScript *) scriptObj->getPrivate();
4792 }
4793
4794 static JSFunction *
4795 CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj,
4796                                      JSPrincipals *principals, const char *name,
4797                                      uintN nargs, const char **argnames,
4798                                      const jschar *chars, size_t length,
4799                                      const char *filename, uintN lineno, JSVersion version)
4800 {
4801     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4802     JSFunction *fun;
4803     JSAtom *funAtom, *argAtom;
4804     uintN i;
4805
4806     CHECK_REQUEST(cx);
4807     assertSameCompartment(cx, obj, principals);
4808     if (!name) {
4809         funAtom = NULL;
4810     } else {
4811         funAtom = js_Atomize(cx, name, strlen(name), 0);
4812         if (!funAtom) {
4813             fun = NULL;
4814             goto out2;
4815         }
4816     }
4817
4818     fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
4819     if (!fun)
4820         goto out2;
4821
4822     {
4823         AutoObjectRooter tvr(cx, FUN_OBJECT(fun));
4824         MUST_FLOW_THROUGH("out");
4825
4826         Bindings bindings(cx);
4827         AutoBindingsRooter root(cx, bindings);
4828         for (i = 0; i < nargs; i++) {
4829             argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
4830             if (!argAtom) {
4831                 fun = NULL;
4832                 goto out2;
4833             }
4834
4835             uint16 dummy;
4836             if (!bindings.addArgument(cx, argAtom, &dummy)) {
4837                 fun = NULL;
4838                 goto out2;
4839             }
4840         }
4841
4842         if (!Compiler::compileFunctionBody(cx, fun, principals, &bindings,
4843                                            chars, length, filename, lineno, version)) {
4844             fun = NULL;
4845             goto out2;
4846         }
4847
4848         if (obj && funAtom &&
4849             !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), ObjectValue(*fun),
4850                                  NULL, NULL, JSPROP_ENUMERATE)) {
4851             fun = NULL;
4852         }
4853
4854 #ifdef JS_SCOPE_DEPTH_METER
4855         if (fun && obj) {
4856             JSObject *pobj = obj;
4857             uintN depth = 1;
4858
4859             while ((pobj = pobj->getParent()) != NULL)
4860                 ++depth;
4861             JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
4862         }
4863 #endif
4864     }
4865
4866   out2:
4867     LAST_FRAME_CHECKS(cx, fun);
4868     return fun;
4869 }
4870 JS_PUBLIC_API(JSFunction *)
4871 JS_CompileUCFunctionForPrincipalsVersion(JSContext *cx, JSObject *obj,
4872                                          JSPrincipals *principals, const char *name,
4873                                          uintN nargs, const char **argnames,
4874                                          const jschar *chars, size_t length,
4875                                          const char *filename, uintN lineno,
4876                                          JSVersion version)
4877 {
4878     AutoVersionAPI avi(cx, version);
4879     return CompileUCFunctionForPrincipalsCommon(cx, obj, principals, name, nargs, argnames, chars,
4880                                                 length, filename, lineno, avi.version());
4881 }
4882
4883 JS_PUBLIC_API(JSFunction *)
4884 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
4885                                   JSPrincipals *principals, const char *name,
4886                                   uintN nargs, const char **argnames,
4887                                   const jschar *chars, size_t length,
4888                                   const char *filename, uintN lineno)
4889 {
4890     return CompileUCFunctionForPrincipalsCommon(cx, obj, principals, name, nargs, argnames, chars,
4891                                                 length, filename, lineno, cx->findVersion());
4892 }
4893
4894 JS_PUBLIC_API(JSFunction *)
4895 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
4896                      uintN nargs, const char **argnames,
4897                      const jschar *chars, size_t length,
4898                      const char *filename, uintN lineno)
4899 {
4900     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4901     return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames,
4902                                              chars, length, filename, lineno);
4903 }
4904
4905 JS_PUBLIC_API(JSFunction *)
4906 JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
4907                                 JSPrincipals *principals, const char *name,
4908                                 uintN nargs, const char **argnames,
4909                                 const char *bytes, size_t length,
4910                                 const char *filename, uintN lineno)
4911 {
4912     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4913     jschar *chars = js_InflateString(cx, bytes, &length);
4914     if (!chars)
4915         return NULL;
4916     JSFunction *fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
4917                                                         nargs, argnames, chars, length,
4918                                                         filename, lineno);
4919     cx->free(chars);
4920     return fun;
4921 }
4922
4923 JS_PUBLIC_API(JSFunction *)
4924 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
4925                    uintN nargs, const char **argnames,
4926                    const char *bytes, size_t length,
4927                    const char *filename, uintN lineno)
4928 {
4929     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4930     return JS_CompileFunctionForPrincipals(cx, obj, NULL, name, nargs, argnames, bytes, length,
4931                                            filename, lineno);
4932 }
4933
4934 JS_PUBLIC_API(JSString *)
4935 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name, uintN indent)
4936 {
4937     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4938     JSPrinter *jp;
4939     JSString *str;
4940
4941     CHECK_REQUEST(cx);
4942 #ifdef DEBUG
4943     if (cx->compartment != script->compartment)
4944         CompartmentChecker::fail(cx->compartment, script->compartment);
4945 #endif
4946     jp = js_NewPrinter(cx, name, NULL,
4947                        indent & ~JS_DONT_PRETTY_PRINT,
4948                        !(indent & JS_DONT_PRETTY_PRINT),
4949                        false, false);
4950     if (!jp)
4951         return NULL;
4952     if (js_DecompileScript(jp, script))
4953         str = js_GetPrinterOutput(jp);
4954     else
4955         str = NULL;
4956     js_DestroyPrinter(jp);
4957     return str;
4958 }
4959
4960 JS_PUBLIC_API(JSString *)
4961 JS_DecompileScriptObject(JSContext *cx, JSObject *scriptObj, const char *name, uintN indent)
4962 {
4963     return JS_DecompileScript(cx, scriptObj->getScript(), name, indent);
4964 }
4965
4966 JS_PUBLIC_API(JSString *)
4967 JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
4968 {
4969     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4970     CHECK_REQUEST(cx);
4971     assertSameCompartment(cx, fun);
4972     return js_DecompileToString(cx, "JS_DecompileFunction", fun,
4973                                 indent & ~JS_DONT_PRETTY_PRINT,
4974                                 !(indent & JS_DONT_PRETTY_PRINT),
4975                                 false, false, js_DecompileFunction);
4976 }
4977
4978 JS_PUBLIC_API(JSString *)
4979 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
4980 {
4981     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4982     CHECK_REQUEST(cx);
4983     assertSameCompartment(cx, fun);
4984     return js_DecompileToString(cx, "JS_DecompileFunctionBody", fun,
4985                                 indent & ~JS_DONT_PRETTY_PRINT,
4986                                 !(indent & JS_DONT_PRETTY_PRINT),
4987                                 false, false, js_DecompileFunctionBody);
4988 }
4989
4990 JS_PUBLIC_API(JSBool)
4991 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSObject *scriptObj, jsval *rval)
4992 {
4993     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
4994
4995     CHECK_REQUEST(cx);
4996     assertSameCompartment(cx, obj, scriptObj);
4997
4998     JSBool ok = Execute(cx, obj, scriptObj->getScript(), NULL, 0, Valueify(rval));
4999     LAST_FRAME_CHECKS(cx, ok);
5000     return ok;
5001 }
5002
5003 JS_PUBLIC_API(JSBool)
5004 JS_ExecuteScriptVersion(JSContext *cx, JSObject *obj, JSObject *scriptObj, jsval *rval,
5005                         JSVersion version)
5006 {
5007     AutoVersionAPI ava(cx, version);
5008     return JS_ExecuteScript(cx, obj, scriptObj, rval);
5009 }
5010
5011 bool
5012 EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj,
5013                                     JSPrincipals *principals,
5014                                     const jschar *chars, uintN length,
5015                                     const char *filename, uintN lineno,
5016                                     jsval *rval, JSVersion compileVersion)
5017 {
5018     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5019
5020     CHECK_REQUEST(cx);
5021     JSScript *script = Compiler::compileScript(cx, obj, NULL, principals,
5022                                                !rval
5023                                                ? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
5024                                                : TCF_COMPILE_N_GO,
5025                                                chars, length, filename, lineno, compileVersion);
5026     if (!script) {
5027         LAST_FRAME_CHECKS(cx, script);
5028         return false;
5029     }
5030     JS_ASSERT(script->getVersion() == compileVersion);
5031     bool ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
5032     LAST_FRAME_CHECKS(cx, ok);
5033     js_DestroyScript(cx, script);
5034     return ok;
5035
5036 }
5037
5038 JS_PUBLIC_API(JSBool)
5039 JS_EvaluateUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj,
5040                                         JSPrincipals *principals,
5041                                         const jschar *chars, uintN length,
5042                                         const char *filename, uintN lineno,
5043                                         jsval *rval, JSVersion version)
5044 {
5045     AutoVersionAPI avi(cx, version);
5046     return EvaluateUCScriptForPrincipalsCommon(cx, obj, principals, chars, length,
5047                                                filename, lineno, rval, avi.version());
5048 }
5049
5050 JS_PUBLIC_API(JSBool)
5051 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
5052                                  JSPrincipals *principals,
5053                                  const jschar *chars, uintN length,
5054                                  const char *filename, uintN lineno,
5055                                  jsval *rval)
5056 {
5057     return EvaluateUCScriptForPrincipalsCommon(cx, obj, principals, chars, length,
5058                                                filename, lineno, rval, cx->findVersion());
5059 }
5060
5061 JS_PUBLIC_API(JSBool)
5062 JS_EvaluateUCScript(JSContext *cx, JSObject *obj, const jschar *chars, uintN length,
5063                     const char *filename, uintN lineno, jsval *rval)
5064 {
5065     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5066     return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length, filename, lineno, rval);
5067 }
5068
5069 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
5070 JS_PUBLIC_API(JSBool)
5071 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *principals,
5072                                const char *bytes, uintN nbytes,
5073                                const char *filename, uintN lineno, jsval *rval)
5074 {
5075     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5076     size_t length = nbytes;
5077     jschar *chars = js_InflateString(cx, bytes, &length);
5078     if (!chars)
5079         return JS_FALSE;
5080     JSBool ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
5081                                                  filename, lineno, rval);
5082     cx->free(chars);
5083     return ok;
5084 }
5085
5086 JS_PUBLIC_API(JSBool)
5087 JS_EvaluateScriptForPrincipalsVersion(JSContext *cx, JSObject *obj, JSPrincipals *principals,
5088                                       const char *bytes, uintN nbytes,
5089                                       const char *filename, uintN lineno, jsval *rval, JSVersion version)
5090 {
5091     AutoVersionAPI avi(cx, version);
5092     return JS_EvaluateScriptForPrincipals(cx, obj, principals, bytes, nbytes, filename, lineno,
5093                                           rval);
5094 }
5095
5096 JS_PUBLIC_API(JSBool)
5097 JS_EvaluateScript(JSContext *cx, JSObject *obj, const char *bytes, uintN nbytes,
5098                   const char *filename, uintN lineno, jsval *rval)
5099 {
5100     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5101     return JS_EvaluateScriptForPrincipals(cx, obj, NULL, bytes, nbytes, filename, lineno, rval);
5102 }
5103
5104 JS_PUBLIC_API(JSBool)
5105 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, jsval *argv,
5106                 jsval *rval)
5107 {
5108     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5109     CHECK_REQUEST(cx);
5110     assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc));
5111     JSBool ok = ExternalInvoke(cx, ObjectOrNullValue(obj), ObjectValue(*fun), argc,
5112                                Valueify(argv), Valueify(rval));
5113     LAST_FRAME_CHECKS(cx, ok);
5114     return ok;
5115 }
5116
5117 JS_PUBLIC_API(JSBool)
5118 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, jsval *argv,
5119                     jsval *rval)
5120 {
5121     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5122     CHECK_REQUEST(cx);
5123     assertSameCompartment(cx, obj, JSValueArray(argv, argc));
5124
5125     AutoValueRooter tvr(cx);
5126     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
5127     JSBool ok =
5128         atom &&
5129         js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, tvr.addr()) &&
5130         ExternalInvoke(cx, ObjectOrNullValue(obj), tvr.value(), argc, Valueify(argv),
5131                        Valueify(rval));
5132     LAST_FRAME_CHECKS(cx, ok);
5133     return ok;
5134 }
5135
5136 JS_PUBLIC_API(JSBool)
5137 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, jsval *argv,
5138                      jsval *rval)
5139 {
5140     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
5141
5142     CHECK_REQUEST(cx);
5143     assertSameCompartment(cx, obj, fval, JSValueArray(argv, argc));
5144     JSBool ok = ExternalInvoke(cx, ObjectOrNullValue(obj), Valueify(fval), argc, Valueify(argv),
5145                                Valueify(rval));
5146     LAST_FRAME_CHECKS(cx, ok);
5147     return ok;
5148 }
5149
5150 namespace JS {
5151
5152 JS_PUBLIC_API(bool)
5153 Call(JSContext *cx, jsval thisv, jsval fval, uintN argc, jsval *argv, jsval *rval)
5154 {
5155     JSBool ok;
5156
5157     CHECK_REQUEST(cx);
5158     assertSameCompartment(cx, thisv, fval, JSValueArray(argv, argc));
5159     ok = ExternalInvoke(cx, Valueify(thisv), Valueify(fval), argc, Valueify(argv), Valueify(rval));
5160     LAST_FRAME_CHECKS(cx, ok);
5161     return ok;
5162 }
5163
5164 } // namespace JS
5165
5166 JS_PUBLIC_API(JSObject *)
5167 JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv)
5168 {
5169     CHECK_REQUEST(cx);
5170     assertSameCompartment(cx, ctor, JSValueArray(argv, argc));
5171
5172     // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
5173     // is not a simple variation of JSOP_CALL. We have to determine what class
5174     // of object to create, create it, and clamp the return value to an object,
5175     // among other details. js_InvokeConstructor does the hard work.
5176     InvokeArgsGuard args;
5177     if (!cx->stack().pushInvokeArgs(cx, argc, &args))
5178         return NULL;
5179
5180     args.callee().setObject(*ctor);
5181     args.thisv().setNull();
5182     memcpy(args.argv(), argv, argc * sizeof(jsval));
5183
5184     bool ok = InvokeConstructor(cx, args);
5185
5186     JSObject *obj = NULL;
5187     if (ok) {
5188         if (args.rval().isObject()) {
5189             obj = &args.rval().toObject();
5190         } else {
5191             /*
5192              * Although constructors may return primitives (via proxies), this
5193              * API is asking for an object, so we report an error.
5194              */
5195             JSAutoByteString bytes;
5196             if (js_ValueToPrintable(cx, args.rval(), &bytes)) {
5197                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_NEW_RESULT,
5198                                      bytes.ptr());
5199             }
5200         }
5201     }
5202
5203     LAST_FRAME_CHECKS(cx, ok);
5204     return obj;
5205 }
5206
5207 JS_PUBLIC_API(JSOperationCallback)
5208 JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback)
5209 {
5210 #ifdef JS_THREADSAFE
5211     JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
5212 #endif
5213     JSOperationCallback old = cx->operationCallback;
5214     cx->operationCallback = callback;
5215     return old;
5216 }
5217
5218 JS_PUBLIC_API(JSOperationCallback)
5219 JS_GetOperationCallback(JSContext *cx)
5220 {
5221     return cx->operationCallback;
5222 }
5223
5224 JS_PUBLIC_API(void)
5225 JS_TriggerOperationCallback(JSContext *cx)
5226 {
5227 #ifdef JS_THREADSAFE
5228     AutoLockGC lock(cx->runtime);
5229 #endif
5230     TriggerOperationCallback(cx);
5231 }
5232
5233 JS_PUBLIC_API(void)
5234 JS_TriggerAllOperationCallbacks(JSRuntime *rt)
5235 {
5236 #ifdef JS_THREADSAFE
5237     AutoLockGC lock(rt);
5238 #endif
5239     TriggerAllOperationCallbacks(rt);
5240 }
5241
5242 JS_PUBLIC_API(JSBool)
5243 JS_IsRunning(JSContext *cx)
5244 {
5245     /*
5246      * The use of cx->fp below is safe. Rationale: Here we don't care if the
5247      * interpreter state is stale. We just want to know if there *is* any
5248      * interpreter state.
5249      */
5250     VOUCH_DOES_NOT_REQUIRE_STACK();
5251
5252 #ifdef JS_TRACER
5253     JS_ASSERT_IF(JS_ON_TRACE(cx) && JS_TRACE_MONITOR_ON_TRACE(cx)->tracecx == cx, cx->hasfp());
5254 #endif
5255     JSStackFrame *fp = cx->maybefp();
5256     while (fp && fp->isDummyFrame())
5257         fp = fp->prev();
5258     return fp != NULL;
5259 }
5260
5261 JS_PUBLIC_API(JSStackFrame *)
5262 JS_SaveFrameChain(JSContext *cx)
5263 {
5264     CHECK_REQUEST(cx);
5265     JSStackFrame *fp = js_GetTopStackFrame(cx);
5266     if (!fp)
5267         return NULL;
5268     cx->saveActiveSegment();
5269     return fp;
5270 }
5271
5272 JS_PUBLIC_API(void)
5273 JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
5274 {
5275     CHECK_REQUEST(cx);
5276     JS_ASSERT_NOT_ON_TRACE(cx);
5277     JS_ASSERT(!cx->hasfp());
5278     if (!fp)
5279         return;
5280     cx->restoreSegment();
5281 }
5282
5283 /************************************************************************/
5284 JS_PUBLIC_API(JSString *)
5285 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
5286 {
5287     CHECK_REQUEST(cx);
5288     return js_NewStringCopyN(cx, s, n);
5289 }
5290
5291 JS_PUBLIC_API(JSString *)
5292 JS_NewStringCopyZ(JSContext *cx, const char *s)
5293 {
5294     size_t n;
5295     jschar *js;
5296     JSString *str;
5297
5298     CHECK_REQUEST(cx);
5299     if (!s)
5300         return cx->runtime->emptyString;
5301     n = strlen(s);
5302     js = js_InflateString(cx, s, &n);
5303     if (!js)
5304         return NULL;
5305     str = js_NewString(cx, js, n);
5306     if (!str)
5307         cx->free(js);
5308     return str;
5309 }
5310
5311 JS_PUBLIC_API(JSBool)
5312 JS_StringHasBeenInterned(JSString *str)
5313 {
5314     return str->isAtomized();
5315 }
5316
5317 JS_PUBLIC_API(JSString *)
5318 JS_InternJSString(JSContext *cx, JSString *str)
5319 {
5320     CHECK_REQUEST(cx);
5321     JSAtom *atom = js_AtomizeString(cx, str, 0);
5322     if (!atom)
5323         return NULL;
5324     return ATOM_TO_STRING(atom);
5325 }
5326
5327 JS_PUBLIC_API(JSString *)
5328 JS_InternString(JSContext *cx, const char *s)
5329 {
5330     JSAtom *atom;
5331
5332     CHECK_REQUEST(cx);
5333     atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
5334     if (!atom)
5335         return NULL;
5336     return ATOM_TO_STRING(atom);
5337 }
5338
5339 JS_PUBLIC_API(JSString *)
5340 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
5341 {
5342     CHECK_REQUEST(cx);
5343     return js_NewString(cx, chars, length);
5344 }
5345
5346 JS_PUBLIC_API(JSString *)
5347 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
5348 {
5349     CHECK_REQUEST(cx);
5350     return js_NewStringCopyN(cx, s, n);
5351 }
5352
5353 JS_PUBLIC_API(JSString *)
5354 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
5355 {
5356     CHECK_REQUEST(cx);
5357     if (!s)
5358         return cx->runtime->emptyString;
5359     return js_NewStringCopyZ(cx, s);
5360 }
5361
5362 JS_PUBLIC_API(JSString *)
5363 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
5364 {
5365     JSAtom *atom;
5366
5367     CHECK_REQUEST(cx);
5368     atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
5369     if (!atom)
5370         return NULL;
5371     return ATOM_TO_STRING(atom);
5372 }
5373
5374 JS_PUBLIC_API(JSString *)
5375 JS_InternUCString(JSContext *cx, const jschar *s)
5376 {
5377     return JS_InternUCStringN(cx, s, js_strlen(s));
5378 }
5379
5380 JS_PUBLIC_API(size_t)
5381 JS_GetStringLength(JSString *str)
5382 {
5383     return str->length();
5384 }
5385
5386 JS_PUBLIC_API(const jschar *)
5387 JS_GetStringCharsZ(JSContext *cx, JSString *str)
5388 {
5389     CHECK_REQUEST(cx);
5390     assertSameCompartment(cx, str);
5391     return str->getCharsZ(cx);
5392 }
5393
5394 JS_PUBLIC_API(const jschar *)
5395 JS_GetStringCharsZAndLength(JSContext *cx, JSString *str, size_t *plength)
5396 {
5397     CHECK_REQUEST(cx);
5398     assertSameCompartment(cx, str);
5399     *plength = str->length();
5400     return str->getCharsZ(cx);
5401 }
5402
5403 JS_PUBLIC_API(const jschar *)
5404 JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
5405 {
5406     CHECK_REQUEST(cx);
5407     assertSameCompartment(cx, str);
5408     *plength = str->length();
5409     return str->getChars(cx);
5410 }
5411
5412 JS_PUBLIC_API(const jschar *)
5413 JS_GetInternedStringChars(JSString *str)
5414 {
5415     JS_ASSERT(str->isAtomized());
5416     return str->flatChars();
5417 }
5418
5419 JS_PUBLIC_API(const jschar *)
5420 JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength)
5421 {
5422     JS_ASSERT(str->isAtomized());
5423     *plength = str->flatLength();
5424     return str->flatChars();
5425 }
5426
5427 extern JS_PUBLIC_API(JSFlatString *)
5428 JS_FlattenString(JSContext *cx, JSString *str)
5429 {
5430     CHECK_REQUEST(cx);
5431     assertSameCompartment(cx, str);
5432     return str->getCharsZ(cx) ? (JSFlatString *)str : NULL;
5433 }
5434
5435 extern JS_PUBLIC_API(const jschar *)
5436 JS_GetFlatStringChars(JSFlatString *str)
5437 {
5438     return str->chars();
5439 }
5440
5441 JS_PUBLIC_API(JSBool)
5442 JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result)
5443 {
5444     return CompareStrings(cx, str1, str2, result);
5445 }
5446
5447 JS_PUBLIC_API(JSBool)
5448 JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match)
5449 {
5450     JSLinearString *linearStr = str->ensureLinear(cx);
5451     if (!linearStr)
5452         return false;
5453     *match = StringEqualsAscii(linearStr, asciiBytes);
5454     return true;
5455 }
5456
5457 JS_PUBLIC_API(JSBool)
5458 JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes)
5459 {
5460     return StringEqualsAscii(str, asciiBytes);
5461 }
5462
5463 JS_PUBLIC_API(size_t)
5464 JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote)
5465 {
5466     return PutEscapedString(buffer, size, str, quote);
5467 }
5468
5469 JS_PUBLIC_API(size_t)
5470 JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote)
5471 {
5472     JSLinearString *linearStr = str->ensureLinear(cx);
5473     if (!linearStr)
5474         return size_t(-1);
5475     return PutEscapedString(buffer, size, linearStr, quote);
5476 }
5477
5478 JS_PUBLIC_API(JSBool)
5479 JS_FileEscapedString(FILE *fp, JSString *str, char quote)
5480 {
5481     JSLinearString *linearStr = str->ensureLinear(NULL);
5482     return linearStr && FileEscapedString(fp, linearStr, quote);
5483 }
5484
5485 JS_PUBLIC_API(JSString *)
5486 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
5487 {
5488     CHECK_REQUEST(cx);
5489     return js_NewString(cx, chars, length);
5490 }
5491
5492 JS_PUBLIC_API(JSString *)
5493 JS_NewDependentString(JSContext *cx, JSString *str, size_t start, size_t length)
5494 {
5495     CHECK_REQUEST(cx);
5496     return js_NewDependentString(cx, str, start, length);
5497 }
5498
5499 JS_PUBLIC_API(JSString *)
5500 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
5501 {
5502     CHECK_REQUEST(cx);
5503     return js_ConcatStrings(cx, left, right);
5504 }
5505
5506 JS_PUBLIC_API(const jschar *)
5507 JS_UndependString(JSContext *cx, JSString *str)
5508 {
5509     CHECK_REQUEST(cx);
5510     return str->getCharsZ(cx);
5511 }
5512
5513 JS_PUBLIC_API(JSBool)
5514 JS_MakeStringImmutable(JSContext *cx, JSString *str)
5515 {
5516     CHECK_REQUEST(cx);
5517     return js_MakeStringImmutable(cx, str);
5518 }
5519
5520 JS_PUBLIC_API(JSBool)
5521 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst, size_t *dstlenp)
5522 {
5523     size_t n;
5524     if (!dst) {
5525         n = js_GetDeflatedStringLength(cx, src, srclen);
5526         if (n == (size_t)-1) {
5527             *dstlenp = 0;
5528             return JS_FALSE;
5529         }
5530         *dstlenp = n;
5531         return JS_TRUE;
5532     }
5533
5534     return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5535 }
5536
5537 JS_PUBLIC_API(JSBool)
5538 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp)
5539 {
5540     return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5541 }
5542
5543 JS_PUBLIC_API(char *)
5544 JS_EncodeString(JSContext *cx, JSString *str)
5545 {
5546     const jschar *chars = str->getChars(cx);
5547     if (!chars)
5548         return NULL;
5549     return js_DeflateString(cx, chars, str->length());
5550 }
5551
5552 JS_PUBLIC_API(size_t)
5553 JS_GetStringEncodingLength(JSContext *cx, JSString *str)
5554 {
5555     const jschar *chars = str->getChars(cx);
5556     if (!chars)
5557         return size_t(-1);
5558     return js_GetDeflatedStringLength(cx, chars, str->length());
5559 }
5560
5561 JS_PUBLIC_API(size_t)
5562 JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length)
5563 {
5564     /*
5565      * FIXME bug 612141 - fix js_DeflateStringToBuffer interface so the result
5566      * would allow to distinguish between insufficient buffer and encoding
5567      * error.
5568      */
5569     size_t writtenLength = length;
5570     const jschar *chars = str->getChars(NULL);
5571     if (!chars)
5572         return size_t(-1);
5573     if (js_DeflateStringToBuffer(NULL, chars, str->length(), buffer, &writtenLength)) {
5574         JS_ASSERT(writtenLength <= length);
5575         return writtenLength;
5576     }
5577     JS_ASSERT(writtenLength <= length);
5578     size_t necessaryLength = js_GetDeflatedStringLength(NULL, chars, str->length());
5579     if (necessaryLength == size_t(-1))
5580         return size_t(-1);
5581     if (writtenLength != length) {
5582         /* Make sure that the buffer contains only valid UTF-8 sequences. */
5583         JS_ASSERT(js_CStringsAreUTF8);
5584         PodZero(buffer + writtenLength, length - writtenLength);
5585     }
5586     return necessaryLength;
5587 }
5588
5589 JS_PUBLIC_API(JSBool)
5590 JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space,
5591              JSONWriteCallback callback, void *data)
5592 {
5593     CHECK_REQUEST(cx);
5594     assertSameCompartment(cx, replacer, space);
5595     StringBuffer sb(cx);
5596     if (!js_Stringify(cx, Valueify(vp), replacer, Valueify(space), sb))
5597         return false;
5598     return callback(sb.begin(), sb.length(), data);
5599 }
5600
5601 JS_PUBLIC_API(JSBool)
5602 JS_TryJSON(JSContext *cx, jsval *vp)
5603 {
5604     CHECK_REQUEST(cx);
5605     assertSameCompartment(cx, *vp);
5606     return js_TryJSON(cx, Valueify(vp));
5607 }
5608
5609 JS_PUBLIC_API(JSONParser *)
5610 JS_BeginJSONParse(JSContext *cx, jsval *vp)
5611 {
5612     CHECK_REQUEST(cx);
5613     return js_BeginJSONParse(cx, Valueify(vp));
5614 }
5615
5616 JS_PUBLIC_API(JSBool)
5617 JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len)
5618 {
5619     CHECK_REQUEST(cx);
5620     return js_ConsumeJSONText(cx, jp, data, len);
5621 }
5622
5623 JS_PUBLIC_API(JSBool)
5624 JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver)
5625 {
5626     CHECK_REQUEST(cx);
5627     assertSameCompartment(cx, reviver);
5628     return js_FinishJSONParse(cx, jp, Valueify(reviver));
5629 }
5630
5631 JS_PUBLIC_API(JSBool)
5632 JS_ReadStructuredClone(JSContext *cx, const uint64 *buf, size_t nbytes,
5633                        uint32 version, jsval *vp,
5634                        const JSStructuredCloneCallbacks *optionalCallbacks,
5635                        void *closure)
5636 {
5637     if (version > JS_STRUCTURED_CLONE_VERSION) {
5638         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CLONE_VERSION);
5639         return false;
5640     }
5641     const JSStructuredCloneCallbacks *callbacks =
5642         optionalCallbacks ?
5643         optionalCallbacks :
5644         cx->runtime->structuredCloneCallbacks;
5645     return ReadStructuredClone(cx, buf, nbytes, Valueify(vp), callbacks, closure);
5646 }
5647
5648 JS_PUBLIC_API(JSBool)
5649 JS_WriteStructuredClone(JSContext *cx, jsval v, uint64 **bufp, size_t *nbytesp,
5650                         const JSStructuredCloneCallbacks *optionalCallbacks,
5651                         void *closure)
5652 {
5653     const JSStructuredCloneCallbacks *callbacks =
5654         optionalCallbacks ?
5655         optionalCallbacks :
5656         cx->runtime->structuredCloneCallbacks;
5657     return WriteStructuredClone(cx, Valueify(v), (uint64_t **) bufp, nbytesp,
5658                                 callbacks, closure);
5659 }
5660
5661 JS_PUBLIC_API(JSBool)
5662 JS_StructuredClone(JSContext *cx, jsval v, jsval *vp,
5663                    ReadStructuredCloneOp optionalReadOp,
5664                    const JSStructuredCloneCallbacks *optionalCallbacks,
5665                    void *closure)
5666 {
5667     const JSStructuredCloneCallbacks *callbacks =
5668         optionalCallbacks ?
5669         optionalCallbacks :
5670         cx->runtime->structuredCloneCallbacks;
5671     JSAutoStructuredCloneBuffer buf;
5672     return buf.write(cx, v, callbacks, closure) &&
5673            buf.read(vp, cx, callbacks, closure);
5674 }
5675
5676 JS_PUBLIC_API(void)
5677 JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks)
5678 {
5679     rt->structuredCloneCallbacks = callbacks;
5680 }
5681
5682 JS_PUBLIC_API(JSBool)
5683 JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32 *p1, uint32 *p2)
5684 {
5685     return r->input().readPair((uint32_t *) p1, (uint32_t *) p2);
5686 }
5687
5688 JS_PUBLIC_API(JSBool)
5689 JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len)
5690 {
5691     return r->input().readBytes(p, len);
5692 }
5693
5694 JS_PUBLIC_API(JSBool)
5695 JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32 tag, uint32 data)
5696 {
5697     return w->output().writePair(tag, data);
5698 }
5699
5700 JS_PUBLIC_API(JSBool)
5701 JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len)
5702 {
5703     return w->output().writeBytes(p, len);
5704 }
5705
5706 /*
5707  * The following determines whether C Strings are to be treated as UTF-8
5708  * or ISO-8859-1.  For correct operation, it must be set prior to the
5709  * first call to JS_NewRuntime.
5710  */
5711 #ifndef JS_C_STRINGS_ARE_UTF8
5712 JSBool js_CStringsAreUTF8 = JS_FALSE;
5713 #endif
5714
5715 JS_PUBLIC_API(JSBool)
5716 JS_CStringsAreUTF8()
5717 {
5718     return js_CStringsAreUTF8;
5719 }
5720
5721 JS_PUBLIC_API(void)
5722 JS_SetCStringsAreUTF8()
5723 {
5724     JS_ASSERT(!js_NewRuntimeWasCalled);
5725
5726 #ifndef JS_C_STRINGS_ARE_UTF8
5727     js_CStringsAreUTF8 = JS_TRUE;
5728 #endif
5729 }
5730
5731 /************************************************************************/
5732
5733 JS_PUBLIC_API(void)
5734 JS_ReportError(JSContext *cx, const char *format, ...)
5735 {
5736     va_list ap;
5737
5738     va_start(ap, format);
5739     js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
5740     va_end(ap);
5741 }
5742
5743 JS_PUBLIC_API(void)
5744 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
5745                      void *userRef, const uintN errorNumber, ...)
5746 {
5747     va_list ap;
5748
5749     va_start(ap, errorNumber);
5750     js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5751                            errorNumber, JS_TRUE, ap);
5752     va_end(ap);
5753 }
5754
5755 JS_PUBLIC_API(void)
5756 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
5757                      void *userRef, const uintN errorNumber, ...)
5758 {
5759     va_list ap;
5760
5761     va_start(ap, errorNumber);
5762     js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5763                            errorNumber, JS_FALSE, ap);
5764     va_end(ap);
5765 }
5766
5767 JS_PUBLIC_API(JSBool)
5768 JS_ReportWarning(JSContext *cx, const char *format, ...)
5769 {
5770     va_list ap;
5771     JSBool ok;
5772
5773     va_start(ap, format);
5774     ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
5775     va_end(ap);
5776     return ok;
5777 }
5778
5779 JS_PUBLIC_API(JSBool)
5780 JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
5781                              JSErrorCallback errorCallback, void *userRef,
5782                              const uintN errorNumber, ...)
5783 {
5784     va_list ap;
5785     JSBool ok;
5786
5787     va_start(ap, errorNumber);
5788     ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5789                                 errorNumber, JS_TRUE, ap);
5790     va_end(ap);
5791     return ok;
5792 }
5793
5794 JS_PUBLIC_API(JSBool)
5795 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
5796                                JSErrorCallback errorCallback, void *userRef,
5797                                const uintN errorNumber, ...)
5798 {
5799     va_list ap;
5800     JSBool ok;
5801
5802     va_start(ap, errorNumber);
5803     ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5804                                 errorNumber, JS_FALSE, ap);
5805     va_end(ap);
5806     return ok;
5807 }
5808
5809 JS_PUBLIC_API(void)
5810 JS_ReportOutOfMemory(JSContext *cx)
5811 {
5812     js_ReportOutOfMemory(cx);
5813 }
5814
5815 JS_PUBLIC_API(void)
5816 JS_ReportAllocationOverflow(JSContext *cx)
5817 {
5818     js_ReportAllocationOverflow(cx);
5819 }
5820
5821 JS_PUBLIC_API(JSErrorReporter)
5822 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
5823 {
5824     JSErrorReporter older;
5825
5826     older = cx->errorReporter;
5827     cx->errorReporter = er;
5828     return older;
5829 }
5830
5831 /************************************************************************/
5832
5833 /*
5834  * Dates.
5835  */
5836 JS_PUBLIC_API(JSObject *)
5837 JS_NewDateObject(JSContext *cx, int year, int mon, int mday, int hour, int min, int sec)
5838 {
5839     CHECK_REQUEST(cx);
5840     return js_NewDateObject(cx, year, mon, mday, hour, min, sec);
5841 }
5842
5843 JS_PUBLIC_API(JSObject *)
5844 JS_NewDateObjectMsec(JSContext *cx, jsdouble msec)
5845 {
5846     CHECK_REQUEST(cx);
5847     return js_NewDateObjectMsec(cx, msec);
5848 }
5849
5850 JS_PUBLIC_API(JSBool)
5851 JS_ObjectIsDate(JSContext *cx, JSObject *obj)
5852 {
5853     JS_ASSERT(obj);
5854     return obj->isDate();
5855 }
5856
5857 /************************************************************************/
5858
5859 /*
5860  * Regular Expressions.
5861  */
5862 JS_PUBLIC_API(JSObject *)
5863 JS_NewRegExpObject(JSContext *cx, JSObject *obj, char *bytes, size_t length, uintN flags)
5864 {
5865     CHECK_REQUEST(cx);
5866     jschar *chars = js_InflateString(cx, bytes, &length);
5867     if (!chars)
5868         return NULL;
5869     RegExpStatics *res = RegExpStatics::extractFrom(obj);
5870     JSObject *reobj = RegExp::createObject(cx, res, chars, length, flags);
5871     cx->free(chars);
5872     return reobj;
5873 }
5874
5875 JS_PUBLIC_API(JSObject *)
5876 JS_NewUCRegExpObject(JSContext *cx, JSObject *obj, jschar *chars, size_t length, uintN flags)
5877 {
5878     CHECK_REQUEST(cx);
5879     RegExpStatics *res = RegExpStatics::extractFrom(obj);
5880     return RegExp::createObject(cx, res, chars, length, flags);
5881 }
5882
5883 JS_PUBLIC_API(void)
5884 JS_SetRegExpInput(JSContext *cx, JSObject *obj, JSString *input, JSBool multiline)
5885 {
5886     CHECK_REQUEST(cx);
5887     assertSameCompartment(cx, input);
5888
5889     RegExpStatics::extractFrom(obj)->reset(input, !!multiline);
5890 }
5891
5892 JS_PUBLIC_API(void)
5893 JS_ClearRegExpStatics(JSContext *cx, JSObject *obj)
5894 {
5895     CHECK_REQUEST(cx);
5896     JS_ASSERT(obj);
5897
5898     RegExpStatics::extractFrom(obj)->clear();
5899 }
5900
5901 JS_PUBLIC_API(JSBool)
5902 JS_ExecuteRegExp(JSContext *cx, JSObject *obj, JSObject *reobj, jschar *chars, size_t length,
5903                  size_t *indexp, JSBool test, jsval *rval)
5904 {
5905     CHECK_REQUEST(cx);
5906
5907     RegExp *re = RegExp::extractFrom(reobj);
5908     if (!re)
5909         return false;
5910
5911     JSString *str = js_NewStringCopyN(cx, chars, length);
5912     if (!str)
5913         return false;
5914
5915     return re->execute(cx, RegExpStatics::extractFrom(obj), str, indexp, test, Valueify(rval));
5916 }
5917
5918 JS_PUBLIC_API(JSObject *)
5919 JS_NewRegExpObjectNoStatics(JSContext *cx, char *bytes, size_t length, uintN flags)
5920 {
5921     CHECK_REQUEST(cx);
5922     jschar *chars = js_InflateString(cx, bytes, &length);
5923     if (!chars)
5924         return NULL;
5925     JSObject *obj = RegExp::createObjectNoStatics(cx, chars, length, flags);
5926     cx->free(chars);
5927     return obj;
5928 }
5929
5930 JS_PUBLIC_API(JSObject *)
5931 JS_NewUCRegExpObjectNoStatics(JSContext *cx, jschar *chars, size_t length, uintN flags)
5932 {
5933     CHECK_REQUEST(cx);
5934     return RegExp::createObjectNoStatics(cx, chars, length, flags);
5935 }
5936
5937 JS_PUBLIC_API(JSBool)
5938 JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *obj, jschar *chars, size_t length,
5939                           size_t *indexp, JSBool test, jsval *rval)
5940 {
5941     CHECK_REQUEST(cx);
5942
5943     RegExp *re = RegExp::extractFrom(obj);
5944     if (!re)
5945         return false;
5946
5947     JSString *str = js_NewStringCopyN(cx, chars, length);
5948     if (!str)
5949         return false;
5950
5951     return re->executeNoStatics(cx, str, indexp, test, Valueify(rval));
5952 }
5953
5954 /************************************************************************/
5955
5956 JS_PUBLIC_API(void)
5957 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
5958 {
5959     cx->localeCallbacks = callbacks;
5960 }
5961
5962 JS_PUBLIC_API(JSLocaleCallbacks *)
5963 JS_GetLocaleCallbacks(JSContext *cx)
5964 {
5965     return cx->localeCallbacks;
5966 }
5967
5968 /************************************************************************/
5969
5970 JS_PUBLIC_API(JSBool)
5971 JS_IsExceptionPending(JSContext *cx)
5972 {
5973     return (JSBool) cx->isExceptionPending();
5974 }
5975
5976 JS_PUBLIC_API(JSBool)
5977 JS_GetPendingException(JSContext *cx, jsval *vp)
5978 {
5979     CHECK_REQUEST(cx);
5980     if (!cx->isExceptionPending())
5981         return JS_FALSE;
5982     Valueify(*vp) = cx->getPendingException();
5983     assertSameCompartment(cx, *vp);
5984     return JS_TRUE;
5985 }
5986
5987 JS_PUBLIC_API(void)
5988 JS_SetPendingException(JSContext *cx, jsval v)
5989 {
5990     CHECK_REQUEST(cx);
5991     assertSameCompartment(cx, v);
5992     cx->setPendingException(Valueify(v));
5993 }
5994
5995 JS_PUBLIC_API(void)
5996 JS_ClearPendingException(JSContext *cx)
5997 {
5998     cx->clearPendingException();
5999 }
6000
6001 JS_PUBLIC_API(JSBool)
6002 JS_ReportPendingException(JSContext *cx)
6003 {
6004     JSBool ok;
6005     JSPackedBool save;
6006
6007     CHECK_REQUEST(cx);
6008
6009     /*
6010      * Set cx->generatingError to suppress the standard error-to-exception
6011      * conversion done by all {js,JS}_Report* functions except for OOM.  The
6012      * cx->generatingError flag was added to suppress recursive divergence
6013      * under js_ErrorToException, but it serves for our purposes here too.
6014      */
6015     save = cx->generatingError;
6016     cx->generatingError = JS_TRUE;
6017     ok = js_ReportUncaughtException(cx);
6018     cx->generatingError = save;
6019     return ok;
6020 }
6021
6022 struct JSExceptionState {
6023     JSBool throwing;
6024     jsval  exception;
6025 };
6026
6027 JS_PUBLIC_API(JSExceptionState *)
6028 JS_SaveExceptionState(JSContext *cx)
6029 {
6030     JSExceptionState *state;
6031
6032     CHECK_REQUEST(cx);
6033     state = (JSExceptionState *) cx->malloc(sizeof(JSExceptionState));
6034     if (state) {
6035         state->throwing = JS_GetPendingException(cx, &state->exception);
6036         if (state->throwing && JSVAL_IS_GCTHING(state->exception))
6037             js_AddRoot(cx, Valueify(&state->exception), "JSExceptionState.exception");
6038     }
6039     return state;
6040 }
6041
6042 JS_PUBLIC_API(void)
6043 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
6044 {
6045     CHECK_REQUEST(cx);
6046     if (state) {
6047         if (state->throwing)
6048             JS_SetPendingException(cx, state->exception);
6049         else
6050             JS_ClearPendingException(cx);
6051         JS_DropExceptionState(cx, state);
6052     }
6053 }
6054
6055 JS_PUBLIC_API(void)
6056 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
6057 {
6058     CHECK_REQUEST(cx);
6059     if (state) {
6060         if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
6061             assertSameCompartment(cx, state->exception);
6062             JS_RemoveValueRoot(cx, &state->exception);
6063         }
6064         cx->free(state);
6065     }
6066 }
6067
6068 JS_PUBLIC_API(JSErrorReport *)
6069 JS_ErrorFromException(JSContext *cx, jsval v)
6070 {
6071     CHECK_REQUEST(cx);
6072     assertSameCompartment(cx, v);
6073     return js_ErrorFromException(cx, v);
6074 }
6075
6076 JS_PUBLIC_API(JSBool)
6077 JS_ThrowReportedError(JSContext *cx, const char *message,
6078                       JSErrorReport *reportp)
6079 {
6080     return JS_IsRunning(cx) &&
6081            js_ErrorToException(cx, message, reportp, NULL, NULL);
6082 }
6083
6084 JS_PUBLIC_API(JSBool)
6085 JS_ThrowStopIteration(JSContext *cx)
6086 {
6087     return js_ThrowStopIteration(cx);
6088 }
6089
6090 /*
6091  * Get the owning thread id of a context. Returns 0 if the context is not
6092  * owned by any thread.
6093  */
6094 JS_PUBLIC_API(jsword)
6095 JS_GetContextThread(JSContext *cx)
6096 {
6097 #ifdef JS_THREADSAFE
6098     return reinterpret_cast<jsword>(JS_THREAD_ID(cx));
6099 #else
6100     return 0;
6101 #endif
6102 }
6103
6104 /*
6105  * Set the current thread as the owning thread of a context. Returns the
6106  * old owning thread id, or -1 if the operation failed.
6107  */
6108 JS_PUBLIC_API(jsword)
6109 JS_SetContextThread(JSContext *cx)
6110 {
6111 #ifdef JS_THREADSAFE
6112     JS_ASSERT(!cx->outstandingRequests);
6113     if (cx->thread) {
6114         JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
6115         return reinterpret_cast<jsword>(cx->thread->id);
6116     }
6117
6118     if (!js_InitContextThread(cx)) {
6119         js_ReportOutOfMemory(cx);
6120         return -1;
6121     }
6122
6123     /* Here the GC lock is still held after js_InitContextThread took it. */
6124     JS_UNLOCK_GC(cx->runtime);
6125 #endif
6126     return 0;
6127 }
6128
6129 JS_PUBLIC_API(jsword)
6130 JS_ClearContextThread(JSContext *cx)
6131 {
6132 #ifdef JS_THREADSAFE
6133     /*
6134      * cx must have exited all requests it entered and, if cx is associated
6135      * with a thread, this must be called only from that thread.  If not, this
6136      * is a harmless no-op.
6137      */
6138     JS_ASSERT(cx->outstandingRequests == 0);
6139     JSThread *t = cx->thread;
6140     if (!t)
6141         return 0;
6142     JS_ASSERT(CURRENT_THREAD_IS_ME(t));
6143
6144     /*
6145      * We must not race with a GC that accesses cx->thread for all threads,
6146      * see bug 476934.
6147      */
6148     JSRuntime *rt = cx->runtime;
6149     AutoLockGC lock(rt);
6150     js_WaitForGC(rt);
6151     js_ClearContextThread(cx);
6152     JS_ASSERT_IF(JS_CLIST_IS_EMPTY(&t->contextList), !t->data.requestDepth);
6153
6154     /*
6155      * We can access t->id as long as the GC lock is held and we cannot race
6156      * with the GC that may delete t.
6157      */
6158     return reinterpret_cast<jsword>(t->id);
6159 #else
6160     return 0;
6161 #endif
6162 }
6163
6164 #ifdef JS_GC_ZEAL
6165 JS_PUBLIC_API(void)
6166 JS_SetGCZeal(JSContext *cx, uint8 zeal)
6167 {
6168     cx->runtime->gcZeal = zeal;
6169 }
6170 #endif
6171
6172 /************************************************************************/
6173
6174 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN) && !defined (WINCE)
6175
6176 #include "jswin.h"
6177
6178 /*
6179  * Initialization routine for the JS DLL.
6180  */
6181 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
6182 {
6183     return TRUE;
6184 }
6185
6186 #endif