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

Annotation of /trunk/js/jsapi.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 507 - (hide annotations)
Sun Jan 10 07:23:34 2010 UTC (12 years, 5 months ago) by siliconforks
File size: 165919 byte(s)
Update SpiderMonkey from Firefox 3.6rc1.

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