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

Annotation of /trunk/js/jsapi.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 332 - (hide annotations)
Thu Oct 23 19:03:33 2008 UTC (13 years, 8 months ago) by siliconforks
File size: 167865 byte(s)
Add SpiderMonkey from Firefox 3.1b1.

The following directories and files were removed:
correct/, correct.js
liveconnect/
nanojit/
t/
v8/
vprof/
xpconnect/
all JavaScript files (Y.js, call.js, if.js, math-partial-sums.js, md5.js, perfect.js, trace-test.js, trace.js)


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