/[jscoverage]/trunk/js/jsapi.cpp
ViewVC logotype

Annotation of /trunk/js/jsapi.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 399 - (hide annotations)
Tue Dec 9 03:37:47 2008 UTC (10 years, 10 months ago) by siliconforks
File size: 170733 byte(s)
Use SpiderMonkey from Firefox 3.1b2.

1 siliconforks 332 /* -*- 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 "jsstddef.h"
45     #include <ctype.h>
46     #include <stdarg.h>
47     #include <stdlib.h>
48     #include <string.h>
49     #include "jstypes.h"
50     #include "jsarena.h" /* Added by JSIFY */
51     #include "jsutil.h" /* Added by JSIFY */
52     #include "jsclist.h"
53     #include "jsdhash.h"
54     #include "jsprf.h"
55     #include "jsapi.h"
56     #include "jsarray.h"
57     #include "jsatom.h"
58     #include "jsbool.h"
59 siliconforks 399 #include "jsbuiltins.h"
60 siliconforks 332 #include "jscntxt.h"
61     #include "jsversion.h"
62     #include "jsdate.h"
63     #include "jsdtoa.h"
64     #include "jsemit.h"
65     #include "jsexn.h"
66     #include "jsfun.h"
67     #include "jsgc.h"
68     #include "jsinterp.h"
69     #include "jsiter.h"
70     #include "jslock.h"
71     #include "jsmath.h"
72     #include "jsnum.h"
73     #include "json.h"
74     #include "jsobj.h"
75     #include "jsopcode.h"
76     #include "jsparse.h"
77     #include "jsregexp.h"
78     #include "jsscan.h"
79     #include "jsscope.h"
80     #include "jsscript.h"
81     #include "jsstr.h"
82     #include "prmjtime.h"
83     #include "jsstaticcheck.h"
84    
85     #if !defined JS_THREADSAFE && defined JS_TRACER
86     #include "jstracer.h"
87     #endif
88    
89     #if JS_HAS_FILE_OBJECT
90     #include "jsfile.h"
91     #endif
92    
93     #if JS_HAS_XML_SUPPORT
94     #include "jsxml.h"
95     #endif
96    
97     #ifdef HAVE_VA_LIST_AS_ARRAY
98     #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
99     #else
100     #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
101     #endif
102    
103     #if defined(JS_THREADSAFE)
104     #define CHECK_REQUEST(cx) \
105     JS_ASSERT((cx)->requestDepth || (cx)->thread == (cx)->runtime->gcThread)
106     #else
107     #define CHECK_REQUEST(cx) ((void)0)
108     #endif
109    
110     JS_PUBLIC_API(int64)
111     JS_Now()
112     {
113     return PRMJ_Now();
114     }
115    
116     JS_PUBLIC_API(jsval)
117     JS_GetNaNValue(JSContext *cx)
118     {
119     return DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
120     }
121    
122     JS_PUBLIC_API(jsval)
123     JS_GetNegativeInfinityValue(JSContext *cx)
124     {
125     return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
126     }
127    
128     JS_PUBLIC_API(jsval)
129     JS_GetPositiveInfinityValue(JSContext *cx)
130     {
131     return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
132     }
133    
134     JS_PUBLIC_API(jsval)
135     JS_GetEmptyStringValue(JSContext *cx)
136     {
137     return STRING_TO_JSVAL(cx->runtime->emptyString);
138     }
139    
140     static JSBool
141     TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS,
142     jsval **vpp, va_list *app)
143     {
144     const char *format;
145     JSArgumentFormatMap *map;
146    
147     format = *formatp;
148     for (map = cx->argumentFormatMap; map; map = map->next) {
149     if (!strncmp(format, map->format, map->length)) {
150     *formatp = format + map->length;
151     return map->formatter(cx, format, fromJS, vpp, app);
152     }
153     }
154     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
155     return JS_FALSE;
156     }
157    
158     JS_PUBLIC_API(JSBool)
159     JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
160     ...)
161     {
162     va_list ap;
163     JSBool ok;
164    
165     va_start(ap, format);
166     ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
167     va_end(ap);
168     return ok;
169     }
170    
171     JS_PUBLIC_API(JSBool)
172     JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
173     const char *format, va_list ap)
174     {
175     jsval *sp;
176     JSBool required;
177     char c;
178     JSFunction *fun;
179     jsdouble d;
180     JSString *str;
181     JSObject *obj;
182    
183     CHECK_REQUEST(cx);
184     sp = argv;
185     required = JS_TRUE;
186     while ((c = *format++) != '\0') {
187     if (isspace(c))
188     continue;
189     if (c == '/') {
190     required = JS_FALSE;
191     continue;
192     }
193     if (sp == argv + argc) {
194     if (required) {
195     fun = js_ValueToFunction(cx, &argv[-2], 0);
196     if (fun) {
197     char numBuf[12];
198     JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
199     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
200     JSMSG_MORE_ARGS_NEEDED,
201     JS_GetFunctionName(fun), numBuf,
202     (argc == 1) ? "" : "s");
203     }
204     return JS_FALSE;
205     }
206     break;
207     }
208     switch (c) {
209     case 'b':
210     *va_arg(ap, JSBool *) = js_ValueToBoolean(*sp);
211     break;
212     case 'c':
213     if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
214     return JS_FALSE;
215     break;
216     case 'i':
217     if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
218     return JS_FALSE;
219     break;
220     case 'u':
221     if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
222     return JS_FALSE;
223     break;
224     case 'j':
225     if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
226     return JS_FALSE;
227     break;
228     case 'd':
229     if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
230     return JS_FALSE;
231     break;
232     case 'I':
233     if (!JS_ValueToNumber(cx, *sp, &d))
234     return JS_FALSE;
235     *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
236     break;
237     case 's':
238     case 'S':
239     case 'W':
240     str = js_ValueToString(cx, *sp);
241     if (!str)
242     return JS_FALSE;
243     *sp = STRING_TO_JSVAL(str);
244     if (c == 's') {
245     const char *bytes = js_GetStringBytes(cx, str);
246     if (!bytes)
247     return JS_FALSE;
248     *va_arg(ap, const char **) = bytes;
249     } else if (c == 'W') {
250     const jschar *chars = js_GetStringChars(cx, str);
251     if (!chars)
252     return JS_FALSE;
253     *va_arg(ap, const jschar **) = chars;
254     } else {
255     *va_arg(ap, JSString **) = str;
256     }
257     break;
258     case 'o':
259     if (!js_ValueToObject(cx, *sp, &obj))
260     return JS_FALSE;
261     *sp = OBJECT_TO_JSVAL(obj);
262     *va_arg(ap, JSObject **) = obj;
263     break;
264     case 'f':
265     obj = js_ValueToFunctionObject(cx, sp, 0);
266     if (!obj)
267     return JS_FALSE;
268     *sp = OBJECT_TO_JSVAL(obj);
269     *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj);
270     break;
271     case 'v':
272     *va_arg(ap, jsval *) = *sp;
273     break;
274     case '*':
275     break;
276     default:
277     format--;
278     if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
279     JS_ADDRESSOF_VA_LIST(ap))) {
280     return JS_FALSE;
281     }
282     /* NB: the formatter already updated sp, so we continue here. */
283     continue;
284     }
285     sp++;
286     }
287     return JS_TRUE;
288     }
289    
290     JS_PUBLIC_API(jsval *)
291     JS_PushArguments(JSContext *cx, void **markp, const char *format, ...)
292     {
293     va_list ap;
294     jsval *argv;
295    
296     va_start(ap, format);
297     argv = JS_PushArgumentsVA(cx, markp, format, ap);
298     va_end(ap);
299     return argv;
300     }
301    
302     JS_PUBLIC_API(jsval *)
303     JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap)
304     {
305     uintN argc;
306     jsval *argv, *sp;
307     char c;
308     const char *cp;
309     JSString *str;
310     JSFunction *fun;
311     JSStackHeader *sh;
312    
313     CHECK_REQUEST(cx);
314     *markp = NULL;
315     argc = 0;
316     for (cp = format; (c = *cp) != '\0'; cp++) {
317     /*
318     * Count non-space non-star characters as individual jsval arguments.
319     * This may over-allocate stack, but we'll fix below.
320     */
321     if (isspace(c) || c == '*')
322     continue;
323     argc++;
324     }
325     sp = js_AllocStack(cx, argc, markp);
326     if (!sp)
327     return NULL;
328     argv = sp;
329     while ((c = *format++) != '\0') {
330     if (isspace(c) || c == '*')
331     continue;
332     switch (c) {
333     case 'b':
334     *sp = BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int));
335     break;
336     case 'c':
337     *sp = INT_TO_JSVAL((uint16) va_arg(ap, unsigned int));
338     break;
339     case 'i':
340     case 'j':
341     /*
342     * Use JS_New{Double,Number}Value here and in the next two cases,
343     * not js_New{Double,Number}InRootedValue, as sp may point to an
344     * unrooted location.
345     */
346     if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp))
347     goto bad;
348     break;
349     case 'u':
350     if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp))
351     goto bad;
352     break;
353     case 'd':
354     case 'I':
355     if (!JS_NewDoubleValue(cx, va_arg(ap, jsdouble), sp))
356     goto bad;
357     break;
358     case 's':
359     str = JS_NewStringCopyZ(cx, va_arg(ap, char *));
360     if (!str)
361     goto bad;
362     *sp = STRING_TO_JSVAL(str);
363     break;
364     case 'W':
365     str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *));
366     if (!str)
367     goto bad;
368     *sp = STRING_TO_JSVAL(str);
369     break;
370     case 'S':
371     str = va_arg(ap, JSString *);
372     *sp = STRING_TO_JSVAL(str);
373     break;
374     case 'o':
375     *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *));
376     break;
377     case 'f':
378     fun = va_arg(ap, JSFunction *);
379     *sp = fun ? OBJECT_TO_JSVAL(FUN_OBJECT(fun)) : JSVAL_NULL;
380     break;
381     case 'v':
382     *sp = va_arg(ap, jsval);
383     break;
384     default:
385     format--;
386     if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp,
387     JS_ADDRESSOF_VA_LIST(ap))) {
388     goto bad;
389     }
390     /* NB: the formatter already updated sp, so we continue here. */
391     continue;
392     }
393     sp++;
394     }
395    
396     /*
397     * We may have overallocated stack due to a multi-character format code
398     * handled by a JSArgumentFormatter. Give back that stack space!
399     */
400     JS_ASSERT(sp <= argv + argc);
401     if (sp < argv + argc) {
402     /* Return slots not pushed to the current stack arena. */
403     cx->stackPool.current->avail = (jsuword)sp;
404    
405     /* Reduce the count of slots the GC will scan in this stack segment. */
406     sh = cx->stackHeaders;
407     JS_ASSERT(JS_STACK_SEGMENT(sh) + sh->nslots == argv + argc);
408     sh->nslots -= argc - (sp - argv);
409     }
410     return argv;
411    
412     bad:
413     js_FreeStack(cx, *markp);
414     return NULL;
415     }
416    
417     JS_PUBLIC_API(void)
418     JS_PopArguments(JSContext *cx, void *mark)
419     {
420     CHECK_REQUEST(cx);
421     js_FreeStack(cx, mark);
422     }
423    
424     JS_PUBLIC_API(JSBool)
425     JS_AddArgumentFormatter(JSContext *cx, const char *format,
426     JSArgumentFormatter formatter)
427     {
428     size_t length;
429     JSArgumentFormatMap **mpp, *map;
430    
431     length = strlen(format);
432     mpp = &cx->argumentFormatMap;
433     while ((map = *mpp) != NULL) {
434     /* Insert before any shorter string to match before prefixes. */
435     if (map->length < length)
436     break;
437     if (map->length == length && !strcmp(map->format, format))
438     goto out;
439     mpp = &map->next;
440     }
441     map = (JSArgumentFormatMap *) JS_malloc(cx, sizeof *map);
442     if (!map)
443     return JS_FALSE;
444     map->format = format;
445     map->length = length;
446     map->next = *mpp;
447     *mpp = map;
448     out:
449     map->formatter = formatter;
450     return JS_TRUE;
451     }
452    
453     JS_PUBLIC_API(void)
454     JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
455     {
456     size_t length;
457     JSArgumentFormatMap **mpp, *map;
458    
459     length = strlen(format);
460     mpp = &cx->argumentFormatMap;
461     while ((map = *mpp) != NULL) {
462     if (map->length == length && !strcmp(map->format, format)) {
463     *mpp = map->next;
464     JS_free(cx, map);
465     return;
466     }
467     mpp = &map->next;
468     }
469     }
470    
471     JS_PUBLIC_API(JSBool)
472     JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
473     {
474     JSBool ok;
475     JSObject *obj;
476     JSString *str;
477     jsdouble d, *dp;
478    
479     CHECK_REQUEST(cx);
480     switch (type) {
481     case JSTYPE_VOID:
482     *vp = JSVAL_VOID;
483     ok = JS_TRUE;
484     break;
485     case JSTYPE_OBJECT:
486     ok = js_ValueToObject(cx, v, &obj);
487     if (ok)
488     *vp = OBJECT_TO_JSVAL(obj);
489     break;
490     case JSTYPE_FUNCTION:
491     *vp = v;
492     obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK);
493     ok = (obj != NULL);
494     break;
495     case JSTYPE_STRING:
496     str = js_ValueToString(cx, v);
497     ok = (str != NULL);
498     if (ok)
499     *vp = STRING_TO_JSVAL(str);
500     break;
501     case JSTYPE_NUMBER:
502     ok = JS_ValueToNumber(cx, v, &d);
503     if (ok) {
504     dp = js_NewWeaklyRootedDouble(cx, d);
505     ok = (dp != NULL);
506     if (ok)
507     *vp = DOUBLE_TO_JSVAL(dp);
508     }
509     break;
510     case JSTYPE_BOOLEAN:
511     *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(v));
512     return JS_TRUE;
513     default: {
514     char numBuf[12];
515     JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
516     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
517     numBuf);
518     ok = JS_FALSE;
519     break;
520     }
521     }
522     return ok;
523     }
524    
525     JS_PUBLIC_API(JSBool)
526     JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
527     {
528     CHECK_REQUEST(cx);
529     return js_ValueToObject(cx, v, objp);
530     }
531    
532     JS_PUBLIC_API(JSFunction *)
533     JS_ValueToFunction(JSContext *cx, jsval v)
534     {
535     CHECK_REQUEST(cx);
536     return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
537     }
538    
539     JS_PUBLIC_API(JSFunction *)
540     JS_ValueToConstructor(JSContext *cx, jsval v)
541     {
542     CHECK_REQUEST(cx);
543     return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
544     }
545    
546     JS_PUBLIC_API(JSString *)
547     JS_ValueToString(JSContext *cx, jsval v)
548     {
549     CHECK_REQUEST(cx);
550     return js_ValueToString(cx, v);
551     }
552    
553 siliconforks 399 JS_PUBLIC_API(JSString *)
554     JS_ValueToSource(JSContext *cx, jsval v)
555     {
556     CHECK_REQUEST(cx);
557     return js_ValueToSource(cx, v);
558     }
559    
560 siliconforks 332 JS_PUBLIC_API(JSBool)
561     JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
562     {
563     JSTempValueRooter tvr;
564    
565     CHECK_REQUEST(cx);
566     JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
567     *dp = js_ValueToNumber(cx, &tvr.u.value);
568     JS_POP_TEMP_ROOT(cx, &tvr);
569     return !JSVAL_IS_NULL(tvr.u.value);
570     }
571    
572     JS_PUBLIC_API(JSBool)
573     JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
574     {
575     JSTempValueRooter tvr;
576    
577     CHECK_REQUEST(cx);
578     JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
579     *ip = js_ValueToECMAInt32(cx, &tvr.u.value);
580     JS_POP_TEMP_ROOT(cx, &tvr);
581     return !JSVAL_IS_NULL(tvr.u.value);
582     }
583    
584     JS_PUBLIC_API(JSBool)
585     JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
586     {
587     JSTempValueRooter tvr;
588    
589     CHECK_REQUEST(cx);
590     JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
591     *ip = js_ValueToECMAUint32(cx, &tvr.u.value);
592     JS_POP_TEMP_ROOT(cx, &tvr);
593     return !JSVAL_IS_NULL(tvr.u.value);
594     }
595    
596     JS_PUBLIC_API(JSBool)
597     JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
598     {
599     JSTempValueRooter tvr;
600    
601     CHECK_REQUEST(cx);
602     JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
603     *ip = js_ValueToInt32(cx, &tvr.u.value);
604     JS_POP_TEMP_ROOT(cx, &tvr);
605     return !JSVAL_IS_NULL(tvr.u.value);
606     }
607    
608     JS_PUBLIC_API(JSBool)
609     JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
610     {
611     JSTempValueRooter tvr;
612    
613     CHECK_REQUEST(cx);
614     JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
615     *ip = js_ValueToUint16(cx, &tvr.u.value);
616     JS_POP_TEMP_ROOT(cx, &tvr);
617     return !JSVAL_IS_NULL(tvr.u.value);
618     }
619    
620     JS_PUBLIC_API(JSBool)
621     JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
622     {
623     CHECK_REQUEST(cx);
624     *bp = js_ValueToBoolean(v);
625     return JS_TRUE;
626     }
627    
628     JS_PUBLIC_API(JSType)
629     JS_TypeOfValue(JSContext *cx, jsval v)
630     {
631     JSType type;
632     JSObject *obj;
633     JSObjectOps *ops;
634     JSClass *clasp;
635    
636     CHECK_REQUEST(cx);
637     if (JSVAL_IS_OBJECT(v)) {
638     type = JSTYPE_OBJECT; /* XXXbe JSTYPE_NULL for JS2 */
639     obj = JSVAL_TO_OBJECT(v);
640     if (obj) {
641     JSObject *wrapped;
642    
643     wrapped = js_GetWrappedObject(cx, obj);
644     if (wrapped)
645     obj = wrapped;
646    
647     ops = obj->map->ops;
648     #if JS_HAS_XML_SUPPORT
649     if (ops == &js_XMLObjectOps.base) {
650     type = JSTYPE_XML;
651     } else
652     #endif
653     {
654     /*
655     * ECMA 262, 11.4.3 says that any native object that implements
656     * [[Call]] should be of type "function". Note that RegExp and
657     * Script are both of type "function" for compatibility with
658     * older SpiderMonkeys.
659     */
660     clasp = OBJ_GET_CLASS(cx, obj);
661     if ((ops == &js_ObjectOps)
662     ? (clasp->call
663     ? clasp == &js_ScriptClass
664     : clasp == &js_FunctionClass)
665     : ops->call != NULL) {
666     type = JSTYPE_FUNCTION;
667     } else {
668     #ifdef NARCISSUS
669     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
670    
671     if (!OBJ_GET_PROPERTY(cx, obj,
672     ATOM_TO_JSID(cx->runtime->atomState
673 siliconforks 399 .__call__Atom),
674 siliconforks 332 &v)) {
675     JS_ClearPendingException(cx);
676     } else if (VALUE_IS_FUNCTION(cx, v)) {
677     type = JSTYPE_FUNCTION;
678     }
679     #endif
680     }
681     }
682     }
683     } else if (JSVAL_IS_NUMBER(v)) {
684     type = JSTYPE_NUMBER;
685     } else if (JSVAL_IS_STRING(v)) {
686     type = JSTYPE_STRING;
687     } else if (JSVAL_IS_BOOLEAN(v)) {
688     type = JSTYPE_BOOLEAN;
689     } else {
690     type = JSTYPE_VOID;
691     }
692     return type;
693     }
694    
695     JS_PUBLIC_API(const char *)
696     JS_GetTypeName(JSContext *cx, JSType type)
697     {
698     if ((uintN)type >= (uintN)JSTYPE_LIMIT)
699     return NULL;
700     return JS_TYPE_STR(type);
701     }
702    
703     /************************************************************************/
704    
705     /*
706     * Has a new runtime ever been created? This flag is used to detect unsafe
707     * changes to js_CStringsAreUTF8 after a runtime has been created, and to
708     * ensure that "first checks" on runtime creation are run only once.
709     */
710     #ifdef DEBUG
711     static JSBool js_NewRuntimeWasCalled = JS_FALSE;
712     #endif
713    
714     JS_PUBLIC_API(JSRuntime *)
715     JS_NewRuntime(uint32 maxbytes)
716     {
717     JSRuntime *rt;
718    
719     #ifdef DEBUG
720     if (!js_NewRuntimeWasCalled) {
721     /*
722     * This code asserts that the numbers associated with the error names
723     * in jsmsg.def are monotonically increasing. It uses values for the
724     * error names enumerated in jscntxt.c. It's not a compile-time check
725     * but it's better than nothing.
726     */
727     int errorNumber = 0;
728     #define MSG_DEF(name, number, count, exception, format) \
729     JS_ASSERT(name == errorNumber++);
730     #include "js.msg"
731     #undef MSG_DEF
732    
733     #define MSG_DEF(name, number, count, exception, format) \
734     JS_BEGIN_MACRO \
735     uintN numfmtspecs = 0; \
736     const char *fmt; \
737     for (fmt = format; *fmt != '\0'; fmt++) { \
738     if (*fmt == '{' && isdigit(fmt[1])) \
739     ++numfmtspecs; \
740     } \
741     JS_ASSERT(count == numfmtspecs); \
742     JS_END_MACRO;
743     #include "js.msg"
744     #undef MSG_DEF
745    
746     js_NewRuntimeWasCalled = JS_TRUE;
747     }
748     #endif /* DEBUG */
749    
750     rt = (JSRuntime *) malloc(sizeof(JSRuntime));
751     if (!rt)
752     return NULL;
753    
754     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
755     memset(rt, 0, sizeof(JSRuntime));
756     JS_INIT_CLIST(&rt->contextList);
757     JS_INIT_CLIST(&rt->trapList);
758     JS_INIT_CLIST(&rt->watchPointList);
759    
760     if (!js_InitDtoa())
761     goto bad;
762     if (!js_InitGC(rt, maxbytes))
763     goto bad;
764     if (!js_InitAtomState(rt))
765     goto bad;
766     if (!js_InitDeflatedStringCache(rt))
767     goto bad;
768     #ifdef JS_THREADSAFE
769     if (!js_InitThreadPrivateIndex(js_ThreadDestructorCB))
770     goto bad;
771     rt->gcLock = JS_NEW_LOCK();
772     if (!rt->gcLock)
773     goto bad;
774     rt->gcDone = JS_NEW_CONDVAR(rt->gcLock);
775     if (!rt->gcDone)
776     goto bad;
777     rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
778     if (!rt->requestDone)
779     goto bad;
780     /* this is asymmetric with JS_ShutDown: */
781     if (!js_SetupLocks(8, 16))
782     goto bad;
783     rt->rtLock = JS_NEW_LOCK();
784     if (!rt->rtLock)
785     goto bad;
786     rt->stateChange = JS_NEW_CONDVAR(rt->gcLock);
787     if (!rt->stateChange)
788     goto bad;
789     rt->titleSharingDone = JS_NEW_CONDVAR(rt->gcLock);
790     if (!rt->titleSharingDone)
791     goto bad;
792     rt->titleSharingTodo = NO_TITLE_SHARING_TODO;
793     rt->debuggerLock = JS_NEW_LOCK();
794     if (!rt->debuggerLock)
795     goto bad;
796     #endif
797     if (!js_InitPropertyTree(rt))
798     goto bad;
799    
800     #if !defined JS_THREADSAFE && defined JS_TRACER
801     js_InitJIT(&rt->traceMonitor);
802     #endif
803    
804     return rt;
805    
806     bad:
807     JS_DestroyRuntime(rt);
808     return NULL;
809     }
810    
811     JS_PUBLIC_API(void)
812     JS_DestroyRuntime(JSRuntime *rt)
813     {
814     #ifdef DEBUG
815     /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
816     if (!JS_CLIST_IS_EMPTY(&rt->contextList)) {
817     JSContext *cx, *iter = NULL;
818     uintN cxcount = 0;
819     while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL) {
820     fprintf(stderr,
821     "JS API usage error: found live context at %p\n",
822     cx);
823     cxcount++;
824     }
825     fprintf(stderr,
826     "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
827     cxcount, (cxcount == 1) ? "" : "s");
828     }
829     #endif
830    
831     #if !defined JS_THREADSAFE && defined JS_TRACER
832     js_FinishJIT(&rt->traceMonitor);
833     #endif
834    
835     js_FreeRuntimeScriptState(rt);
836     js_FinishAtomState(rt);
837    
838     /*
839     * Free unit string storage only after all strings have been finalized, so
840     * that js_FinalizeString can detect unit strings and avoid calling free
841     * on their chars storage.
842     */
843     js_FinishUnitStrings(rt);
844    
845     /*
846     * Finish the deflated string cache after the last GC and after
847     * calling js_FinishAtomState, which finalizes strings.
848     */
849     js_FinishDeflatedStringCache(rt);
850     js_FinishGC(rt);
851     #ifdef JS_THREADSAFE
852     if (rt->gcLock)
853     JS_DESTROY_LOCK(rt->gcLock);
854     if (rt->gcDone)
855     JS_DESTROY_CONDVAR(rt->gcDone);
856     if (rt->requestDone)
857     JS_DESTROY_CONDVAR(rt->requestDone);
858     if (rt->rtLock)
859     JS_DESTROY_LOCK(rt->rtLock);
860     if (rt->stateChange)
861     JS_DESTROY_CONDVAR(rt->stateChange);
862     if (rt->titleSharingDone)
863     JS_DESTROY_CONDVAR(rt->titleSharingDone);
864     if (rt->debuggerLock)
865     JS_DESTROY_LOCK(rt->debuggerLock);
866     #else
867     GSN_CACHE_CLEAR(&rt->gsnCache);
868     #endif
869     js_FinishPropertyTree(rt);
870     free(rt);
871     }
872    
873     JS_PUBLIC_API(void)
874     JS_ShutDown(void)
875     {
876     #ifdef JS_OPMETER
877     extern void js_DumpOpMeters();
878    
879     js_DumpOpMeters();
880     #endif
881    
882     js_FinishDtoa();
883     #ifdef JS_THREADSAFE
884     js_CleanupLocks();
885     #endif
886     PRMJ_NowShutdown();
887     }
888    
889     JS_PUBLIC_API(void *)
890     JS_GetRuntimePrivate(JSRuntime *rt)
891     {
892     return rt->data;
893     }
894    
895     JS_PUBLIC_API(void)
896     JS_SetRuntimePrivate(JSRuntime *rt, void *data)
897     {
898     rt->data = data;
899     }
900    
901     JS_PUBLIC_API(void)
902     JS_BeginRequest(JSContext *cx)
903     {
904     #ifdef JS_THREADSAFE
905     JSRuntime *rt;
906    
907     JS_ASSERT(cx->thread->id == js_CurrentThreadId());
908     if (!cx->requestDepth) {
909     JS_ASSERT(cx->gcLocalFreeLists == &js_GCEmptyFreeListSet);
910    
911     /* Wait until the GC is finished. */
912     rt = cx->runtime;
913     JS_LOCK_GC(rt);
914    
915     /* NB: we use cx->thread here, not js_GetCurrentThread(). */
916     if (rt->gcThread != cx->thread) {
917     while (rt->gcLevel > 0)
918     JS_AWAIT_GC_DONE(rt);
919     }
920    
921     /* Indicate that a request is running. */
922     rt->requestCount++;
923     cx->requestDepth = 1;
924     cx->outstandingRequests++;
925     JS_UNLOCK_GC(rt);
926     return;
927     }
928     cx->requestDepth++;
929     cx->outstandingRequests++;
930     #endif
931     }
932    
933     JS_PUBLIC_API(void)
934     JS_EndRequest(JSContext *cx)
935     {
936     #ifdef JS_THREADSAFE
937     JSRuntime *rt;
938     JSTitle *title, **todop;
939     JSBool shared;
940    
941     CHECK_REQUEST(cx);
942     JS_ASSERT(cx->requestDepth > 0);
943     JS_ASSERT(cx->outstandingRequests > 0);
944     if (cx->requestDepth == 1) {
945     /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
946     rt = cx->runtime;
947     JS_LOCK_GC(rt);
948     cx->requestDepth = 0;
949     cx->outstandingRequests--;
950    
951     /* See whether cx has any single-threaded titles to start sharing. */
952     todop = &rt->titleSharingTodo;
953     shared = JS_FALSE;
954     while ((title = *todop) != NO_TITLE_SHARING_TODO) {
955     if (title->ownercx != cx) {
956     todop = &title->u.link;
957     continue;
958     }
959     *todop = title->u.link;
960     title->u.link = NULL; /* null u.link for sanity ASAP */
961    
962     /*
963     * If js_DropObjectMap returns null, we held the last ref to scope.
964     * The waiting thread(s) must have been killed, after which the GC
965     * collected the object that held this scope. Unlikely, because it
966     * requires that the GC ran (e.g., from an operation callback)
967     * during this request, but possible.
968     */
969     if (js_DropObjectMap(cx, TITLE_TO_MAP(title), NULL)) {
970     js_InitLock(&title->lock);
971     title->u.count = 0; /* NULL may not pun as 0 */
972     js_FinishSharingTitle(cx, title); /* set ownercx = NULL */
973     shared = JS_TRUE;
974     }
975     }
976     if (shared)
977     JS_NOTIFY_ALL_CONDVAR(rt->titleSharingDone);
978    
979     js_RevokeGCLocalFreeLists(cx);
980    
981     /* Give the GC a chance to run if this was the last request running. */
982     JS_ASSERT(rt->requestCount > 0);
983     rt->requestCount--;
984     if (rt->requestCount == 0)
985     JS_NOTIFY_REQUEST_DONE(rt);
986    
987     JS_UNLOCK_GC(rt);
988     return;
989     }
990    
991     cx->requestDepth--;
992     cx->outstandingRequests--;
993     #endif
994     }
995    
996     /* Yield to pending GC operations, regardless of request depth */
997     JS_PUBLIC_API(void)
998     JS_YieldRequest(JSContext *cx)
999     {
1000     #ifdef JS_THREADSAFE
1001     JS_ASSERT(cx->thread);
1002     CHECK_REQUEST(cx);
1003     JS_ResumeRequest(cx, JS_SuspendRequest(cx));
1004     #endif
1005     }
1006    
1007     JS_PUBLIC_API(jsrefcount)
1008     JS_SuspendRequest(JSContext *cx)
1009     {
1010     #ifdef JS_THREADSAFE
1011     jsrefcount saveDepth = cx->requestDepth;
1012    
1013     while (cx->requestDepth) {
1014     cx->outstandingRequests++; /* compensate for JS_EndRequest */
1015     JS_EndRequest(cx);
1016     }
1017     return saveDepth;
1018     #else
1019     return 0;
1020     #endif
1021     }
1022    
1023     JS_PUBLIC_API(void)
1024     JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
1025     {
1026     #ifdef JS_THREADSAFE
1027     JS_ASSERT(!cx->requestDepth);
1028     while (--saveDepth >= 0) {
1029     JS_BeginRequest(cx);
1030     cx->outstandingRequests--; /* compensate for JS_BeginRequest */
1031     }
1032     #endif
1033     }
1034    
1035     JS_PUBLIC_API(void)
1036     JS_Lock(JSRuntime *rt)
1037     {
1038     JS_LOCK_RUNTIME(rt);
1039     }
1040    
1041     JS_PUBLIC_API(void)
1042     JS_Unlock(JSRuntime *rt)
1043     {
1044     JS_UNLOCK_RUNTIME(rt);
1045     }
1046    
1047     JS_PUBLIC_API(JSContextCallback)
1048     JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
1049     {
1050     JSContextCallback old;
1051    
1052     old = rt->cxCallback;
1053     rt->cxCallback = cxCallback;
1054     return old;
1055     }
1056    
1057     JS_PUBLIC_API(JSContext *)
1058     JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
1059     {
1060     return js_NewContext(rt, stackChunkSize);
1061     }
1062    
1063     JS_PUBLIC_API(void)
1064     JS_DestroyContext(JSContext *cx)
1065     {
1066     js_DestroyContext(cx, JSDCM_FORCE_GC);
1067     }
1068    
1069     JS_PUBLIC_API(void)
1070     JS_DestroyContextNoGC(JSContext *cx)
1071     {
1072     js_DestroyContext(cx, JSDCM_NO_GC);
1073     }
1074    
1075     JS_PUBLIC_API(void)
1076     JS_DestroyContextMaybeGC(JSContext *cx)
1077     {
1078     js_DestroyContext(cx, JSDCM_MAYBE_GC);
1079     }
1080    
1081     JS_PUBLIC_API(void *)
1082     JS_GetContextPrivate(JSContext *cx)
1083     {
1084     return cx->data;
1085     }
1086    
1087     JS_PUBLIC_API(void)
1088     JS_SetContextPrivate(JSContext *cx, void *data)
1089     {
1090     cx->data = data;
1091     }
1092    
1093     JS_PUBLIC_API(JSRuntime *)
1094     JS_GetRuntime(JSContext *cx)
1095     {
1096     return cx->runtime;
1097     }
1098    
1099     JS_PUBLIC_API(JSContext *)
1100     JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
1101     {
1102     return js_ContextIterator(rt, JS_TRUE, iterp);
1103     }
1104    
1105     JS_PUBLIC_API(JSVersion)
1106     JS_GetVersion(JSContext *cx)
1107     {
1108     return JSVERSION_NUMBER(cx);
1109     }
1110    
1111     JS_PUBLIC_API(JSVersion)
1112     JS_SetVersion(JSContext *cx, JSVersion version)
1113     {
1114     JSVersion oldVersion;
1115    
1116     JS_ASSERT(version != JSVERSION_UNKNOWN);
1117     JS_ASSERT((version & ~JSVERSION_MASK) == 0);
1118    
1119     oldVersion = JSVERSION_NUMBER(cx);
1120     if (version == oldVersion)
1121     return oldVersion;
1122    
1123     /* We no longer support 1.4 or below. */
1124     if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4)
1125     return oldVersion;
1126    
1127     cx->version = (cx->version & ~JSVERSION_MASK) | version;
1128     js_OnVersionChange(cx);
1129     return oldVersion;
1130     }
1131    
1132     static struct v2smap {
1133     JSVersion version;
1134     const char *string;
1135     } v2smap[] = {
1136     {JSVERSION_1_0, "1.0"},
1137     {JSVERSION_1_1, "1.1"},
1138     {JSVERSION_1_2, "1.2"},
1139     {JSVERSION_1_3, "1.3"},
1140     {JSVERSION_1_4, "1.4"},
1141     {JSVERSION_ECMA_3, "ECMAv3"},
1142     {JSVERSION_1_5, "1.5"},
1143     {JSVERSION_1_6, "1.6"},
1144     {JSVERSION_1_7, "1.7"},
1145     {JSVERSION_1_8, "1.8"},
1146     {JSVERSION_DEFAULT, js_default_str},
1147     {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
1148     };
1149    
1150     JS_PUBLIC_API(const char *)
1151     JS_VersionToString(JSVersion version)
1152     {
1153     int i;
1154    
1155     for (i = 0; v2smap[i].string; i++)
1156     if (v2smap[i].version == version)
1157     return v2smap[i].string;
1158     return "unknown";
1159     }
1160    
1161     JS_PUBLIC_API(JSVersion)
1162     JS_StringToVersion(const char *string)
1163     {
1164     int i;
1165    
1166     for (i = 0; v2smap[i].string; i++)
1167     if (strcmp(v2smap[i].string, string) == 0)
1168     return v2smap[i].version;
1169     return JSVERSION_UNKNOWN;
1170     }
1171    
1172     JS_PUBLIC_API(uint32)
1173     JS_GetOptions(JSContext *cx)
1174     {
1175     return cx->options;
1176     }
1177    
1178     #define SYNC_OPTIONS_TO_VERSION(cx) \
1179     JS_BEGIN_MACRO \
1180     if ((cx)->options & JSOPTION_XML) \
1181     (cx)->version |= JSVERSION_HAS_XML; \
1182     else \
1183     (cx)->version &= ~JSVERSION_HAS_XML; \
1184     JS_END_MACRO
1185    
1186     JS_PUBLIC_API(uint32)
1187     JS_SetOptions(JSContext *cx, uint32 options)
1188     {
1189     uint32 oldopts = cx->options;
1190     cx->options = options;
1191     SYNC_OPTIONS_TO_VERSION(cx);
1192     return oldopts;
1193     }
1194    
1195     JS_PUBLIC_API(uint32)
1196     JS_ToggleOptions(JSContext *cx, uint32 options)
1197     {
1198     uint32 oldopts = cx->options;
1199     cx->options ^= options;
1200     SYNC_OPTIONS_TO_VERSION(cx);
1201     return oldopts;
1202     }
1203    
1204     JS_PUBLIC_API(const char *)
1205     JS_GetImplementationVersion(void)
1206     {
1207     return "JavaScript-C 1.8.0 pre-release 1 2007-10-03";
1208     }
1209    
1210    
1211     JS_PUBLIC_API(JSObject *)
1212     JS_GetGlobalObject(JSContext *cx)
1213     {
1214     return cx->globalObject;
1215     }
1216    
1217     JS_PUBLIC_API(void)
1218     JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1219     {
1220     cx->globalObject = obj;
1221    
1222     #if JS_HAS_XML_SUPPORT
1223     cx->xmlSettingFlags = 0;
1224     #endif
1225     }
1226    
1227     JS_BEGIN_EXTERN_C
1228    
1229     JSObject *
1230     js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1231     {
1232     JSDHashTable *table;
1233     JSBool resolving;
1234     JSRuntime *rt;
1235     JSResolvingKey key;
1236     JSResolvingEntry *entry;
1237     JSObject *fun_proto, *obj_proto;
1238    
1239     /* If cx has no global object, use obj so prototypes can be found. */
1240     if (!cx->globalObject)
1241     JS_SetGlobalObject(cx, obj);
1242    
1243     /* Record Function and Object in cx->resolvingTable, if we are resolving. */
1244     table = cx->resolvingTable;
1245     resolving = (table && table->entryCount);
1246     rt = cx->runtime;
1247     key.obj = obj;
1248     if (resolving) {
1249     key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]);
1250     entry = (JSResolvingEntry *)
1251     JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1252     if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) {
1253     /* Already resolving Function, record Object too. */
1254     JS_ASSERT(entry->key.obj == obj);
1255     key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1256     entry = (JSResolvingEntry *)
1257     JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1258     }
1259     if (!entry) {
1260     JS_ReportOutOfMemory(cx);
1261     return NULL;
1262     }
1263     JS_ASSERT(!entry->key.obj && entry->flags == 0);
1264     entry->key = key;
1265     entry->flags = JSRESFLAG_LOOKUP;
1266     } else {
1267     key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1268     if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry))
1269     return NULL;
1270    
1271     key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]);
1272     if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) {
1273     key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1274     JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1275     return NULL;
1276     }
1277    
1278     table = cx->resolvingTable;
1279     }
1280    
1281     /* Initialize the function class first so constructors can be made. */
1282     if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Function),
1283     &fun_proto)) {
1284     fun_proto = NULL;
1285     goto out;
1286     }
1287     if (!fun_proto) {
1288     fun_proto = js_InitFunctionClass(cx, obj);
1289     if (!fun_proto)
1290     goto out;
1291     } else {
1292     JSObject *ctor;
1293    
1294     ctor = JS_GetConstructor(cx, fun_proto);
1295     if (!ctor) {
1296     fun_proto = NULL;
1297     goto out;
1298     }
1299     OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
1300     OBJECT_TO_JSVAL(ctor), 0, 0, 0, NULL);
1301     }
1302    
1303     /* Initialize the object class next so Object.prototype works. */
1304     if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object),
1305     &obj_proto)) {
1306     fun_proto = NULL;
1307     goto out;
1308     }
1309     if (!obj_proto)
1310     obj_proto = js_InitObjectClass(cx, obj);
1311     if (!obj_proto) {
1312     fun_proto = NULL;
1313     goto out;
1314     }
1315    
1316     /* Function.prototype and the global object delegate to Object.prototype. */
1317     OBJ_SET_PROTO(cx, fun_proto, obj_proto);
1318     if (!OBJ_GET_PROTO(cx, obj))
1319     OBJ_SET_PROTO(cx, obj, obj_proto);
1320    
1321     out:
1322     /* If resolving, remove the other entry (Object or Function) from table. */
1323     JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1324     if (!resolving) {
1325     /* If not resolving, remove the first entry added above, for Object. */
1326     JS_ASSERT(key.id == \
1327     ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]));
1328     key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1329     JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1330     }
1331     return fun_proto;
1332     }
1333    
1334     JS_END_EXTERN_C
1335    
1336     JS_PUBLIC_API(JSBool)
1337     JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1338     {
1339     JSAtom *atom;
1340    
1341     CHECK_REQUEST(cx);
1342    
1343     /* Define a top-level property 'undefined' with the undefined value. */
1344     atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1345     if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1346     NULL, NULL, JSPROP_PERMANENT, NULL)) {
1347     return JS_FALSE;
1348     }
1349    
1350     /* Function and Object require cooperative bootstrapping magic. */
1351     if (!js_InitFunctionAndObjectClasses(cx, obj))
1352     return JS_FALSE;
1353    
1354     /* Initialize the rest of the standard objects and functions. */
1355     return js_InitArrayClass(cx, obj) &&
1356     js_InitBlockClass(cx, obj) &&
1357     js_InitBooleanClass(cx, obj) &&
1358     js_InitCallClass(cx, obj) &&
1359     js_InitExceptionClasses(cx, obj) &&
1360     js_InitMathClass(cx, obj) &&
1361     js_InitNumberClass(cx, obj) &&
1362     js_InitJSONClass(cx, obj) &&
1363     js_InitRegExpClass(cx, obj) &&
1364     js_InitStringClass(cx, obj) &&
1365     js_InitEval(cx, obj) &&
1366     #if JS_HAS_SCRIPT_OBJECT
1367     js_InitScriptClass(cx, obj) &&
1368     #endif
1369     #if JS_HAS_XML_SUPPORT
1370     js_InitXMLClasses(cx, obj) &&
1371     #endif
1372     #if JS_HAS_FILE_OBJECT
1373     js_InitFileClass(cx, obj) &&
1374     #endif
1375     #if JS_HAS_GENERATORS
1376     js_InitIteratorClasses(cx, obj) &&
1377     #endif
1378     js_InitDateClass(cx, obj);
1379     }
1380    
1381     #define CLASP(name) (&js_##name##Class)
1382     #define EXT_CLASP(name) (&js_##name##Class.base)
1383     #define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
1384     #define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
1385     #define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
1386     #define EAGER_ATOM_AND_EXT_CLASP(name) EAGER_CLASS_ATOM(name), EXT_CLASP(name)
1387     #define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
1388    
1389     typedef struct JSStdName {
1390     JSObjectOp init;
1391     size_t atomOffset; /* offset of atom pointer in JSAtomState */
1392     const char *name; /* null if atom is pre-pinned, else name */
1393     JSClass *clasp;
1394     } JSStdName;
1395    
1396     static JSAtom *
1397     StdNameToAtom(JSContext *cx, JSStdName *stdn)
1398     {
1399     size_t offset;
1400     JSAtom *atom;
1401     const char *name;
1402    
1403     offset = stdn->atomOffset;
1404     atom = OFFSET_TO_ATOM(cx->runtime, offset);
1405     if (!atom) {
1406     name = stdn->name;
1407     if (name) {
1408     atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1409     OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1410     }
1411     }
1412     return atom;
1413     }
1414    
1415     /*
1416     * Table of class initializers and their atom offsets in rt->atomState.
1417     * If you add a "standard" class, remember to update this table.
1418     */
1419     static JSStdName standard_class_atoms[] = {
1420     {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Function)},
1421     {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Object)},
1422     {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)},
1423     {js_InitBlockClass, EAGER_ATOM_AND_CLASP(Block)},
1424     {js_InitBooleanClass, EAGER_ATOM_AND_CLASP(Boolean)},
1425     {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)},
1426     {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)},
1427     {js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)},
1428     {js_InitStringClass, EAGER_ATOM_AND_CLASP(String)},
1429     {js_InitCallClass, EAGER_ATOM_AND_CLASP(Call)},
1430     {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)},
1431     {js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)},
1432     #if JS_HAS_SCRIPT_OBJECT
1433     {js_InitScriptClass, EAGER_ATOM_AND_CLASP(Script)},
1434     #endif
1435     #if JS_HAS_XML_SUPPORT
1436     {js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)},
1437     {js_InitNamespaceClass, EAGER_ATOM_AND_EXT_CLASP(Namespace)},
1438     {js_InitQNameClass, EAGER_ATOM_AND_EXT_CLASP(QName)},
1439     #endif
1440     #if JS_HAS_FILE_OBJECT
1441     {js_InitFileClass, EAGER_ATOM_AND_CLASP(File)},
1442     #endif
1443     #if JS_HAS_GENERATORS
1444     {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
1445     #endif
1446     {js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
1447     {NULL, 0, NULL, NULL}
1448     };
1449    
1450     /*
1451     * Table of top-level function and constant names and their init functions.
1452     * If you add a "standard" global function or property, remember to update
1453     * this table.
1454     */
1455     static JSStdName standard_class_names[] = {
1456     /* ECMA requires that eval be a direct property of the global object. */
1457     {js_InitEval, EAGER_ATOM(eval), NULL},
1458    
1459     /* Global properties and functions defined by the Number class. */
1460     {js_InitNumberClass, LAZY_ATOM(NaN), NULL},
1461     {js_InitNumberClass, LAZY_ATOM(Infinity), NULL},
1462     {js_InitNumberClass, LAZY_ATOM(isNaN), NULL},
1463     {js_InitNumberClass, LAZY_ATOM(isFinite), NULL},
1464     {js_InitNumberClass, LAZY_ATOM(parseFloat), NULL},
1465     {js_InitNumberClass, LAZY_ATOM(parseInt), NULL},
1466    
1467     /* String global functions. */
1468     {js_InitStringClass, LAZY_ATOM(escape), NULL},
1469     {js_InitStringClass, LAZY_ATOM(unescape), NULL},
1470     {js_InitStringClass, LAZY_ATOM(decodeURI), NULL},
1471     {js_InitStringClass, LAZY_ATOM(encodeURI), NULL},
1472     {js_InitStringClass, LAZY_ATOM(decodeURIComponent), NULL},
1473     {js_InitStringClass, LAZY_ATOM(encodeURIComponent), NULL},
1474     #if JS_HAS_UNEVAL
1475     {js_InitStringClass, LAZY_ATOM(uneval), NULL},
1476     #endif
1477    
1478     /* Exception constructors. */
1479     {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)},
1480     {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
1481     {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
1482     {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
1483     {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
1484     {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
1485     {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
1486     {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)},
1487    
1488     #if JS_HAS_XML_SUPPORT
1489     {js_InitAnyNameClass, EAGER_ATOM_AND_CLASP(AnyName)},
1490     {js_InitAttributeNameClass, EAGER_ATOM_AND_CLASP(AttributeName)},
1491     {js_InitXMLClass, LAZY_ATOM(XMLList), &js_XMLClass},
1492     {js_InitXMLClass, LAZY_ATOM(isXMLName), NULL},
1493     #endif
1494    
1495     #if JS_HAS_GENERATORS
1496     {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)},
1497     {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Generator)},
1498     #endif
1499    
1500     {NULL, 0, NULL, NULL}
1501     };
1502    
1503     static JSStdName object_prototype_names[] = {
1504     /* Object.prototype properties (global delegates to Object.prototype). */
1505     {js_InitObjectClass, EAGER_ATOM(proto), NULL},
1506     {js_InitObjectClass, EAGER_ATOM(parent), NULL},
1507     {js_InitObjectClass, EAGER_ATOM(count), NULL},
1508     #if JS_HAS_TOSOURCE
1509     {js_InitObjectClass, EAGER_ATOM(toSource), NULL},
1510     #endif
1511     {js_InitObjectClass, EAGER_ATOM(toString), NULL},
1512     {js_InitObjectClass, EAGER_ATOM(toLocaleString), NULL},
1513     {js_InitObjectClass, EAGER_ATOM(valueOf), NULL},
1514     #if JS_HAS_OBJ_WATCHPOINT
1515     {js_InitObjectClass, LAZY_ATOM(watch), NULL},
1516     {js_InitObjectClass, LAZY_ATOM(unwatch), NULL},
1517     #endif
1518     {js_InitObjectClass, LAZY_ATOM(hasOwnProperty), NULL},
1519     {js_InitObjectClass, LAZY_ATOM(isPrototypeOf), NULL},
1520     {js_InitObjectClass, LAZY_ATOM(propertyIsEnumerable), NULL},
1521     #if JS_HAS_GETTER_SETTER
1522     {js_InitObjectClass, LAZY_ATOM(defineGetter), NULL},
1523     {js_InitObjectClass, LAZY_ATOM(defineSetter), NULL},
1524     {js_InitObjectClass, LAZY_ATOM(lookupGetter), NULL},
1525     {js_InitObjectClass, LAZY_ATOM(lookupSetter), NULL},
1526     #endif
1527    
1528     {NULL, 0, NULL, NULL}
1529     };
1530    
1531     JS_PUBLIC_API(JSBool)
1532     JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
1533     JSBool *resolved)
1534     {
1535     JSString *idstr;
1536     JSRuntime *rt;
1537     JSAtom *atom;
1538     JSStdName *stdnm;
1539     uintN i;
1540    
1541     CHECK_REQUEST(cx);
1542     *resolved = JS_FALSE;
1543    
1544     rt = cx->runtime;
1545     JS_ASSERT(rt->state != JSRTS_DOWN);
1546     if (rt->state == JSRTS_LANDING || !JSVAL_IS_STRING(id))
1547     return JS_TRUE;
1548    
1549     idstr = JSVAL_TO_STRING(id);
1550    
1551     /* Check whether we're resolving 'undefined', and define it if so. */
1552     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1553     if (idstr == ATOM_TO_STRING(atom)) {
1554     *resolved = JS_TRUE;
1555     return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1556     NULL, NULL, JSPROP_PERMANENT, NULL);
1557     }
1558    
1559     /* Try for class constructors/prototypes named by well-known atoms. */
1560     stdnm = NULL;
1561     for (i = 0; standard_class_atoms[i].init; i++) {
1562     atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1563     if (idstr == ATOM_TO_STRING(atom)) {
1564     stdnm = &standard_class_atoms[i];
1565     break;
1566     }
1567     }
1568    
1569     if (!stdnm) {
1570     /* Try less frequently used top-level functions and constants. */
1571     for (i = 0; standard_class_names[i].init; i++) {
1572     atom = StdNameToAtom(cx, &standard_class_names[i]);
1573     if (!atom)
1574     return JS_FALSE;
1575     if (idstr == ATOM_TO_STRING(atom)) {
1576     stdnm = &standard_class_names[i];
1577     break;
1578     }
1579     }
1580    
1581     if (!stdnm && !OBJ_GET_PROTO(cx, obj)) {
1582     /*
1583     * Try even less frequently used names delegated from the global
1584     * object to Object.prototype, but only if the Object class hasn't
1585     * yet been initialized.
1586     */
1587     for (i = 0; object_prototype_names[i].init; i++) {
1588     atom = StdNameToAtom(cx, &object_prototype_names[i]);
1589     if (!atom)
1590     return JS_FALSE;
1591     if (idstr == ATOM_TO_STRING(atom)) {
1592     stdnm = &standard_class_names[i];
1593     break;
1594     }
1595     }
1596     }
1597     }
1598    
1599     if (stdnm) {
1600     /*
1601     * If this standard class is anonymous and obj advertises itself as a
1602     * global object (in order to reserve slots for standard class object
1603     * pointers), then we don't want to resolve by name.
1604     *
1605     * If inversely, either id does not name a class, or id does not name
1606     * an anonymous class, or the global does not reserve slots for class
1607     * objects, then we must call the init hook here.
1608     */
1609     if (stdnm->clasp &&
1610     (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS) &&
1611     (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL)) {
1612     return JS_TRUE;
1613     }
1614    
1615     if (!stdnm->init(cx, obj))
1616     return JS_FALSE;
1617     *resolved = JS_TRUE;
1618     }
1619     return JS_TRUE;
1620     }
1621    
1622     static JSBool
1623     AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom)
1624     {
1625     JSScopeProperty *sprop;
1626     JSScope *scope;
1627    
1628     JS_ASSERT(OBJ_IS_NATIVE(obj));
1629     JS_LOCK_OBJ(cx, obj);
1630     scope = OBJ_SCOPE(obj);
1631     sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom));
1632     JS_UNLOCK_SCOPE(cx, scope);
1633     return sprop != NULL;
1634     }
1635    
1636     JS_PUBLIC_API(JSBool)
1637     JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1638     {
1639     JSRuntime *rt;
1640     JSAtom *atom;
1641     uintN i;
1642    
1643     CHECK_REQUEST(cx);
1644     rt = cx->runtime;
1645    
1646     /* Check whether we need to bind 'undefined' and define it if so. */
1647     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1648     if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1649     !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1650     NULL, NULL, JSPROP_PERMANENT, NULL)) {
1651     return JS_FALSE;
1652     }
1653    
1654     /* Initialize any classes that have not been resolved yet. */
1655     for (i = 0; standard_class_atoms[i].init; i++) {
1656     atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1657     if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1658     !standard_class_atoms[i].init(cx, obj)) {
1659     return JS_FALSE;
1660     }
1661     }
1662    
1663     return JS_TRUE;
1664     }
1665    
1666     static JSIdArray *
1667     NewIdArray(JSContext *cx, jsint length)
1668     {
1669     JSIdArray *ida;
1670    
1671     ida = (JSIdArray *)
1672     JS_malloc(cx, offsetof(JSIdArray, vector) + length * sizeof(jsval));
1673     if (ida)
1674     ida->length = length;
1675     return ida;
1676     }
1677    
1678     /*
1679     * Unlike realloc(3), this function frees ida on failure.
1680     */
1681     static JSIdArray *
1682     SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
1683     {
1684     JSIdArray *rida;
1685    
1686     rida = (JSIdArray *)
1687     JS_realloc(cx, ida,
1688     offsetof(JSIdArray, vector) + length * sizeof(jsval));
1689     if (!rida)
1690     JS_DestroyIdArray(cx, ida);
1691     else
1692     rida->length = length;
1693     return rida;
1694     }
1695    
1696     static JSIdArray *
1697     AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1698     {
1699     jsint i, length;
1700    
1701     i = *ip;
1702     length = ida->length;
1703     if (i >= length) {
1704     ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
1705     if (!ida)
1706     return NULL;
1707     JS_ASSERT(i < ida->length);
1708     }
1709     ida->vector[i] = ATOM_TO_JSID(atom);
1710     *ip = i + 1;
1711     return ida;
1712     }
1713    
1714     static JSIdArray *
1715     EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
1716     jsint *ip, JSBool *foundp)
1717     {
1718     *foundp = AlreadyHasOwnProperty(cx, obj, atom);
1719     if (*foundp)
1720     ida = AddAtomToArray(cx, atom, ida, ip);
1721     return ida;
1722     }
1723    
1724     JS_PUBLIC_API(JSIdArray *)
1725     JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
1726     JSIdArray *ida)
1727     {
1728     JSRuntime *rt;
1729     jsint i, j, k;
1730     JSAtom *atom;
1731     JSBool found;
1732     JSObjectOp init;
1733    
1734     CHECK_REQUEST(cx);
1735     rt = cx->runtime;
1736     if (ida) {
1737     i = ida->length;
1738     } else {
1739     ida = NewIdArray(cx, 8);
1740     if (!ida)
1741     return NULL;
1742     i = 0;
1743     }
1744    
1745     /* Check whether 'undefined' has been resolved and enumerate it if so. */
1746     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1747     ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1748     if (!ida)
1749     return NULL;
1750    
1751     /* Enumerate only classes that *have* been resolved. */
1752     for (j = 0; standard_class_atoms[j].init; j++) {
1753     atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
1754     ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1755     if (!ida)
1756     return NULL;
1757    
1758     if (found) {
1759     init = standard_class_atoms[j].init;
1760    
1761     for (k = 0; standard_class_names[k].init; k++) {
1762     if (standard_class_names[k].init == init) {
1763     atom = StdNameToAtom(cx, &standard_class_names[k]);
1764     ida = AddAtomToArray(cx, atom, ida, &i);
1765     if (!ida)
1766     return NULL;
1767     }
1768     }
1769    
1770     if (init == js_InitObjectClass) {
1771     for (k = 0; object_prototype_names[k].init; k++) {
1772     atom = StdNameToAtom(cx, &object_prototype_names[k]);
1773     ida = AddAtomToArray(cx, atom, ida, &i);
1774     if (!ida)
1775     return NULL;
1776     }
1777     }
1778     }
1779     }
1780    
1781     /* Trim to exact length. */
1782     return SetIdArrayLength(cx, ida, i);
1783     }
1784    
1785     #undef CLASP
1786     #undef EAGER_ATOM
1787     #undef EAGER_CLASS_ATOM
1788     #undef EAGER_ATOM_CLASP
1789     #undef LAZY_ATOM
1790    
1791     JS_PUBLIC_API(JSBool)
1792     JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
1793     JSObject **objp)
1794     {
1795     CHECK_REQUEST(cx);
1796     return js_GetClassObject(cx, obj, key, objp);
1797     }
1798    
1799     JS_PUBLIC_API(JSObject *)
1800     JS_GetScopeChain(JSContext *cx)
1801     {
1802     JSStackFrame *fp;
1803    
1804     CHECK_REQUEST(cx);
1805     fp = cx->fp;
1806     if (!fp) {
1807     /*
1808     * There is no code active on this context. In place of an actual
1809     * scope chain, use the context's global object, which is set in
1810     * js_InitFunctionAndObjectClasses, and which represents the default
1811     * scope chain for the embedding. See also js_FindClassObject.
1812     *
1813     * For embeddings that use the inner and outer object hooks, the inner
1814     * object represents the ultimate global object, with the outer object
1815     * acting as a stand-in.
1816     */
1817     JSObject *obj = cx->globalObject;
1818     if (!obj) {
1819     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
1820     return NULL;
1821     }
1822    
1823     OBJ_TO_INNER_OBJECT(cx, obj);
1824     return obj;
1825     }
1826     return js_GetScopeChain(cx, fp);
1827     }
1828    
1829     JS_PUBLIC_API(JSObject *)
1830     JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
1831     {
1832     JSObject *parent;
1833    
1834     while ((parent = OBJ_GET_PARENT(cx, obj)) != NULL)
1835     obj = parent;
1836     return obj;
1837     }
1838    
1839     JS_PUBLIC_API(jsval)
1840     JS_ComputeThis(JSContext *cx, jsval *vp)
1841     {
1842     if (!js_ComputeThis(cx, JS_FALSE, vp + 2))
1843     return JSVAL_NULL;
1844     return vp[1];
1845     }
1846    
1847     JS_PUBLIC_API(void *)
1848     JS_malloc(JSContext *cx, size_t nbytes)
1849     {
1850     void *p;
1851    
1852     JS_ASSERT(nbytes != 0);
1853     JS_COUNT_OPERATION(cx, JSOW_ALLOCATION);
1854     if (nbytes == 0)
1855     nbytes = 1;
1856    
1857     p = malloc(nbytes);
1858     if (!p) {
1859     JS_ReportOutOfMemory(cx);
1860     return NULL;
1861     }
1862     js_UpdateMallocCounter(cx, nbytes);
1863    
1864     return p;
1865     }
1866    
1867     JS_PUBLIC_API(void *)
1868     JS_realloc(JSContext *cx, void *p, size_t nbytes)
1869     {
1870     JS_COUNT_OPERATION(cx, JSOW_ALLOCATION);
1871     p = realloc(p, nbytes);
1872     if (!p)
1873     JS_ReportOutOfMemory(cx);
1874     return p;
1875     }
1876    
1877     JS_PUBLIC_API(void)
1878     JS_free(JSContext *cx, void *p)
1879     {
1880     if (p)
1881     free(p);
1882     }
1883    
1884     JS_PUBLIC_API(char *)
1885     JS_strdup(JSContext *cx, const char *s)
1886     {
1887     size_t n;
1888     void *p;
1889    
1890     n = strlen(s) + 1;
1891     p = JS_malloc(cx, n);
1892     if (!p)
1893     return NULL;
1894     return (char *)memcpy(p, s, n);
1895     }
1896    
1897     JS_PUBLIC_API(jsdouble *)
1898     JS_NewDouble(JSContext *cx, jsdouble d)
1899     {
1900     CHECK_REQUEST(cx);
1901     return js_NewWeaklyRootedDouble(cx, d);
1902     }
1903    
1904     JS_PUBLIC_API(JSBool)
1905     JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
1906     {
1907     jsdouble *dp;
1908    
1909     CHECK_REQUEST(cx);
1910     dp = js_NewWeaklyRootedDouble(cx, d);
1911     if (!dp)
1912     return JS_FALSE;
1913     *rval = DOUBLE_TO_JSVAL(dp);
1914     return JS_TRUE;
1915     }
1916    
1917     JS_PUBLIC_API(JSBool)
1918     JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
1919     {
1920     jsint i;
1921    
1922     CHECK_REQUEST(cx);
1923     if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
1924     *rval = INT_TO_JSVAL(i);
1925     return JS_TRUE;
1926     }
1927     return JS_NewDoubleValue(cx, d, rval);
1928     }
1929    
1930     #undef JS_AddRoot
1931     JS_PUBLIC_API(JSBool)
1932     JS_AddRoot(JSContext *cx, void *rp)
1933     {
1934     CHECK_REQUEST(cx);
1935     return js_AddRoot(cx, rp, NULL);
1936     }
1937    
1938     JS_PUBLIC_API(JSBool)
1939     JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name)
1940     {
1941     return js_AddRootRT(rt, rp, name);
1942     }
1943    
1944     JS_PUBLIC_API(JSBool)
1945     JS_RemoveRoot(JSContext *cx, void *rp)
1946     {
1947     CHECK_REQUEST(cx);
1948     return js_RemoveRoot(cx->runtime, rp);
1949     }
1950    
1951     JS_PUBLIC_API(JSBool)
1952     JS_RemoveRootRT(JSRuntime *rt, void *rp)
1953     {
1954     return js_RemoveRoot(rt, rp);
1955     }
1956    
1957     JS_PUBLIC_API(JSBool)
1958     JS_AddNamedRoot(JSContext *cx, void *rp, const char *name)
1959     {
1960     CHECK_REQUEST(cx);
1961     return js_AddRoot(cx, rp, name);
1962     }
1963    
1964     JS_PUBLIC_API(void)
1965     JS_ClearNewbornRoots(JSContext *cx)
1966     {
1967     JS_CLEAR_WEAK_ROOTS(&cx->weakRoots);
1968     }
1969    
1970     JS_PUBLIC_API(JSBool)
1971     JS_EnterLocalRootScope(JSContext *cx)
1972     {
1973     CHECK_REQUEST(cx);
1974     return js_EnterLocalRootScope(cx);
1975     }
1976    
1977     JS_PUBLIC_API(void)
1978     JS_LeaveLocalRootScope(JSContext *cx)
1979     {
1980     CHECK_REQUEST(cx);
1981     js_LeaveLocalRootScope(cx);
1982     }
1983    
1984     JS_PUBLIC_API(void)
1985     JS_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval)
1986     {
1987     CHECK_REQUEST(cx);
1988     js_LeaveLocalRootScopeWithResult(cx, rval);
1989     }
1990    
1991     JS_PUBLIC_API(void)
1992     JS_ForgetLocalRoot(JSContext *cx, void *thing)
1993     {
1994     CHECK_REQUEST(cx);
1995     js_ForgetLocalRoot(cx, (jsval) thing);
1996     }
1997    
1998     #ifdef DEBUG
1999    
2000     JS_PUBLIC_API(void)
2001     JS_DumpNamedRoots(JSRuntime *rt,
2002     void (*dump)(const char *name, void *rp, void *data),
2003     void *data)
2004     {
2005     js_DumpNamedRoots(rt, dump, data);
2006     }
2007    
2008     #endif /* DEBUG */
2009    
2010     JS_PUBLIC_API(uint32)
2011     JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
2012     {
2013     return js_MapGCRoots(rt, map, data);
2014     }
2015    
2016     JS_PUBLIC_API(JSBool)
2017     JS_LockGCThing(JSContext *cx, void *thing)
2018     {
2019     JSBool ok;
2020    
2021     CHECK_REQUEST(cx);
2022     ok = js_LockGCThingRT(cx->runtime, thing);
2023     if (!ok)
2024     JS_ReportOutOfMemory(cx);
2025     return ok;
2026     }
2027    
2028     JS_PUBLIC_API(JSBool)
2029     JS_LockGCThingRT(JSRuntime *rt, void *thing)
2030     {
2031     return js_LockGCThingRT(rt, thing);
2032     }
2033    
2034     JS_PUBLIC_API(JSBool)
2035     JS_UnlockGCThing(JSContext *cx, void *thing)
2036     {
2037     JSBool ok;
2038    
2039     CHECK_REQUEST(cx);
2040     ok = js_UnlockGCThingRT(cx->runtime, thing);
2041     if (!ok)
2042     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_UNLOCK);
2043     return ok;
2044     }
2045    
2046     JS_PUBLIC_API(JSBool)
2047     JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
2048     {
2049     return js_UnlockGCThingRT(rt, thing);
2050     }
2051    
2052     JS_PUBLIC_API(void)
2053     JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
2054     {
2055     rt->gcExtraRootsTraceOp = traceOp;
2056     rt->gcExtraRootsData = data;
2057     }
2058    
2059     JS_PUBLIC_API(void)
2060     JS_TraceRuntime(JSTracer *trc)
2061     {
2062     JSBool allAtoms = trc->context->runtime->gcKeepAtoms != 0;
2063    
2064     js_TraceRuntime(trc, allAtoms);
2065     }
2066    
2067     #ifdef DEBUG
2068    
2069     #ifdef HAVE_XPCONNECT
2070     #include "dump_xpc.h"
2071     #endif
2072    
2073     JS_PUBLIC_API(void)
2074     JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc,
2075     void *thing, uint32 kind, JSBool details)
2076     {
2077     const char *name;
2078     size_t n;
2079    
2080     if (bufsize == 0)
2081     return;
2082    
2083     switch (kind) {
2084     case JSTRACE_OBJECT:
2085     {
2086     JSObject *obj = (JSObject *)thing;
2087     JSClass *clasp = STOBJ_GET_CLASS(obj);
2088    
2089     name = clasp->name;
2090     #ifdef HAVE_XPCONNECT
2091     if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
2092     jsval privateValue = STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
2093    
2094     JS_ASSERT(clasp->flags & JSCLASS_HAS_PRIVATE);
2095     if (!JSVAL_IS_VOID(privateValue)) {
2096     void *privateThing = JSVAL_TO_PRIVATE(privateValue);
2097     const char *xpcClassName = GetXPCObjectClassName(privateThing);
2098    
2099     if (xpcClassName)
2100     name = xpcClassName;
2101     }
2102     }
2103     #endif
2104     break;
2105     }
2106    
2107     case JSTRACE_STRING:
2108     name = JSSTRING_IS_DEPENDENT((JSString *)thing)
2109     ? "substring"
2110     : "string";
2111     break;
2112    
2113     case JSTRACE_DOUBLE:
2114     name = "double";
2115     break;
2116    
2117     #if JS_HAS_XML_SUPPORT
2118     case JSTRACE_XML:
2119     name = "xml";
2120     break;
2121     #endif
2122     default:
2123     JS_ASSERT(0);
2124     return;
2125     break;
2126     }
2127    
2128     n = strlen(name);
2129     if (n > bufsize - 1)
2130     n = bufsize - 1;
2131     memcpy(buf, name, n + 1);
2132     buf += n;
2133     bufsize -= n;
2134    
2135     if (details && bufsize > 2) {
2136     *buf++ = ' ';
2137     bufsize--;
2138    
2139     switch (kind) {
2140     case JSTRACE_OBJECT:
2141     {
2142     JSObject *obj = (JSObject *)thing;
2143     JSClass *clasp = STOBJ_GET_CLASS(obj);
2144     if (clasp == &js_FunctionClass) {
2145     JSFunction *fun = (JSFunction *)
2146     JS_GetPrivate(trc->context, obj);
2147    
2148     if (!fun) {
2149     JS_snprintf(buf, bufsize, "<newborn>");
2150     } else if (FUN_OBJECT(fun) != obj) {
2151     JS_snprintf(buf, bufsize, "%p", fun);
2152     } else {
2153     if (fun->atom && ATOM_IS_STRING(fun->atom))
2154     js_PutEscapedString(buf, bufsize,
2155     ATOM_TO_STRING(fun->atom), 0);
2156     }
2157     } else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
2158     jsval privateValue = STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
2159     void *privateThing = JSVAL_IS_VOID(privateValue)
2160     ? NULL
2161     : JSVAL_TO_PRIVATE(privateValue);
2162    
2163     JS_snprintf(buf, bufsize, "%p", privateThing);
2164     } else {
2165     JS_snprintf(buf, bufsize, "<no private>");
2166     }
2167     break;
2168     }
2169    
2170     case JSTRACE_STRING:
2171     js_PutEscapedString(buf, bufsize, (JSString *)thing, 0);
2172     break;
2173    
2174     case JSTRACE_DOUBLE:
2175     JS_snprintf(buf, bufsize, "%g", *(jsdouble *)thing);
2176     break;
2177    
2178     #if JS_HAS_XML_SUPPORT
2179     case JSTRACE_XML:
2180     {
2181     extern const char *js_xml_class_str[];
2182     JSXML *xml = (JSXML *)thing;
2183    
2184     JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]);
2185     break;
2186     }
2187     #endif
2188     default:
2189     JS_ASSERT(0);
2190     break;
2191     }
2192     }
2193     buf[bufsize - 1] = '\0';
2194     }
2195    
2196     typedef struct JSHeapDumpNode JSHeapDumpNode;
2197    
2198     struct JSHeapDumpNode {
2199     void *thing;
2200     uint32 kind;
2201     JSHeapDumpNode *next; /* next sibling */
2202     JSHeapDumpNode *parent; /* node with the thing that refer to thing
2203     from this node */
2204     char edgeName[1]; /* name of the edge from parent->thing
2205     into thing */
2206     };
2207    
2208     typedef struct JSDumpingTracer {
2209     JSTracer base;
2210     JSDHashTable visited;
2211     JSBool ok;
2212     void *startThing;
2213     void *thingToFind;
2214     void *thingToIgnore;
2215     JSHeapDumpNode *parentNode;
2216     JSHeapDumpNode **lastNodep;
2217     char buffer[200];
2218     } JSDumpingTracer;
2219    
2220     static void
2221     DumpNotify(JSTracer *trc, void *thing, uint32 kind)
2222     {
2223     JSDumpingTracer *dtrc;
2224     JSContext *cx;
2225     JSDHashEntryStub *entry;
2226     JSHeapDumpNode *node;
2227     const char *edgeName;
2228     size_t edgeNameSize;
2229    
2230     JS_ASSERT(trc->callback == DumpNotify);
2231     dtrc = (JSDumpingTracer *)trc;
2232    
2233     if (!dtrc->ok || thing == dtrc->thingToIgnore)
2234     return;
2235    
2236     cx = trc->context;
2237    
2238     /*
2239     * Check if we have already seen thing unless it is thingToFind to include
2240     * it to the graph each time we reach it and print all live things that
2241     * refer to thingToFind.
2242     *
2243     * This does not print all possible paths leading to thingToFind since
2244     * when a thing A refers directly or indirectly to thingToFind and A is
2245     * present several times in the graph, we will print only the first path
2246     * leading to A and thingToFind, other ways to reach A will be ignored.
2247     */
2248     if (dtrc->thingToFind != thing) {
2249     /*
2250     * The startThing check allows to avoid putting startThing into the
2251     * hash table before tracing startThing in JS_DumpHeap.
2252     */
2253     if (thing == dtrc->startThing)
2254     return;
2255     entry = (JSDHashEntryStub *)
2256     JS_DHashTableOperate(&dtrc->visited, thing, JS_DHASH_ADD);
2257     if (!entry) {
2258     JS_ReportOutOfMemory(cx);
2259     dtrc->ok = JS_FALSE;
2260     return;
2261     }
2262     if (entry->key)
2263     return;
2264     entry->key = thing;
2265     }
2266    
2267     if (dtrc->base.debugPrinter) {
2268     dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer));
2269     edgeName = dtrc->buffer;
2270     } else if (dtrc->base.debugPrintIndex != (size_t)-1) {
2271     JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]",
2272     (const char *)dtrc->base.debugPrintArg,
2273     dtrc->base.debugPrintIndex);
2274     edgeName = dtrc->buffer;
2275     } else {
2276     edgeName = (const char*)dtrc->base.debugPrintArg;
2277     }
2278    
2279     edgeNameSize = strlen(edgeName) + 1;
2280     node = (JSHeapDumpNode *)
2281     JS_malloc(cx, offsetof(JSHeapDumpNode, edgeName) + edgeNameSize);
2282     if (!node) {
2283     dtrc->ok = JS_FALSE;
2284     return;
2285     }
2286    
2287     node->thing = thing;
2288     node->kind = kind;
2289     node->next = NULL;
2290     node->parent = dtrc->parentNode;
2291     memcpy(node->edgeName, edgeName, edgeNameSize);
2292    
2293     JS_ASSERT(!*dtrc->lastNodep);
2294     *dtrc->lastNodep = node;
2295     dtrc->lastNodep = &node->next;
2296     }
2297    
2298     /* Dump node and the chain that leads to thing it contains. */
2299     static JSBool
2300     DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
2301     {
2302     JSHeapDumpNode *prev, *following;
2303     size_t chainLimit;
2304     JSBool ok;
2305     enum { MAX_PARENTS_TO_PRINT = 10 };
2306    
2307     JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2308     &dtrc->base, node->thing, node->kind, JS_TRUE);
2309     if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
2310     return JS_FALSE;
2311    
2312     /*
2313     * We need to print the parent chain in the reverse order. To do it in
2314     * O(N) time where N is the chain length we first reverse the chain while
2315     * searching for the top and then print each node while restoring the
2316     * chain order.
2317     */
2318     chainLimit = MAX_PARENTS_TO_PRINT;
2319     prev = NULL;
2320     for (;;) {
2321     following = node->parent;
2322     node->parent = prev;
2323     prev = node;
2324     node = following;
2325     if (!node)
2326     break;
2327     if (chainLimit == 0) {
2328     if (fputs("...", fp) < 0)
2329     return JS_FALSE;
2330     break;
2331     }
2332     --chainLimit;
2333     }
2334    
2335     node = prev;
2336     prev = following;
2337     ok = JS_TRUE;
2338     do {
2339     /* Loop must continue even when !ok to restore the parent chain. */
2340     if (ok) {
2341     if (!prev) {
2342     /* Print edge from some runtime root or startThing. */
2343     if (fputs(node->edgeName, fp) < 0)
2344     ok = JS_FALSE;
2345     } else {
2346     JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2347     &dtrc->base, prev->thing, prev->kind,
2348     JS_FALSE);
2349     if (fprintf(fp, "(%p %s).%s",
2350     prev->thing, dtrc->buffer, node->edgeName) < 0) {
2351     ok = JS_FALSE;
2352     }
2353     }
2354     }
2355     following = node->parent;
2356     node->parent = prev;
2357     prev = node;
2358     node = following;
2359     } while (node);
2360    
2361     return ok && putc('\n', fp) >= 0;
2362     }
2363    
2364     JS_PUBLIC_API(JSBool)
2365     JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind,
2366     void *thingToFind, size_t maxDepth, void *thingToIgnore)
2367     {
2368     JSDumpingTracer dtrc;
2369     JSHeapDumpNode *node, *children, *next, *parent;
2370     size_t depth;
2371     JSBool thingToFindWasTraced;
2372    
2373     if (maxDepth == 0)
2374     return JS_TRUE;
2375    
2376     JS_TRACER_INIT(&dtrc.base, cx, DumpNotify);
2377     if (!JS_DHashTableInit(&dtrc.visited, JS_DHashGetStubOps(),
2378     NULL, sizeof(JSDHashEntryStub),
2379     JS_DHASH_DEFAULT_CAPACITY(100))) {
2380     JS_ReportOutOfMemory(cx);
2381     return JS_FALSE;
2382     }
2383     dtrc.ok = JS_TRUE;
2384     dtrc.startThing = startThing;
2385     dtrc.thingToFind = thingToFind;
2386     dtrc.thingToIgnore = thingToIgnore;
2387     dtrc.parentNode = NULL;
2388     node = NULL;
2389     dtrc.lastNodep = &node;
2390     if (!startThing) {
2391     JS_ASSERT(startKind == 0);
2392     JS_TraceRuntime(&dtrc.base);
2393     } else {
2394     JS_TraceChildren(&dtrc.base, startThing, startKind);
2395     }
2396    
2397     depth = 1;
2398     if (!node)
2399     goto dump_out;
2400    
2401     thingToFindWasTraced = thingToFind && thingToFind == startThing;
2402     for (;;) {
2403     /*
2404     * Loop must continue even when !dtrc.ok to free all nodes allocated
2405     * so far.
2406     */
2407     if (dtrc.ok) {
2408     if (thingToFind == NULL || thingToFind == node->thing)
2409     dtrc.ok = DumpNode(&dtrc, fp, node);
2410    
2411     /* Descend into children. */
2412     if (dtrc.ok &&
2413     depth < maxDepth &&
2414     (thingToFind != node->thing || !thingToFindWasTraced)) {
2415     dtrc.parentNode = node;
2416     children = NULL;
2417     dtrc.lastNodep = &children;
2418     JS_TraceChildren(&dtrc.base, node->thing, node->kind);
2419     if (thingToFind == node->thing)
2420     thingToFindWasTraced = JS_TRUE;
2421     if (children != NULL) {
2422     ++depth;
2423     node = children;
2424     continue;
2425     }
2426     }
2427     }
2428    
2429     /* Move to next or parents next and free the node. */
2430     for (;;) {
2431     next = node->next;
2432     parent = node->parent;
2433     JS_free(cx, node);
2434     node = next;
2435     if (node)
2436     break;
2437     if (!parent)
2438     goto dump_out;
2439     JS_ASSERT(depth > 1);
2440     --depth;
2441     node = parent;
2442     }
2443     }
2444    
2445     dump_out:
2446     JS_ASSERT(depth == 1);
2447     JS_DHashTableFinish(&dtrc.visited);
2448     return dtrc.ok;
2449     }
2450    
2451     #endif /* DEBUG */
2452    
2453     JS_PUBLIC_API(void)
2454     JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg)
2455     {
2456     JSTracer *trc;
2457    
2458     trc = (JSTracer *)arg;
2459     if (!trc)
2460     trc = cx->runtime->gcMarkingTracer;
2461     else
2462     JS_ASSERT(trc == cx->runtime->gcMarkingTracer);
2463    
2464     #ifdef JS_THREADSAFE
2465     JS_ASSERT(cx->runtime->gcThread == trc->context->thread);
2466     #endif
2467     JS_SET_TRACING_NAME(trc, name ? name : "unknown");
2468     js_CallValueTracerIfGCThing(trc, (jsval)thing);
2469     }
2470    
2471     extern JS_PUBLIC_API(JSBool)
2472     JS_IsGCMarkingTracer(JSTracer *trc)
2473     {
2474     return IS_GC_MARKING_TRACER(trc);
2475     }
2476    
2477     JS_PUBLIC_API(void)
2478     JS_GC(JSContext *cx)
2479     {
2480     /* Don't nuke active arenas if executing or compiling. */
2481     if (cx->stackPool.current == &cx->stackPool.first)
2482     JS_FinishArenaPool(&cx->stackPool);
2483     if (cx->tempPool.current == &cx->tempPool.first)
2484     JS_FinishArenaPool(&cx->tempPool);
2485     js_GC(cx, GC_NORMAL);
2486     }
2487    
2488     JS_PUBLIC_API(void)
2489     JS_MaybeGC(JSContext *cx)
2490     {
2491     JSRuntime *rt;
2492     uint32 bytes, lastBytes;
2493    
2494     rt = cx->runtime;
2495    
2496     #ifdef JS_GC_ZEAL
2497     if (rt->gcZeal > 0) {
2498     JS_GC(cx);
2499     return;
2500     }
2501     #endif
2502    
2503     bytes = rt->gcBytes;
2504     lastBytes = rt->gcLastBytes;
2505    
2506     /*
2507     * We run the GC if we used all available free GC cells and had to
2508     * allocate extra 1/3 of GC arenas since the last run of GC, or if
2509     * we have malloc'd more bytes through JS_malloc than we were told
2510     * to allocate by JS_NewRuntime.
2511     *
2512     * The reason for
2513     * bytes > 4/3 lastBytes
2514     * condition is the following. Bug 312238 changed bytes and lastBytes
2515     * to mean the total amount of memory that the GC uses now and right
2516     * after the last GC.
2517     *
2518     * Before the bug the variables meant the size of allocated GC things
2519     * now and right after the last GC. That size did not include the
2520     * memory taken by free GC cells and the condition was
2521     * bytes > 3/2 lastBytes.
2522     * That is, we run the GC if we have half again as many bytes of
2523     * GC-things as the last time we GC'd. To be compatible we need to
2524     * express that condition through the new meaning of bytes and
2525     * lastBytes.
2526     *
2527     * We write the original condition as
2528     * B*(1-F) > 3/2 Bl*(1-Fl)
2529     * where B is the total memory size allocated by GC and F is the free
2530     * cell density currently and Sl and Fl are the size and the density
2531     * right after GC. The density by definition is memory taken by free
2532     * cells divided by total amount of memory. In other words, B and Bl
2533     * are bytes and lastBytes with the new meaning and B*(1-F) and
2534     * Bl*(1-Fl) are bytes and lastBytes with the original meaning.
2535     *
2536     * Our task is to exclude F and Fl from the last statement. According
2537     * to the stats from bug 331966 comment 23, Fl is about 10-25% for a
2538     * typical run of the browser. It means that the original condition
2539     * implied that we did not run GC unless we exhausted the pool of
2540     * free cells. Indeed if we still have free cells, then B == Bl since
2541     * we did not yet allocated any new arenas and the condition means
2542     * 1 - F > 3/2 (1-Fl) or 3/2Fl > 1/2 + F
2543     * That implies 3/2 Fl > 1/2 or Fl > 1/3. That can not be fulfilled
2544     * for the state described by the stats. So we can write the original
2545     * condition as:
2546     * F == 0 && B > 3/2 Bl(1-Fl)
2547     * Again using the stats we see that Fl is about 11% when the browser
2548     * starts up and when we are far from hitting rt->gcMaxBytes. With
2549     * this F we have
2550     * F == 0 && B > 3/2 Bl(1-0.11)
2551     * or approximately F == 0 && B > 4/3 Bl.
2552     */
2553     if ((bytes > 8192 && bytes > lastBytes + lastBytes / 3) ||
2554     rt->gcMallocBytes >= rt->gcMaxMallocBytes) {
2555     JS_GC(cx);
2556     }
2557     }
2558    
2559     JS_PUBLIC_API(JSGCCallback)
2560     JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
2561     {
2562     CHECK_REQUEST(cx);
2563     return JS_SetGCCallbackRT(cx->runtime, cb);
2564     }
2565    
2566     JS_PUBLIC_API(JSGCCallback)
2567     JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
2568     {
2569     JSGCCallback oldcb;
2570    
2571     oldcb = rt->gcCallback;
2572     rt->gcCallback = cb;
2573     return oldcb;
2574     }
2575    
2576     JS_PUBLIC_API(JSBool)
2577     JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
2578     {
2579     JS_ASSERT(thing);
2580     return js_IsAboutToBeFinalized(cx, thing);
2581     }
2582    
2583     JS_PUBLIC_API(void)
2584     JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
2585     {
2586     switch (key) {
2587     case JSGC_MAX_BYTES:
2588     rt->gcMaxBytes = value;
2589     break;
2590     case JSGC_MAX_MALLOC_BYTES:
2591     rt->gcMaxMallocBytes = value;
2592     break;
2593     case JSGC_STACKPOOL_LIFESPAN:
2594     rt->gcEmptyArenaPoolLifespan = value;
2595     break;
2596     }
2597     }
2598    
2599     JS_PUBLIC_API(intN)
2600     JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
2601     {
2602     return js_ChangeExternalStringFinalizer(NULL, finalizer);
2603     }
2604    
2605     JS_PUBLIC_API(intN)
2606     JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
2607     {
2608     return js_ChangeExternalStringFinalizer(finalizer, NULL);
2609     }
2610    
2611     JS_PUBLIC_API(JSString *)
2612     JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
2613     {
2614     JSString *str;
2615    
2616     CHECK_REQUEST(cx);
2617     JS_ASSERT((uintN) type < (uintN) (GCX_NTYPES - GCX_EXTERNAL_STRING));
2618    
2619     str = (JSString *) js_NewGCThing(cx, (uintN) type + GCX_EXTERNAL_STRING,
2620     sizeof(JSString));
2621     if (!str)
2622     return NULL;
2623     JSFLATSTR_INIT(str, chars, length);
2624     return str;
2625     }
2626    
2627     JS_PUBLIC_API(intN)
2628     JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
2629     {
2630     return js_GetExternalStringGCType(str);
2631     }
2632    
2633     JS_PUBLIC_API(void)
2634     JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
2635     {
2636     #if JS_STACK_GROWTH_DIRECTION > 0
2637     if (limitAddr == 0)
2638     limitAddr = (jsuword)-1;
2639     #endif
2640     cx->stackLimit = limitAddr;
2641     }
2642    
2643     JS_PUBLIC_API(void)
2644     JS_SetScriptStackQuota(JSContext *cx, size_t quota)
2645     {
2646     cx->scriptStackQuota = quota;
2647     }
2648    
2649     /************************************************************************/
2650    
2651     JS_PUBLIC_API(void)
2652     JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
2653     {
2654     JS_free(cx, ida);
2655     }
2656    
2657     JS_PUBLIC_API(JSBool)
2658     JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
2659     {
2660     CHECK_REQUEST(cx);
2661     if (JSVAL_IS_INT(v))
2662     *idp = INT_JSVAL_TO_JSID(v);
2663     #if JS_HAS_XML_SUPPORT
2664     else if (!JSVAL_IS_PRIMITIVE(v))
2665     *idp = OBJECT_JSVAL_TO_JSID<