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

Annotation of /trunk/js/jsapi.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 460 - (hide annotations)
Sat Sep 26 23:15:22 2009 UTC (12 years, 9 months ago) by siliconforks
File size: 168805 byte(s)
Upgrade to SpiderMonkey from Firefox 3.5.3.

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