1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sw=4 et tw=80:
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is Mozilla Communicator client code, released
18  * March 31, 1998.
19  *
20  * The Initial Developer of the Original Code is
21  * Netscape Communications Corporation.
22  * Portions created by the Initial Developer are Copyright (C) 1998
23  * the Initial Developer. All Rights Reserved.
24  *
25  * Contributor(s):
26  *
27  * Alternatively, the contents of this file may be used under the terms of
28  * either of the GNU General Public License Version 2 or later (the "GPL"),
29  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30  * in which case the provisions of the GPL or the LGPL are applicable instead
31  * of those above. If you wish to allow use of your version of this file only
32  * under the terms of either the GPL or the LGPL, and not to allow others to
33  * use your version of this file under the terms of the MPL, indicate your
34  * decision by deleting the provisions above and replace them with the notice
35  * and other provisions required by the GPL or the LGPL. If you do not delete
36  * the provisions above, a recipient may use your version of this file under
37  * the terms of any one of the MPL, the GPL or the LGPL.
38  *
39  * ***** END LICENSE BLOCK ***** */
40
41 /*
42  * JavaScript API.
43  */
44 #include "jsstddef.h"
45 #include <ctype.h>
46 #include <stdarg.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include "jstypes.h"
50 #include "jsarena.h" /* Added by JSIFY */
51 #include "jsutil.h" /* Added by JSIFY */
52 #include "jsclist.h"
53 #include "jsdhash.h"
54 #include "jsprf.h"
55 #include "jsapi.h"
56 #include "jsarray.h"
57 #include "jsatom.h"
58 #include "jsbool.h"
59 #include "jscntxt.h"
60 #include "jsconfig.h"
61 #include "jsdate.h"
62 #include "jsdtoa.h"
63 #include "jsemit.h"
64 #include "jsexn.h"
65 #include "jsfun.h"
66 #include "jsgc.h"
67 #include "jsinterp.h"
68 #include "jslock.h"
69 #include "jsmath.h"
70 #include "jsnum.h"
71 #include "jsobj.h"
72 #include "jsopcode.h"
73 #include "jsparse.h"
74 #include "jsregexp.h"
75 #include "jsscan.h"
76 #include "jsscope.h"
77 #include "jsscript.h"
78 #include "jsstr.h"
79 #include "prmjtime.h"
80
81 #if JS_HAS_FILE_OBJECT
82 #include "jsfile.h"
83 #endif
84
85 #if JS_HAS_XML_SUPPORT
86 #include "jsxml.h"
87 #endif
88
89 #ifdef HAVE_VA_LIST_AS_ARRAY
90 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
91 #else
92 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
93 #endif
94
95 #if defined(JS_PARANOID_REQUEST) && defined(JS_THREADSAFE)
96 #define CHECK_REQUEST(cx)       JS_ASSERT(cx->requestDepth)
97 #else
98 #define CHECK_REQUEST(cx)       ((void)0)
99 #endif
100
101 JS_PUBLIC_API(int64)
102 JS_Now()
103 0 {
104 0     return PRMJ_Now();
105 }
106
107 JS_PUBLIC_API(jsval)
108 JS_GetNaNValue(JSContext *cx)
109 0 {
110 0     return DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
111 }
112
113 JS_PUBLIC_API(jsval)
114 JS_GetNegativeInfinityValue(JSContext *cx)
115 0 {
116 0     return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
117 }
118
119 JS_PUBLIC_API(jsval)
120 JS_GetPositiveInfinityValue(JSContext *cx)
121 1731 {
122 1731     return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
123 }
124
125 JS_PUBLIC_API(jsval)
126 JS_GetEmptyStringValue(JSContext *cx)
127 0 {
128 0     return STRING_TO_JSVAL(cx->runtime->emptyString);
129 }
130
131 static JSBool
132 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS,
133                      jsval **vpp, va_list *app)
134 0 {
135 0     const char *format;
136 0     JSArgumentFormatMap *map;
137
138 0     format = *formatp;
139 0     for (map = cx->argumentFormatMap; map; map = map->next) {
140 0         if (!strncmp(format, map->format, map->length)) {
141 0             *formatp = format + map->length;
142 0             return map->formatter(cx, format, fromJS, vpp, app);
143         }
144     }
145 0     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
146 0     return JS_FALSE;
147 }
148
149 JS_PUBLIC_API(JSBool)
150 JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
151                     ...)
152 0 {
153 0     va_list ap;
154 0     JSBool ok;
155
156 0     va_start(ap, format);
157 0     ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
158 0     va_end(ap);
159 0     return ok;
160 }
161
162 JS_PUBLIC_API(JSBool)
163 JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
164                       const char *format, va_list ap)
165 0 {
166 0     jsval *sp;
167 0     JSBool required;
168 0     char c;
169 0     JSFunction *fun;
170 0     jsdouble d;
171 0     JSString *str;
172 0     JSObject *obj;
173
174 0     CHECK_REQUEST(cx);
175 0     sp = argv;
176 0     required = JS_TRUE;
177 0     while ((c = *format++) != '\0') {
178 0         if (isspace(c))
179 0             continue;
180 0         if (c == '/') {
181 0             required = JS_FALSE;
182 0             continue;
183         }
184 0         if (sp == argv + argc) {
185 0             if (required) {
186 0                 fun = js_ValueToFunction(cx, &argv[-2], 0);
187 0                 if (fun) {
188 0                     char numBuf[12];
189 0                     JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
190 0                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
191                                          JSMSG_MORE_ARGS_NEEDED,
192                                          JS_GetFunctionName(fun), numBuf,
193                                          (argc == 1) ? "" : "s");
194                 }
195 0                 return JS_FALSE;
196             }
197 0             break;
198         }
199 0         switch (c) {
200           case 'b':
201 0             if (!js_ValueToBoolean(cx, *sp, va_arg(ap, JSBool *)))
202 0                 return JS_FALSE;
203 0             break;
204           case 'c':
205 0             if (!js_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
206 0                 return JS_FALSE;
207 0             break;
208           case 'i':
209 0             if (!js_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
210 0                 return JS_FALSE;
211 0             break;
212           case 'u':
213 0             if (!js_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
214 0                 return JS_FALSE;
215 0             break;
216           case 'j':
217 0             if (!js_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
218 0                 return JS_FALSE;
219 0             break;
220           case 'd':
221 0             if (!js_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
222 0                 return JS_FALSE;
223 0             break;
224           case 'I':
225 0             if (!js_ValueToNumber(cx, *sp, &d))
226 0                 return JS_FALSE;
227 0             *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
228 0             break;
229           case 's':
230           case 'S':
231           case 'W':
232 0             str = js_ValueToString(cx, *sp);
233 0             if (!str)
234 0                 return JS_FALSE;
235 0             *sp = STRING_TO_JSVAL(str);
236 0             if (c == 's')
237 0                 *va_arg(ap, char **) = JS_GetStringBytes(str);
238 0             else if (c == 'W')
239 0                 *va_arg(ap, jschar **) = JS_GetStringChars(str);
240             else
241 0                 *va_arg(ap, JSString **) = str;
242 0             break;
243           case 'o':
244 0             if (!js_ValueToObject(cx, *sp, &obj))
245 0                 return JS_FALSE;
246 0             *sp = OBJECT_TO_JSVAL(obj);
247 0             *va_arg(ap, JSObject **) = obj;
248 0             break;
249           case 'f':
250 0             obj = js_ValueToFunctionObject(cx, sp, 0);
251 0             if (!obj)
252 0                 return JS_FALSE;
253 0             *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj);
254 0             break;
255           case 'v':
256 0             *va_arg(ap, jsval *) = *sp;
257 0             break;
258           case '*':
259 0             break;
260           default:
261 0             format--;
262 0             if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
263                                       JS_ADDRESSOF_VA_LIST(ap))) {
264 0                 return JS_FALSE;
265             }
266             /* NB: the formatter already updated sp, so we continue here. */
267 0             continue;
268         }
269 0         sp++;
270     }
271 0     return JS_TRUE;
272 }
273
274 JS_PUBLIC_API(jsval *)
275 JS_PushArguments(JSContext *cx, void **markp, const char *format, ...)
276 0 {
277 0     va_list ap;
278 0     jsval *argv;
279
280 0     va_start(ap, format);
281 0     argv = JS_PushArgumentsVA(cx, markp, format, ap);
282 0     va_end(ap);
283 0     return argv;
284 }
285
286 JS_PUBLIC_API(jsval *)
287 JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap)
288 0 {
289 0     uintN argc;
290 0     jsval *argv, *sp;
291 0     char c;
292 0     const char *cp;
293 0     JSString *str;
294 0     JSFunction *fun;
295 0     JSStackHeader *sh;
296
297 0     CHECK_REQUEST(cx);
298 0     *markp = NULL;
299 0     argc = 0;
300 0     for (cp = format; (c = *cp) != '\0'; cp++) {
301         /*
302          * Count non-space non-star characters as individual jsval arguments.
303          * This may over-allocate stack, but we'll fix below.
304          */
305 0         if (isspace(c) || c == '*')
306 0             continue;
307 0         argc++;
308     }
309 0     sp = js_AllocStack(cx, argc, markp);
310 0     if (!sp)
311 0         return NULL;
312 0     argv = sp;
313 0     while ((c = *format++) != '\0') {
314 0         if (isspace(c) || c == '*')
315 0             continue;
316 0         switch (c) {
317           case 'b':
318 0             *sp = BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int));
319 0             break;
320           case 'c':
321 0             *sp = INT_TO_JSVAL((uint16) va_arg(ap, unsigned int));
322 0             break;
323           case 'i':
324           case 'j':
325 0             if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp))
326 0                 goto bad;
327 0             break;
328           case 'u':
329 0             if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp))
330 0                 goto bad;
331 0             break;
332           case 'd':
333           case 'I':
334 0             if (!js_NewDoubleValue(cx, va_arg(ap, jsdouble), sp))
335 0                 goto bad;
336 0             break;
337           case 's':
338 0             str = JS_NewStringCopyZ(cx, va_arg(ap, char *));
339 0             if (!str)
340 0                 goto bad;
341 0             *sp = STRING_TO_JSVAL(str);
342 0             break;
343           case 'W':
344 0             str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *));
345 0             if (!str)
346 0                 goto bad;
347 0             *sp = STRING_TO_JSVAL(str);
348 0             break;
349           case 'S':
350 0             str = va_arg(ap, JSString *);
351 0             *sp = STRING_TO_JSVAL(str);
352 0             break;
353           case 'o':
354 0             *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *));
355 0             break;
356           case 'f':
357 0             fun = va_arg(ap, JSFunction *);
358 0             *sp = fun ? OBJECT_TO_JSVAL(fun->object) : JSVAL_NULL;
359 0             break;
360           case 'v':
361 0             *sp = va_arg(ap, jsval);
362 0             break;
363           default:
364 0             format--;
365 0             if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp,
366                                       JS_ADDRESSOF_VA_LIST(ap))) {
367 0                 goto bad;
368             }
369             /* NB: the formatter already updated sp, so we continue here. */
370 0             continue;
371         }
372 0         sp++;
373     }
374
375     /*
376      * We may have overallocated stack due to a multi-character format code
377      * handled by a JSArgumentFormatter.  Give back that stack space!
378      */
379 0     JS_ASSERT(sp <= argv + argc);
380 0     if (sp < argv + argc) {
381         /* Return slots not pushed to the current stack arena. */
382 0         cx->stackPool.current->avail = (jsuword)sp;
383
384         /* Reduce the count of slots the GC will scan in this stack segment. */
385 0         sh = cx->stackHeaders;
386 0         JS_ASSERT(JS_STACK_SEGMENT(sh) + sh->nslots == argv + argc);
387 0         sh->nslots -= argc - (sp - argv);
388     }
389 0     return argv;
390
391 bad:
392 0     js_FreeStack(cx, *markp);
393 0     return NULL;
394 }
395
396 JS_PUBLIC_API(void)
397 JS_PopArguments(JSContext *cx, void *mark)
398 0 {
399 0     CHECK_REQUEST(cx);
400 0     js_FreeStack(cx, mark);
401 }
402
403 JS_PUBLIC_API(JSBool)
404 JS_AddArgumentFormatter(JSContext *cx, const char *format,
405                         JSArgumentFormatter formatter)
406 0 {
407 0     size_t length;
408 0     JSArgumentFormatMap **mpp, *map;
409
410 0     length = strlen(format);
411 0     mpp = &cx->argumentFormatMap;
412 0     while ((map = *mpp) != NULL) {
413         /* Insert before any shorter string to match before prefixes. */
414 0         if (map->length < length)
415 0             break;
416 0         if (map->length == length && !strcmp(map->format, format))
417 0             goto out;
418 0         mpp = &map->next;
419     }
420 0     map = (JSArgumentFormatMap *) JS_malloc(cx, sizeof *map);
421 0     if (!map)
422 0         return JS_FALSE;
423 0     map->format = format;
424 0     map->length = length;
425 0     map->next = *mpp;
426 0     *mpp = map;
427 out:
428 0     map->formatter = formatter;
429 0     return JS_TRUE;
430 }
431
432 JS_PUBLIC_API(void)
433 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
434 0 {
435 0     size_t length;
436 0     JSArgumentFormatMap **mpp, *map;
437
438 0     length = strlen(format);
439 0     mpp = &cx->argumentFormatMap;
440 0     while ((map = *mpp) != NULL) {
441 0         if (map->length == length && !strcmp(map->format, format)) {
442 0             *mpp = map->next;
443 0             JS_free(cx, map);
444 0             return;
445         }
446 0         mpp = &map->next;
447     }
448 }
449
450 JS_PUBLIC_API(JSBool)
451 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
452 0 {
453 0     JSBool ok, b;
454 0     JSObject *obj;
455 0     JSString *str;
456 0     jsdouble d, *dp;
457
458 0     CHECK_REQUEST(cx);
459 0     switch (type) {
460       case JSTYPE_VOID:
461 0         *vp = JSVAL_VOID;
462 0         ok = JS_TRUE;
463 0         break;
464       case JSTYPE_OBJECT:
465 0         ok = js_ValueToObject(cx, v, &obj);
466 0         if (ok)
467 0             *vp = OBJECT_TO_JSVAL(obj);
468 0         break;
469       case JSTYPE_FUNCTION:
470 0         *vp = v;
471 0         obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK);
472 0         ok = (obj != NULL);
473 0         break;
474       case JSTYPE_STRING:
475 0         str = js_ValueToString(cx, v);
476 0         ok = (str != NULL);
477 0         if (ok)
478 0             *vp = STRING_TO_JSVAL(str);
479 0         break;
480       case JSTYPE_NUMBER:
481 0         ok = js_ValueToNumber(cx, v, &d);
482 0         if (ok) {
483 0             dp = js_NewDouble(cx, d, 0);
484 0             ok = (dp != NULL);
485 0             if (ok)
486 0                 *vp = DOUBLE_TO_JSVAL(dp);
487         }
488 0         break;
489       case JSTYPE_BOOLEAN:
490 0         ok = js_ValueToBoolean(cx, v, &b);
491 0         if (ok)
492 0             *vp = BOOLEAN_TO_JSVAL(b);
493 0         break;
494       default: {
495 0         char numBuf[12];
496 0         JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
497 0         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
498                              numBuf);
499 0         ok = JS_FALSE;
500 0         break;
501       }
502     }
503 0     return ok;
504 }
505
506 JS_PUBLIC_API(JSBool)
507 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
508 0 {
509 0     CHECK_REQUEST(cx);
510 0     return js_ValueToObject(cx, v, objp);
511 }
512
513 JS_PUBLIC_API(JSFunction *)
514 JS_ValueToFunction(JSContext *cx, jsval v)
515 0 {
516 0     CHECK_REQUEST(cx);
517 0     return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
518 }
519
520 JS_PUBLIC_API(JSFunction *)
521 JS_ValueToConstructor(JSContext *cx, jsval v)
522 0 {
523 0     CHECK_REQUEST(cx);
524 0     return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
525 }
526
527 JS_PUBLIC_API(JSString *)
528 JS_ValueToString(JSContext *cx, jsval v)
529 320357 {
530 320357     CHECK_REQUEST(cx);
531 320357     return js_ValueToString(cx, v);
532 }
533
534 JS_PUBLIC_API(JSBool)
535 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
536 0 {
537 0     CHECK_REQUEST(cx);
538 0     return js_ValueToNumber(cx, v, dp);
539 }
540
541 JS_PUBLIC_API(JSBool)
542 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
543 0 {
544 0     CHECK_REQUEST(cx);
545 0     return js_ValueToECMAInt32(cx, v, ip);
546 }
547
548 JS_PUBLIC_API(JSBool)
549 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
550 0 {
551 0     CHECK_REQUEST(cx);
552 0     return js_ValueToECMAUint32(cx, v, ip);
553 }
554
555 JS_PUBLIC_API(JSBool)
556 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
557 0 {
558 0     CHECK_REQUEST(cx);
559 0     return js_ValueToInt32(cx, v, ip);
560 }
561
562 JS_PUBLIC_API(JSBool)
563 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
564 0 {
565 0     CHECK_REQUEST(cx);
566 0     return js_ValueToUint16(cx, v, ip);
567 }
568
569 JS_PUBLIC_API(JSBool)
570 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
571 0 {
572 0     CHECK_REQUEST(cx);
573 0     return js_ValueToBoolean(cx, v, bp);
574 }
575
576 JS_PUBLIC_API(JSType)
577 JS_TypeOfValue(JSContext *cx, jsval v)
578 0 {
579 0     JSType type;
580 0     JSObject *obj;
581 0     JSObjectOps *ops;
582 0     JSClass *clasp;
583
584 0     CHECK_REQUEST(cx);
585 0     if (JSVAL_IS_OBJECT(v)) {
586 0         type = JSTYPE_OBJECT;           /* XXXbe JSTYPE_NULL for JS2 */
587 0         obj = JSVAL_TO_OBJECT(v);
588 0         if (obj) {
589 0             ops = obj->map->ops;
590 #if JS_HAS_XML_SUPPORT
591 0             if (ops == &js_XMLObjectOps.base) {
592 0                 type = JSTYPE_XML;
593             } else
594 #endif
595             {
596                 /*
597                  * ECMA 262, 11.4.3 says that any native object that implements
598                  * [[Call]] should be of type "function". Note that RegExp and
599                  * Script are both of type "function" for compatibility with
600                  * older SpiderMonkeys.
601                  */
602 0                 clasp = OBJ_GET_CLASS(cx, obj);
603 0                 if ((ops == &js_ObjectOps)
604                     ? (clasp->call
605                        ? (clasp == &js_RegExpClass || clasp == &js_ScriptClass)
606                        : clasp == &js_FunctionClass)
607                     : ops->call != NULL) {
608 0                     type = JSTYPE_FUNCTION;
609                 } else {
610 #ifdef NARCISSUS
611                     if (!OBJ_GET_PROPERTY(cx, obj,
612                                           ATOM_TO_JSID(cx->runtime->atomState
613                                                        .callAtom),
614                                           &v)) {
615                         JS_ClearPendingException(cx);
616                     } else if (JSVAL_IS_FUNCTION(cx, v)) {
617                         type = JSTYPE_FUNCTION;
618                     }
619 #endif
620                 }
621             }
622         }
623 0     } else if (JSVAL_IS_NUMBER(v)) {
624 0         type = JSTYPE_NUMBER;
625 0     } else if (JSVAL_IS_STRING(v)) {
626 0         type = JSTYPE_STRING;
627 0     } else if (JSVAL_IS_BOOLEAN(v)) {
628 0         type = JSTYPE_BOOLEAN;
629     } else {
630 0         type = JSTYPE_VOID;
631     }
632 0     return type;
633 }
634
635 JS_PUBLIC_API(const char *)
636 JS_GetTypeName(JSContext *cx, JSType type)
637 0 {
638 0     if ((uintN)type >= (uintN)JSTYPE_LIMIT)
639 0         return NULL;
640 0     return js_type_str[type];
641 }
642
643 /************************************************************************/
644
645 JS_PUBLIC_API(JSRuntime *)
646 JS_NewRuntime(uint32 maxbytes)
647 16 {
648 16     JSRuntime *rt;
649
650 #ifdef DEBUG
651     JS_BEGIN_MACRO
652     /*
653      * This code asserts that the numbers associated with the error names in
654      * jsmsg.def are monotonically increasing.  It uses values for the error
655      * names enumerated in jscntxt.c.  It's not a compiletime check, but it's
656      * better than nothing.
657      */
658     int errorNumber = 0;
659 #define MSG_DEF(name, number, count, exception, format) \
660     JS_ASSERT(name == errorNumber++);
661 #include "js.msg"
662 #undef MSG_DEF
663     JS_END_MACRO;
664 #endif /* DEBUG */
665
666 16     if (!js_InitStringGlobals())
667 0         return NULL;
668 16     rt = (JSRuntime *) malloc(sizeof(JSRuntime));
669 16     if (!rt)
670 0         return NULL;
671
672     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
673 16     memset(rt, 0, sizeof(JSRuntime));
674 16     JS_INIT_CLIST(&rt->contextList);
675 16     JS_INIT_CLIST(&rt->trapList);
676 16     JS_INIT_CLIST(&rt->watchPointList);
677
678 16     if (!js_InitGC(rt, maxbytes))
679 0         goto bad;
680 #ifdef JS_THREADSAFE
681     rt->gcLock = JS_NEW_LOCK();
682     if (!rt->gcLock)
683         goto bad;
684     rt->gcDone = JS_NEW_CONDVAR(rt->gcLock);
685     if (!rt->gcDone)
686         goto bad;
687     rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
688     if (!rt->requestDone)
689         goto bad;
690     /* this is asymmetric with JS_ShutDown: */
691     if (!js_SetupLocks(8, 16))
692         goto bad;
693     rt->rtLock = JS_NEW_LOCK();
694     if (!rt->rtLock)
695         goto bad;
696     rt->stateChange = JS_NEW_CONDVAR(rt->gcLock);
697     if (!rt->stateChange)
698         goto bad;
699     rt->setSlotLock = JS_NEW_LOCK();
700     if (!rt->setSlotLock)
701         goto bad;
702     rt->setSlotDone = JS_NEW_CONDVAR(rt->setSlotLock);
703     if (!rt->setSlotDone)
704         goto bad;
705     rt->scopeSharingDone = JS_NEW_CONDVAR(rt->gcLock);
706     if (!rt->scopeSharingDone)
707         goto bad;
708     rt->scopeSharingTodo = NO_SCOPE_SHARING_TODO;
709 #endif
710 16     rt->propertyCache.empty = JS_TRUE;
711 16     if (!js_InitPropertyTree(rt))
712 0         goto bad;
713 16     return rt;
714
715 bad:
716 0     JS_DestroyRuntime(rt);
717 0     return NULL;
718 }
719
720 JS_PUBLIC_API(void)
721 JS_DestroyRuntime(JSRuntime *rt)
722 16 {
723 #ifdef DEBUG
724     /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
725     if (!JS_CLIST_IS_EMPTY(&rt->contextList)) {
726         JSContext *cx, *iter = NULL;
727         uintN cxcount = 0;
728         while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)
729             cxcount++;
730         fprintf(stderr,
731 "JS API usage error: %u contexts left in runtime upon JS_DestroyRuntime.\n",
732                 cxcount);
733     }
734 #endif
735
736 16     js_FreeRuntimeScriptState(rt);
737 16     js_FinishAtomState(&rt->atomState);
738 16     js_FinishGC(rt);
739 #ifdef JS_THREADSAFE
740     if (rt->gcLock)
741         JS_DESTROY_LOCK(rt->gcLock);
742     if (rt->gcDone)
743         JS_DESTROY_CONDVAR(rt->gcDone);
744     if (rt->requestDone)
745         JS_DESTROY_CONDVAR(rt->requestDone);
746     if (rt->rtLock)
747         JS_DESTROY_LOCK(rt->rtLock);
748     if (rt->stateChange)
749         JS_DESTROY_CONDVAR(rt->stateChange);
750     if (rt->setSlotLock)
751         JS_DESTROY_LOCK(rt->setSlotLock);
752     if (rt->setSlotDone)
753         JS_DESTROY_CONDVAR(rt->setSlotDone);
754     if (rt->scopeSharingDone)
755         JS_DESTROY_CONDVAR(rt->scopeSharingDone);
756 #endif
757 16     js_FinishPropertyTree(rt);
758 16     free(rt);
759 }
760
761 JS_PUBLIC_API(void)
762 JS_ShutDown(void)
763 0 {
764 0     JS_ArenaShutDown();
765 0     js_FinishDtoa();
766 0     js_FreeStringGlobals();
767 #ifdef JS_THREADSAFE
768     js_CleanupLocks();
769 #endif
770 }
771
772 JS_PUBLIC_API(void *)
773 JS_GetRuntimePrivate(JSRuntime *rt)
774 0 {
775 0     return rt->data;
776 }
777
778 JS_PUBLIC_API(void)
779 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
780 0 {
781 0     rt->data = data;
782 }
783
784 #ifdef JS_THREADSAFE
785
786 JS_PUBLIC_API(void)
787 JS_BeginRequest(JSContext *cx)
788 {
789     JSRuntime *rt;
790
791     JS_ASSERT(cx->thread);
792     if (!cx->requestDepth) {
793         /* Wait until the GC is finished. */
794         rt = cx->runtime;
795         JS_LOCK_GC(rt);
796
797         /* NB: we use cx->thread here, not js_CurrentThreadId(). */
798         if (rt->gcThread != cx->thread) {
799             while (rt->gcLevel > 0)
800                 JS_AWAIT_GC_DONE(rt);
801         }
802
803         /* Indicate that a request is running. */
804         rt->requestCount++;
805         cx->requestDepth = 1;
806         JS_UNLOCK_GC(rt);
807         return;
808     }
809     cx->requestDepth++;
810 }
811
812 JS_PUBLIC_API(void)
813 JS_EndRequest(JSContext *cx)
814 {
815     JSRuntime *rt;
816     JSScope *scope, **todop;
817     uintN nshares;
818
819     CHECK_REQUEST(cx);
820     JS_ASSERT(cx->requestDepth > 0);
821     if (cx->requestDepth == 1) {
822         /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
823         rt = cx->runtime;
824         JS_LOCK_GC(rt);
825         cx->requestDepth = 0;
826
827         /* See whether cx has any single-threaded scopes to start sharing. */
828         todop = &rt->scopeSharingTodo;
829         nshares = 0;
830         while ((scope = *todop) != NO_SCOPE_SHARING_TODO) {
831             if (scope->ownercx != cx) {
832                 todop = &scope->u.link;
833                 continue;
834             }
835             *todop = scope->u.link;
836             scope->u.link = NULL;       /* null u.link for sanity ASAP */
837
838             /*
839              * If js_DropObjectMap returns null, we held the last ref to scope.
840              * The waiting thread(s) must have been killed, after which the GC
841              * collected the object that held this scope.  Unlikely, because it
842              * requires that the GC ran (e.g., from a branch callback) during
843              * this request, but possible.
844              */
845             if (js_DropObjectMap(cx, &scope->map, NULL)) {
846                 js_InitLock(&scope->lock);
847                 scope->u.count = 0;                 /* NULL may not pun as 0 */
848                 js_FinishSharingScope(rt, scope);   /* set ownercx = NULL */
849                 nshares++;
850             }
851         }
852         if (nshares)
853             JS_NOTIFY_ALL_CONDVAR(rt->scopeSharingDone);
854
855         /* Give the GC a chance to run if this was the last request running. */
856         JS_ASSERT(rt->requestCount > 0);
857         rt->requestCount--;
858         if (rt->requestCount == 0)
859             JS_NOTIFY_REQUEST_DONE(rt);
860
861         JS_UNLOCK_GC(rt);
862         return;
863     }
864
865     cx->requestDepth--;
866 }
867
868 /* Yield to pending GC operations, regardless of request depth */
869 JS_PUBLIC_API(void)
870 JS_YieldRequest(JSContext *cx)
871 {
872     JSRuntime *rt;
873
874     JS_ASSERT(cx->thread);
875     CHECK_REQUEST(cx);
876
877     rt = cx->runtime;
878     JS_LOCK_GC(rt);
879     JS_ASSERT(rt->requestCount > 0);
880     rt->requestCount--;
881     if (rt->requestCount == 0)
882         JS_NOTIFY_REQUEST_DONE(rt);
883     JS_UNLOCK_GC(rt);
884     /* XXXbe give the GC or another request calling it a chance to run here?
885              Assumes FIFO scheduling */
886     JS_LOCK_GC(rt);
887     rt->requestCount++;
888     JS_UNLOCK_GC(rt);
889 }
890
891 JS_PUBLIC_API(jsrefcount)
892 JS_SuspendRequest(JSContext *cx)
893 {
894     jsrefcount saveDepth = cx->requestDepth;
895
896     while (cx->requestDepth)
897         JS_EndRequest(cx);
898     return saveDepth;
899 }
900
901 JS_PUBLIC_API(void)
902 JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
903 {
904     JS_ASSERT(!cx->requestDepth);
905     while (--saveDepth >= 0)
906         JS_BeginRequest(cx);
907 }
908
909 #endif /* JS_THREADSAFE */
910
911 JS_PUBLIC_API(void)
912 JS_Lock(JSRuntime *rt)
913 0 {
914 0     JS_LOCK_RUNTIME(rt);
915 }
916
917 JS_PUBLIC_API(void)
918 JS_Unlock(JSRuntime *rt)
919 0 {
920 0     JS_UNLOCK_RUNTIME(rt);
921 }
922
923 JS_PUBLIC_API(JSContext *)
924 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
925 16 {
926 16     return js_NewContext(rt, stackChunkSize);
927 }
928
929 JS_PUBLIC_API(void)
930 JS_DestroyContext(JSContext *cx)
931 16 {
932 16     js_DestroyContext(cx, JS_FORCE_GC);
933 }
934
935 JS_PUBLIC_API(void)
936 JS_DestroyContextNoGC(JSContext *cx)
937 0 {
938 0     js_DestroyContext(cx, JS_NO_GC);
939 }
940
941 JS_PUBLIC_API(void)
942 JS_DestroyContextMaybeGC(JSContext *cx)
943 0 {
944 0     js_DestroyContext(cx, JS_MAYBE_GC);
945 }
946
947 JS_PUBLIC_API(void *)
948 JS_GetContextPrivate(JSContext *cx)
949 318347 {
950 318347     return cx->data;
951 }
952
953 JS_PUBLIC_API(void)
954 JS_SetContextPrivate(JSContext *cx, void *data)
955 2430 {
956 2430     cx->data = data;
957 }
958
959 JS_PUBLIC_API(JSRuntime *)
960 JS_GetRuntime(JSContext *cx)
961 0 {
962 0     return cx->runtime;
963 }
964
965 JS_PUBLIC_API(JSContext *)
966 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
967 0 {
968 0     return js_ContextIterator(rt, JS_TRUE, iterp);
969 }
970
971 JS_PUBLIC_API(JSVersion)
972 JS_GetVersion(JSContext *cx)
973 0 {
974 0     return cx->version & JSVERSION_MASK;
975 }
976
977 JS_PUBLIC_API(JSVersion)
978 JS_SetVersion(JSContext *cx, JSVersion version)
979 0 {
980 0     JSVersion oldVersion;
981
982 0     JS_ASSERT(version != JSVERSION_UNKNOWN);
983 0     JS_ASSERT((version & ~JSVERSION_MASK) == 0);
984
985 0     oldVersion = cx->version & JSVERSION_MASK;
986 0     if (version == oldVersion)
987 0         return oldVersion;
988
989 0     cx->version = (cx->version & ~JSVERSION_MASK) | version;
990 0     js_OnVersionChange(cx);
991 0     return oldVersion;
992 }
993
994 static struct v2smap {
995     JSVersion   version;
996     const char  *string;
997 } v2smap[] = {
998     {JSVERSION_1_0,     "1.0"},
999     {JSVERSION_1_1,     "1.1"},
1000     {JSVERSION_1_2,     "1.2"},
1001     {JSVERSION_1_3,     "1.3"},
1002     {JSVERSION_1_4,     "1.4"},
1003     {JSVERSION_ECMA_3,  "ECMAv3"},
1004     {JSVERSION_1_5,     "1.5"},
1005     {JSVERSION_1_6,     "1.6"},
1006     {JSVERSION_DEFAULT, js_default_str},
1007     {JSVERSION_UNKNOWN, NULL},          /* must be last, NULL is sentinel */
1008 };
1009
1010 JS_PUBLIC_API(const char *)
1011 JS_VersionToString(JSVersion version)
1012 0 {
1013 0     int i;
1014
1015 0     for (i = 0; v2smap[i].string; i++)
1016 0         if (v2smap[i].version == version)
1017 0             return v2smap[i].string;
1018 0     return "unknown";
1019 }
1020
1021 JS_PUBLIC_API(JSVersion)
1022 JS_StringToVersion(const char *string)
1023 0 {
1024 0     int i;
1025
1026 0     for (i = 0; v2smap[i].string; i++)
1027 0         if (strcmp(v2smap[i].string, string) == 0)
1028 0             return v2smap[i].version;
1029 0     return JSVERSION_UNKNOWN;
1030 }
1031
1032 JS_PUBLIC_API(uint32)
1033 JS_GetOptions(JSContext *cx)
1034 0 {
1035 0     return cx->options;
1036 }
1037
1038 #define SYNC_OPTIONS_TO_VERSION(cx)                                           \
1039     JS_BEGIN_MACRO                                                            \
1040         if ((cx)->options & JSOPTION_XML)                                     \
1041             (cx)->version |= JSVERSION_HAS_XML;                               \
1042         else                                                                  \
1043             (cx)->version &= ~JSVERSION_HAS_XML;                              \
1044     JS_END_MACRO
1045
1046 JS_PUBLIC_API(uint32)
1047 JS_SetOptions(JSContext *cx, uint32 options)
1048 0 {
1049 0     uint32 oldopts = cx->options;
1050 0     cx->options = options;
1051 0     SYNC_OPTIONS_TO_VERSION(cx);
1052 0     return oldopts;
1053 }
1054
1055 JS_PUBLIC_API(uint32)
1056 JS_ToggleOptions(JSContext *cx, uint32 options)
1057 0 {
1058 0     uint32 oldopts = cx->options;
1059 0     cx->options ^= options;
1060 0     SYNC_OPTIONS_TO_VERSION(cx);
1061 0     return oldopts;
1062 }
1063
1064 JS_PUBLIC_API(const char *)
1065 JS_GetImplementationVersion(void)
1066 0 {
1067 0     return "JavaScript-C 1.6 2006-11-19";
1068 }
1069
1070
1071 JS_PUBLIC_API(JSObject *)
1072 JS_GetGlobalObject(JSContext *cx)
1073 63 {
1074 63     return cx->globalObject;
1075 }
1076
1077 JS_PUBLIC_API(void)
1078 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1079 16 {
1080 16     cx->globalObject = obj;
1081 #if JS_HAS_XML_SUPPORT
1082 16     cx->xmlSettingFlags = 0;
1083 #endif
1084 }
1085
1086 static JSObject *
1087 InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1088 16 {
1089 16     JSDHashTable *table;
1090 16     JSBool resolving;
1091 16     JSRuntime *rt;
1092 16     JSResolvingKey key;
1093 16     JSResolvingEntry *entry;
1094 16     JSObject *fun_proto, *obj_proto;
1095
1096     /* If cx has no global object, use obj so prototypes can be found. */
1097 16     if (!cx->globalObject)
1098 16         JS_SetGlobalObject(cx, obj);
1099
1100     /* Record Function and Object in cx->resolvingTable, if we are resolving. */
1101 16     table = cx->resolvingTable;
1102 16     resolving = (table && table->entryCount);
1103 16     if (resolving) {
1104 0         rt = cx->runtime;
1105 0         key.obj = obj;
1106 0         key.id = ATOM_TO_JSID(rt->atomState.FunctionAtom);
1107 0         entry = (JSResolvingEntry *)
1108                 JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1109 0         if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) {
1110             /* Already resolving Function, record Object too. */
1111 0             JS_ASSERT(entry->key.obj == obj);
1112 0             key.id = ATOM_TO_JSID(rt->atomState.ObjectAtom);
1113 0             entry = (JSResolvingEntry *)
1114                     JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1115         }
1116 0         if (!entry) {
1117 0             JS_ReportOutOfMemory(cx);
1118 0             return NULL;
1119         }
1120 0         JS_ASSERT(!entry->key.obj && entry->flags == 0);
1121 0         entry->key = key;
1122 0         entry->flags = JSRESFLAG_LOOKUP;
1123     }
1124
1125     /* Initialize the function class first so constructors can be made. */
1126 16     fun_proto = js_InitFunctionClass(cx, obj);
1127 16     if (!fun_proto)
1128 0         goto out;
1129
1130     /* Initialize the object class next so Object.prototype works. */
1131 16     obj_proto = js_InitObjectClass(cx, obj);
1132 16     if (!obj_proto) {
1133 0         fun_proto = NULL;
1134 0         goto out;
1135     }
1136
1137     /* Function.prototype and the global object delegate to Object.prototype. */
1138 16     OBJ_SET_PROTO(cx, fun_proto, obj_proto);
1139 16     if (!OBJ_GET_PROTO(cx, obj))
1140 16         OBJ_SET_PROTO(cx, obj, obj_proto);
1141
1142 out:
1143     /* If resolving, remove the other entry (Object or Function) from table. */
1144 16     if (resolving)
1145 0         JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1146 16     return fun_proto;
1147 }
1148
1149 JS_PUBLIC_API(JSBool)
1150 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1151 16 {
1152 16     CHECK_REQUEST(cx);
1153
1154 #if JS_HAS_UNDEFINED
1155 {
1156     /* Define a top-level property 'undefined' with the undefined value. */
1157 16     JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1158 16     if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1159                              NULL, NULL, JSPROP_PERMANENT, NULL)) {
1160 0         return JS_FALSE;
1161     }
1162 }
1163 #endif
1164
1165     /* Function and Object require cooperative bootstrapping magic. */
1166 16     if (!InitFunctionAndObjectClasses(cx, obj))
1167 0         return JS_FALSE;
1168
1169     /* Initialize the rest of the standard objects and functions. */
1170 16     return js_InitArrayClass(cx, obj) &&
1171            js_InitBooleanClass(cx, obj) &&
1172            js_InitMathClass(cx, obj) &&
1173            js_InitNumberClass(cx, obj) &&
1174            js_InitStringClass(cx, obj) &&
1175 #if JS_HAS_CALL_OBJECT
1176            js_InitCallClass(cx, obj) &&
1177 #endif
1178 #if JS_HAS_REGEXPS
1179            js_InitRegExpClass(cx, obj) &&
1180 #endif
1181 #if JS_HAS_SCRIPT_OBJECT
1182            js_InitScriptClass(cx, obj) &&
1183 #endif
1184 #if JS_HAS_ERROR_EXCEPTIONS
1185            js_InitExceptionClasses(cx, obj) &&
1186 #endif
1187 #if JS_HAS_XML_SUPPORT
1188            js_InitXMLClasses(cx, obj) &&
1189 #endif
1190 #if JS_HAS_FILE_OBJECT
1191            js_InitFileClass(cx, obj) &&
1192 #endif
1193            js_InitDateClass(cx, obj);
1194 }
1195
1196 #define ATOM_OFFSET(name)       offsetof(JSAtomState, name##Atom)
1197 #define OFFSET_TO_ATOM(rt,off)  (*(JSAtom **)((char*)&(rt)->atomState + (off)))
1198
1199 /*
1200  * Table of class initializers and their atom offsets in rt->atomState.
1201  * If you add a "standard" class, remember to update this table.
1202  */
1203 static struct {
1204     JSObjectOp  init;
1205     size_t      atomOffset;
1206 } standard_class_atoms[] = {
1207     {InitFunctionAndObjectClasses,  ATOM_OFFSET(Function)},
1208     {InitFunctionAndObjectClasses,  ATOM_OFFSET(Object)},
1209     {js_InitArrayClass,             ATOM_OFFSET(Array)},
1210     {js_InitBooleanClass,           ATOM_OFFSET(Boolean)},
1211     {js_InitDateClass,              ATOM_OFFSET(Date)},
1212     {js_InitMathClass,              ATOM_OFFSET(Math)},
1213     {js_InitNumberClass,            ATOM_OFFSET(Number)},
1214     {js_InitStringClass,            ATOM_OFFSET(String)},
1215 #if JS_HAS_CALL_OBJECT
1216     {js_InitCallClass,              ATOM_OFFSET(Call)},
1217 #endif
1218 #if JS_HAS_ERROR_EXCEPTIONS
1219     {js_InitExceptionClasses,       ATOM_OFFSET(Error)},
1220 #endif
1221 #if JS_HAS_REGEXPS
1222     {js_InitRegExpClass,            ATOM_OFFSET(RegExp)},
1223 #endif
1224 #if JS_HAS_SCRIPT_OBJECT
1225     {js_InitScriptClass,            ATOM_OFFSET(Script)},
1226 #endif
1227 #if JS_HAS_XML_SUPPORT
1228     {js_InitXMLClass,               ATOM_OFFSET(XML)},
1229     {js_InitNamespaceClass,         ATOM_OFFSET(Namespace)},
1230     {js_InitQNameClass,             ATOM_OFFSET(QName)},
1231 #endif
1232 #if JS_HAS_FILE_OBJECT
1233     {js_InitFileClass,              ATOM_OFFSET(File)},
1234 #endif
1235     {NULL,                          0}
1236 };
1237
1238 /*
1239  * Table of top-level function and constant names and their init functions.
1240  * If you add a "standard" global function or property, remember to update
1241  * this table.
1242  */
1243 typedef struct JSStdName {
1244     JSObjectOp  init;
1245     size_t      atomOffset;     /* offset of atom pointer in JSAtomState */
1246     const char  *name;          /* null if atom is pre-pinned, else name */
1247 } JSStdName;
1248
1249 static JSAtom *
1250 StdNameToAtom(JSContext *cx, JSStdName *stdn)
1251 0 {
1252 0     size_t offset;
1253 0     JSAtom *atom;
1254 0     const char *name;
1255
1256 0     offset = stdn->atomOffset;
1257 0     atom = OFFSET_TO_ATOM(cx->runtime, offset);
1258 0     if (!atom) {
1259 0         name = stdn->name;
1260 0         if (name) {
1261 0             atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1262 0             OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1263         }
1264     }
1265 0     return atom;
1266 }
1267
1268 #define EAGERLY_PINNED_ATOM(name)   ATOM_OFFSET(name), NULL
1269 #define LAZILY_PINNED_ATOM(name)    ATOM_OFFSET(lazy.name), js_##name##_str
1270
1271 static JSStdName standard_class_names[] = {
1272     /* ECMA requires that eval be a direct property of the global object. */
1273     {js_InitObjectClass,        EAGERLY_PINNED_ATOM(eval)},
1274
1275     /* Global properties and functions defined by the Number class. */
1276     {js_InitNumberClass,        LAZILY_PINNED_ATOM(NaN)},
1277     {js_InitNumberClass,        LAZILY_PINNED_ATOM(Infinity)},
1278     {js_InitNumberClass,        LAZILY_PINNED_ATOM(isNaN)},
1279     {js_InitNumberClass,        LAZILY_PINNED_ATOM(isFinite)},
1280     {js_InitNumberClass,        LAZILY_PINNED_ATOM(parseFloat)},
1281     {js_InitNumberClass,        LAZILY_PINNED_ATOM(parseInt)},
1282
1283     /* String global functions. */
1284     {js_InitStringClass,        LAZILY_PINNED_ATOM(escape)},
1285     {js_InitStringClass,        LAZILY_PINNED_ATOM(unescape)},
1286     {js_InitStringClass,        LAZILY_PINNED_ATOM(decodeURI)},
1287     {js_InitStringClass,        LAZILY_PINNED_ATOM(encodeURI)},
1288     {js_InitStringClass,        LAZILY_PINNED_ATOM(decodeURIComponent)},
1289     {js_InitStringClass,        LAZILY_PINNED_ATOM(encodeURIComponent)},
1290 #if JS_HAS_UNEVAL
1291     {js_InitStringClass,        LAZILY_PINNED_ATOM(uneval)},
1292 #endif
1293
1294     /* Exception constructors. */
1295 #if JS_HAS_ERROR_EXCEPTIONS
1296     {js_InitExceptionClasses,   EAGERLY_PINNED_ATOM(Error)},
1297     {js_InitExceptionClasses,   LAZILY_PINNED_ATOM(InternalError)},
1298     {js_InitExceptionClasses,   LAZILY_PINNED_ATOM(EvalError)},
1299     {js_InitExceptionClasses,   LAZILY_PINNED_ATOM(RangeError)},
1300     {js_InitExceptionClasses,   LAZILY_PINNED_ATOM(ReferenceError)},
1301     {js_InitExceptionClasses,   LAZILY_PINNED_ATOM(SyntaxError)},
1302     {js_InitExceptionClasses,   LAZILY_PINNED_ATOM(TypeError)},
1303     {js_InitExceptionClasses,   LAZILY_PINNED_ATOM(URIError)},
1304 #endif
1305
1306 #if JS_HAS_XML_SUPPORT
1307     {js_InitAnyNameClass,       LAZILY_PINNED_ATOM(AnyName)},
1308     {js_InitAttributeNameClass, LAZILY_PINNED_ATOM(AttributeName)},
1309     {js_InitXMLClass,           LAZILY_PINNED_ATOM(XMLList)},
1310     {js_InitXMLClass,           LAZILY_PINNED_ATOM(isXMLName)},
1311 #endif
1312
1313     {NULL,                      0, NULL}
1314 };
1315
1316 static JSStdName object_prototype_names[] = {
1317     /* Object.prototype properties (global delegates to Object.prototype). */
1318     {js_InitObjectClass,        EAGERLY_PINNED_ATOM(proto)},
1319     {js_InitObjectClass,        EAGERLY_PINNED_ATOM(parent)},
1320     {js_InitObjectClass,        EAGERLY_PINNED_ATOM(count)},
1321 #if JS_HAS_TOSOURCE
1322     {js_InitObjectClass,        EAGERLY_PINNED_ATOM(toSource)},
1323 #endif
1324     {js_InitObjectClass,        EAGERLY_PINNED_ATOM(toString)},
1325     {js_InitObjectClass,        EAGERLY_PINNED_ATOM(toLocaleString)},
1326     {js_InitObjectClass,        EAGERLY_PINNED_ATOM(valueOf)},
1327 #if JS_HAS_OBJ_WATCHPOINT
1328     {js_InitObjectClass,        LAZILY_PINNED_ATOM(watch)},
1329     {js_InitObjectClass,        LAZILY_PINNED_ATOM(unwatch)},
1330 #endif
1331 #if JS_HAS_NEW_OBJ_METHODS
1332     {js_InitObjectClass,        LAZILY_PINNED_ATOM(hasOwnProperty)},
1333     {js_InitObjectClass,        LAZILY_PINNED_ATOM(isPrototypeOf)},
1334     {js_InitObjectClass,        LAZILY_PINNED_ATOM(propertyIsEnumerable)},
1335 #endif
1336 #if JS_HAS_GETTER_SETTER
1337     {js_InitObjectClass,        LAZILY_PINNED_ATOM(defineGetter)},
1338     {js_InitObjectClass,        LAZILY_PINNED_ATOM(defineSetter)},
1339     {js_InitObjectClass,        LAZILY_PINNED_ATOM(lookupGetter)},
1340     {js_InitObjectClass,        LAZILY_PINNED_ATOM(lookupSetter)},
1341 #endif
1342
1343     {NULL,                      0, NULL}
1344 };
1345
1346 #undef EAGERLY_PINNED_ATOM
1347 #undef LAZILY_PINNED_ATOM
1348
1349 JS_PUBLIC_API(JSBool)
1350 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
1351                         JSBool *resolved)
1352 0 {
1353 0     JSString *idstr;
1354 0     JSRuntime *rt;
1355 0     JSAtom *atom;
1356 0     JSObjectOp init;
1357 0     uintN i;
1358
1359 0     CHECK_REQUEST(cx);
1360 0     *resolved = JS_FALSE;
1361
1362 0     if (!JSVAL_IS_STRING(id))
1363 0         return JS_TRUE;
1364 0     idstr = JSVAL_TO_STRING(id);
1365 0     rt = cx->runtime;
1366
1367 #if JS_HAS_UNDEFINED
1368     /* Check whether we're resolving 'undefined', and define it if so. */
1369 0     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1370 0     if (idstr == ATOM_TO_STRING(atom)) {
1371 0         *resolved = JS_TRUE;
1372 0         return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1373                                    NULL, NULL, JSPROP_PERMANENT, NULL);
1374     }
1375 #endif
1376
1377     /* Try for class constructors/prototypes named by well-known atoms. */
1378 0     init = NULL;
1379 0     for (i = 0; standard_class_atoms[i].init; i++) {
1380 0         atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1381 0         if (idstr == ATOM_TO_STRING(atom)) {
1382 0             init = standard_class_atoms[i].init;
1383 0             break;
1384         }
1385     }
1386
1387 0     if (!init) {
1388         /* Try less frequently used top-level functions and constants. */
1389 0         for (i = 0; standard_class_names[i].init; i++) {
1390 0             atom = StdNameToAtom(cx, &standard_class_names[i]);
1391 0             if (!atom)
1392 0                 return JS_FALSE;
1393 0             if (idstr == ATOM_TO_STRING(atom)) {
1394 0                 init = standard_class_names[i].init;
1395 0                 break;
1396             }
1397         }
1398
1399 0         if (!init && !OBJ_GET_PROTO(cx, obj)) {
1400             /*
1401              * Try even less frequently used names delegated from the global
1402              * object to Object.prototype, but only if the Object class hasn't
1403              * yet been initialized.
1404              */
1405 0             for (i = 0; object_prototype_names[i].init; i++) {
1406 0                 atom = StdNameToAtom(cx, &object_prototype_names[i]);
1407 0                 if (!atom)
1408 0                     return JS_FALSE;
1409 0                 if (idstr == ATOM_TO_STRING(atom)) {
1410 0                     init = standard_class_names[i].init;
1411 0                     break;
1412                 }
1413             }
1414         }
1415     }
1416
1417 0     if (init) {
1418 0         if (!init(cx, obj))
1419 0             return JS_FALSE;
1420 0         *resolved = JS_TRUE;
1421     }
1422 0     return JS_TRUE;
1423 }
1424
1425 static JSBool
1426 AlreadyHasOwnProperty(JSObject *obj, JSAtom *atom)
1427 0 {
1428 0     JS_ASSERT(OBJ_IS_NATIVE(obj));
1429 0     return SCOPE_GET_PROPERTY(OBJ_SCOPE(obj), ATOM_TO_JSID(atom)) != NULL;
1430 }
1431
1432 JS_PUBLIC_API(JSBool)
1433 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1434 0 {
1435 0     JSRuntime *rt;
1436 0     JSAtom *atom;
1437 0     uintN i;
1438
1439 0     CHECK_REQUEST(cx);
1440 0     rt = cx->runtime;
1441
1442 #if JS_HAS_UNDEFINED
1443     /* Check whether we need to bind 'undefined' and define it if so. */
1444 0     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1445 0     if (!AlreadyHasOwnProperty(obj, atom) &&
1446         !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1447                              NULL, NULL, JSPROP_PERMANENT, NULL)) {
1448 0         return JS_FALSE;
1449     }
1450 #endif
1451
1452     /* Initialize any classes that have not been resolved yet. */
1453 0     for (i = 0; standard_class_atoms[i].init; i++) {
1454 0         atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1455 0         if (!AlreadyHasOwnProperty(obj, atom) &&
1456             !standard_class_atoms[i].init(cx, obj)) {
1457 0             return JS_FALSE;
1458         }
1459     }
1460
1461 0     return JS_TRUE;
1462 }
1463
1464 static JSIdArray *
1465 AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1466 0 {
1467 0     jsint i, length;
1468     
1469 0     i = *ip;
1470 0     length = ida->length;
1471 0     if (i >= length) {
1472 0         ida = js_SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
1473 0         if (!ida)
1474 0             return NULL;
1475 0         JS_ASSERT(i < ida->length);
1476     }
1477 0     ida->vector[i] = ATOM_TO_JSID(atom);
1478 0     *ip = i + 1;
1479 0     return ida;
1480 }
1481
1482 static JSIdArray *
1483 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
1484                     jsint *ip, JSBool *foundp)
1485 0 {
1486 0     *foundp = AlreadyHasOwnProperty(obj, atom);
1487 0     if (*foundp)
1488 0         ida = AddAtomToArray(cx, atom, ida, ip);
1489 0     return ida;
1490 }
1491
1492 JS_PUBLIC_API(JSIdArray *)
1493 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
1494                                     JSIdArray *ida)
1495 0 {
1496 0     JSRuntime *rt;
1497 0     jsint i, j, k;
1498 0     JSAtom *atom;
1499 0     JSBool found;
1500 0     JSObjectOp init;
1501
1502 0     CHECK_REQUEST(cx);
1503 0     rt = cx->runtime;
1504 0     if (ida) {
1505 0         i = ida->length;
1506     } else {
1507 0         ida = js_NewIdArray(cx, 8);
1508 0         if (!ida)
1509 0             return NULL;
1510 0         i = 0;
1511     }
1512
1513 #if JS_HAS_UNDEFINED
1514     /* Check whether 'undefined' has been resolved and enumerate it if so. */
1515 0     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1516 0     ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1517 0     if (!ida)
1518 0         return NULL;
1519 #endif
1520
1521     /* Enumerate only classes that *have* been resolved. */
1522 0     for (j = 0; standard_class_atoms[j].init; j++) {
1523 0         atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
1524 0         ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1525 0         if (!ida)
1526 0             return NULL;
1527
1528 0         if (found) {
1529 0             init = standard_class_atoms[j].init;
1530
1531 0             for (k = 0; standard_class_names[k].init; k++) {
1532 0                 if (standard_class_names[k].init == init) {
1533 0                     atom = StdNameToAtom(cx, &standard_class_names[k]);
1534 0                     ida = AddAtomToArray(cx, atom, ida, &i);
1535 0                     if (!ida)
1536 0                         return NULL;
1537                 }
1538             }
1539
1540 0             if (init == js_InitObjectClass) {
1541 0                 for (k = 0; object_prototype_names[k].init; k++) {
1542 0                     atom = StdNameToAtom(cx, &object_prototype_names[k]);
1543 0                     ida = AddAtomToArray(cx, atom, ida, &i);
1544 0                     if (!ida)
1545 0                         return NULL;
1546                 }
1547             }
1548         }
1549     }
1550
1551     /* Trim to exact length via js_SetIdArrayLength. */
1552 0     return js_SetIdArrayLength(cx, ida, i);
1553 }
1554
1555 #undef ATOM_OFFSET
1556 #undef OFFSET_TO_ATOM
1557
1558 JS_PUBLIC_API(JSObject *)
1559 JS_GetScopeChain(JSContext *cx)
1560 0 {
1561 0     return cx->fp ? cx->fp->scopeChain : NULL;
1562 }
1563
1564 JS_PUBLIC_API(void *)
1565 JS_malloc(JSContext *cx, size_t nbytes)
1566 509156 {
1567 509156     void *p;
1568
1569 509156     JS_ASSERT(nbytes != 0);
1570 509156     if (nbytes == 0)
1571 0         nbytes = 1;
1572 509156     cx->runtime->gcMallocBytes += nbytes;
1573 509156     p = malloc(nbytes);
1574 509156     if (!p)
1575 0         JS_ReportOutOfMemory(cx);
1576 509156     return p;
1577 }
1578
1579 JS_PUBLIC_API(void *)
1580 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1581 82681 {
1582 82681     p = realloc(p, nbytes);
1583 82681     if (!p)
1584 0         JS_ReportOutOfMemory(cx);
1585 82681     return p;
1586 }
1587
1588 JS_PUBLIC_API(void)
1589 JS_free(JSContext *cx, void *p)
1590 571461 {
1591 571461     if (p)
1592 571461         free(p);
1593 }
1594
1595 JS_PUBLIC_API(char *)
1596 JS_strdup(JSContext *cx, const char *s)
1597 48 {
1598 48     size_t n;
1599 48     void *p;
1600
1601 48     n = strlen(s) + 1;
1602 48     p = JS_malloc(cx, n);
1603 48     if (!p)
1604 0         return NULL;
1605 48     return (char *)memcpy(p, s, n);
1606 }
1607
1608 JS_PUBLIC_API(jsdouble *)
1609 JS_NewDouble(JSContext *cx, jsdouble d)
1610 0 {
1611 0     CHECK_REQUEST(cx);
1612 0     return js_NewDouble(cx, d, 0);
1613 }
1614
1615 JS_PUBLIC_API(JSBool)
1616 JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
1617 0 {
1618 0     CHECK_REQUEST(cx);
1619 0     return js_NewDoubleValue(cx, d, rval);
1620 }
1621
1622 JS_PUBLIC_API(JSBool)
1623 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
1624 0 {
1625 0     CHECK_REQUEST(cx);
1626 0     return js_NewNumberValue(cx, d, rval);
1627 }
1628
1629 #undef JS_AddRoot
1630 JS_PUBLIC_API(JSBool)
1631 JS_AddRoot(JSContext *cx, void *rp)
1632 0 {
1633 0     CHECK_REQUEST(cx);
1634 0     return js_AddRoot(cx, rp, NULL);
1635 }
1636
1637 JS_PUBLIC_API(JSBool)
1638 JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name)
1639 0 {
1640 0     return js_AddRootRT(rt, rp, name);
1641 }
1642
1643 JS_PUBLIC_API(JSBool)
1644 JS_RemoveRoot(JSContext *cx, void *rp)
1645 0 {
1646 0     CHECK_REQUEST(cx);
1647 0     return js_RemoveRoot(cx->runtime, rp);
1648 }
1649
1650 JS_PUBLIC_API(JSBool)
1651 JS_RemoveRootRT(JSRuntime *rt, void *rp)
1652 0 {
1653 0     return js_RemoveRoot(rt, rp);
1654 }
1655
1656 JS_PUBLIC_API(JSBool)
1657 JS_AddNamedRoot(JSContext *cx, void *rp, const char *name)
1658 0 {
1659 0     CHECK_REQUEST(cx);
1660 0     return js_AddRoot(cx, rp, name);
1661 }
1662
1663 JS_PUBLIC_API(void)
1664 JS_ClearNewbornRoots(JSContext *cx)
1665 0 {
1666 0     uintN i;
1667
1668 0     for (i = 0; i < GCX_NTYPES; i++)
1669 0         cx->newborn[i] = NULL;
1670 0     cx->lastAtom = NULL;
1671 0     cx->lastInternalResult = JSVAL_NULL;
1672 }
1673
1674 JS_PUBLIC_API(JSBool)
1675 JS_EnterLocalRootScope(JSContext *cx)
1676 0 {
1677 0     CHECK_REQUEST(cx);
1678 0     return js_EnterLocalRootScope(cx);
1679 }
1680
1681 JS_PUBLIC_API(void)
1682 JS_LeaveLocalRootScope(JSContext *cx)
1683 0 {
1684 0     CHECK_REQUEST(cx);
1685 0     js_LeaveLocalRootScope(cx);
1686 }
1687
1688 JS_PUBLIC_API(void)
1689 JS_ForgetLocalRoot(JSContext *cx, void *thing)
1690 0 {
1691 0     CHECK_REQUEST(cx);
1692 0     js_ForgetLocalRoot(cx, (jsval) thing);
1693 }
1694
1695 #include "jshash.h" /* Added by JSIFY */
1696
1697 #ifdef DEBUG
1698
1699 typedef struct NamedRootDumpArgs {
1700     void (*dump)(const char *name, void *rp, void *data);
1701     void *data;
1702 } NamedRootDumpArgs;
1703
1704 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
1705 js_named_root_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
1706                      void *arg)
1707 {
1708     NamedRootDumpArgs *args = (NamedRootDumpArgs *) arg;
1709     JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
1710
1711     if (rhe->name)
1712         args->dump(rhe->name, rhe->root, args->data);
1713     return JS_DHASH_NEXT;
1714 }
1715
1716 JS_PUBLIC_API(void)
1717 JS_DumpNamedRoots(JSRuntime *rt,
1718                   void (*dump)(const char *name, void *rp, void *data),
1719                   void *data)
1720 {
1721     NamedRootDumpArgs args;
1722
1723     args.dump = dump;
1724     args.data = data;
1725     JS_DHashTableEnumerate(&rt->gcRootsHash, js_named_root_dumper, &args);
1726 }
1727
1728 #endif /* DEBUG */
1729
1730 typedef struct GCRootMapArgs {
1731     JSGCRootMapFun map;
1732     void *data;
1733 } GCRootMapArgs;
1734
1735 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
1736 js_gcroot_mapper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
1737                  void *arg)
1738 0 {
1739 0     GCRootMapArgs *args = (GCRootMapArgs *) arg;
1740 0     JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
1741 0     intN mapflags;
1742 0     JSDHashOperator op;
1743
1744 0     mapflags = args->map(rhe->root, rhe->name, args->data);
1745
1746 #if JS_MAP_GCROOT_NEXT == JS_DHASH_NEXT &&                                     \
1747     JS_MAP_GCROOT_STOP == JS_DHASH_STOP &&                                     \
1748     JS_MAP_GCROOT_REMOVE == JS_DHASH_REMOVE
1749     op = (JSDHashOperator)mapflags;
1750 #else
1751 0     op = JS_DHASH_NEXT;
1752 0     if (mapflags & JS_MAP_GCROOT_STOP)
1753 0         op |= JS_DHASH_STOP;
1754 0     if (mapflags & JS_MAP_GCROOT_REMOVE)
1755 0         op |= JS_DHASH_REMOVE;
1756 #endif
1757
1758 0     return op;
1759 }
1760
1761 JS_PUBLIC_API(uint32)
1762 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
1763 0 {
1764 0     GCRootMapArgs args;
1765 0     uint32 rv;
1766
1767 0     args.map = map;
1768 0     args.data = data;
1769 0     JS_LOCK_GC(rt);
1770 0     rv = JS_DHashTableEnumerate(&rt->gcRootsHash, js_gcroot_mapper, &args);
1771 0     JS_UNLOCK_GC(rt);
1772 0     return rv;
1773 }
1774
1775 JS_PUBLIC_API(JSBool)
1776 JS_LockGCThing(JSContext *cx, void *thing)
1777 0 {
1778 0     JSBool ok;
1779
1780 0     CHECK_REQUEST(cx);
1781 0     ok = js_LockGCThing(cx, thing);
1782 0     if (!ok)
1783 0         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_LOCK);
1784 0     return ok;
1785 }
1786
1787 JS_PUBLIC_API(JSBool)
1788 JS_LockGCThingRT(JSRuntime *rt, void *thing)
1789 0 {
1790 0     return js_LockGCThingRT(rt, thing);
1791 }
1792
1793 JS_PUBLIC_API(JSBool)
1794 JS_UnlockGCThing(JSContext *cx, void *thing)
1795 0 {
1796 0     JSBool ok;
1797
1798 0     CHECK_REQUEST(cx);
1799 0     ok = js_UnlockGCThingRT(cx->runtime, thing);
1800 0     if (!ok)
1801 0         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_UNLOCK);
1802 0     return ok;
1803 }
1804
1805 JS_PUBLIC_API(JSBool)
1806 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
1807 0 {
1808 0     return js_UnlockGCThingRT(rt, thing);
1809 }
1810
1811 JS_PUBLIC_API(void)
1812 JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg)
1813 6864 {
1814 6864     JS_ASSERT(cx->runtime->gcLevel > 0);
1815 #ifdef JS_THREADSAFE
1816     JS_ASSERT(cx->runtime->gcThread == js_CurrentThreadId());
1817 #endif
1818
1819 6864     GC_MARK(cx, thing, name, arg);
1820 }
1821
1822 JS_PUBLIC_API(void)
1823 JS_GC(JSContext *cx)
1824 0 {
1825     /* Don't nuke active arenas if executing or compiling. */
1826 0     if (cx->stackPool.current == &cx->stackPool.first)
1827 0         JS_FinishArenaPool(&cx->stackPool);
1828 0     if (cx->tempPool.current == &cx->tempPool.first)
1829 0         JS_FinishArenaPool(&cx->tempPool);
1830 0     js_ForceGC(cx, 0);
1831 }
1832
1833 JS_PUBLIC_API(void)
1834 JS_MaybeGC(JSContext *cx)
1835 0 {
1836 #ifdef WAY_TOO_MUCH_GC
1837     JS_GC(cx);
1838 #else
1839 0     JSRuntime *rt;
1840 0     uint32 bytes, lastBytes;
1841
1842 0     rt = cx->runtime;
1843 0     bytes = rt->gcBytes;
1844 0     lastBytes = rt->gcLastBytes;
1845 0     if ((bytes > 8192 && bytes > lastBytes + lastBytes / 2) ||
1846         rt->gcMallocBytes > rt->gcMaxMallocBytes) {
1847         /*
1848          * Run the GC if we have half again as many bytes of GC-things as
1849          * the last time we GC'd, or if we have malloc'd more bytes through
1850          * JS_malloc than we were told to allocate by JS_NewRuntime.
1851          */
1852 0         JS_GC(cx);
1853     }
1854 #endif
1855 }
1856
1857 JS_PUBLIC_API(JSGCCallback)
1858 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
1859 0 {
1860 0     return JS_SetGCCallbackRT(cx->runtime, cb);
1861 }
1862
1863 JS_PUBLIC_API(JSGCCallback)
1864 JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
1865 0 {
1866 0     JSGCCallback oldcb;
1867
1868 0     oldcb = rt->gcCallback;
1869 0     rt->gcCallback = cb;
1870 0     return oldcb;
1871 }
1872
1873 JS_PUBLIC_API(JSBool)
1874 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
1875 0 {
1876 0     JS_ASSERT(thing);
1877 0     return js_IsAboutToBeFinalized(cx, thing);
1878 }
1879
1880 JS_PUBLIC_API(void)
1881 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
1882 0 {
1883 0     switch (key) {
1884       case JSGC_MAX_BYTES:
1885 0         rt->gcMaxBytes = value;
1886 0         break;
1887       case JSGC_MAX_MALLOC_BYTES:
1888 0         rt->gcMaxMallocBytes = value;
1889         break;
1890     }
1891 }
1892
1893 JS_PUBLIC_API(intN)
1894 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
1895 0 {
1896 0     return js_ChangeExternalStringFinalizer(NULL, finalizer);
1897 }
1898
1899 JS_PUBLIC_API(intN)
1900 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
1901 0 {
1902 0     return js_ChangeExternalStringFinalizer(finalizer, NULL);
1903 }
1904
1905 JS_PUBLIC_API(JSString *)
1906 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
1907 0 {
1908 0     JSString *str;
1909
1910 0     CHECK_REQUEST(cx);
1911 0     JS_ASSERT(GCX_EXTERNAL_STRING <= type && type < (intN) GCX_NTYPES);
1912
1913 0     str = (JSString *) js_NewGCThing(cx, (uintN) type, sizeof(JSString));
1914 0     if (!str)
1915 0         return NULL;
1916 0     str->length = length;
1917 0     str->chars = chars;
1918 0     return str;
1919 }
1920
1921 JS_PUBLIC_API(intN)
1922 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
1923 0 {
1924 0     uint8 type = (uint8) (*js_GetGCThingFlags(str) & GCF_TYPEMASK);
1925
1926 0     if (type >= GCX_EXTERNAL_STRING)
1927 0         return (intN)type;
1928 0     JS_ASSERT(type == GCX_STRING || type == GCX_MUTABLE_STRING);
1929 0     return -1;
1930 }
1931
1932 JS_PUBLIC_API(void)
1933 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
1934 0 {
1935 #if JS_STACK_GROWTH_DIRECTION > 0
1936     if (limitAddr == 0)
1937         limitAddr = (jsuword)-1;
1938 #endif
1939 0     cx->stackLimit = limitAddr;
1940 }
1941
1942 /************************************************************************/
1943
1944 JS_PUBLIC_API(void)
1945 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
1946 45523 {
1947 45523     JS_free(cx, ida);
1948 }
1949
1950 JS_PUBLIC_API(JSBool)
1951 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
1952 0 {
1953 0     JSAtom *atom;
1954
1955 0     CHECK_REQUEST(cx);
1956 0     if (JSVAL_IS_INT(v)) {
1957 0         *idp = v;
1958     } else {
1959 0         atom = js_ValueToStringAtom(cx, v);
1960 0         if (!atom)
1961 0             return JS_FALSE;
1962 0         *idp = ATOM_TO_JSID(atom);
1963     }
1964 0     return JS_TRUE;
1965 }
1966
1967 JS_PUBLIC_API(JSBool)
1968 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
1969 0 {
1970 0     CHECK_REQUEST(cx);
1971 0     *vp = ID_TO_VALUE(id);
1972 0     return JS_TRUE;
1973 }
1974
1975 JS_PUBLIC_API(JSBool)
1976 JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
1977 260026 {
1978 260026     return JS_TRUE;
1979 }
1980
1981 JS_PUBLIC_API(JSBool)
1982 JS_EnumerateStub(JSContext *cx, JSObject *obj)
1983 45523 {
1984 45523     return JS_TRUE;
1985 }
1986
1987 JS_PUBLIC_API(JSBool)
1988 JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id)
1989 0 {
1990 0     return JS_TRUE;
1991 }
1992
1993 JS_PUBLIC_API(JSBool)
1994 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
1995 0 {
1996 #if JS_BUG_EAGER_TOSTRING
1997     if (type == JSTYPE_STRING)
1998         return JS_TRUE;
1999 #endif
2000 0     js_TryValueOf(cx, obj, type, vp);
2001 0     return JS_TRUE;
2002 }
2003
2004 JS_PUBLIC_API(void)
2005 JS_FinalizeStub(JSContext *cx, JSObject *obj)
2006 186094 {
2007 }
2008
2009 JS_PUBLIC_API(JSObject *)
2010 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
2011              JSClass *clasp, JSNative constructor, uintN nargs,
2012              JSPropertySpec *ps, JSFunctionSpec *fs,
2013              JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
2014 448 {
2015 448     JSAtom *atom;
2016 448     JSObject *proto, *ctor;
2017 448     JSTempValueRooter tvr;
2018 448     jsval cval, rval;
2019 448     JSBool named;
2020 448     JSFunction *fun;
2021
2022 448     CHECK_REQUEST(cx);
2023 448     atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
2024 448     if (!atom)
2025 0         return NULL;
2026
2027     /* Create a prototype object for this class. */
2028 448     proto = js_NewObject(cx, clasp, parent_proto, obj);
2029 448     if (!proto)
2030 0         return NULL;
2031
2032     /* After this point, control must exit via label bad or out. */
2033 448     JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(proto), &tvr);
2034
2035 448     if (!constructor) {
2036         /* Lacking a constructor, name the prototype (e.g., Math). */
2037 224         named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
2038                                     OBJECT_TO_JSVAL(proto),
2039                                     NULL, NULL, 0, NULL);
2040 224         if (!named)
2041 0             goto bad;
2042 224         ctor = proto;
2043     } else {
2044         /* Define the constructor function in obj's scope. */
2045 224         fun = js_DefineFunction(cx, obj, atom, constructor, nargs, 0);
2046 224         named = (fun != NULL);
2047 224         if (!fun)
2048 0             goto bad;
2049
2050         /*
2051          * Remember the class this function is a constructor for so that
2052          * we know to create an object of this class when we call the
2053          * constructor.
2054          */
2055 224         fun->clasp = clasp;
2056
2057         /*
2058          * Optionally construct the prototype object, before the class has
2059          * been fully initialized.  Allow the ctor to replace proto with a
2060          * different object, as is done for operator new -- and as at least
2061          * XML support requires.
2062          */
2063 224         ctor = fun->object;
2064 224         if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) {
2065 48             cval = OBJECT_TO_JSVAL(ctor);
2066 48             if (!js_InternalConstruct(cx, proto, cval, 0, NULL, &rval))
2067 0                 goto bad;
2068 48             if (!JSVAL_IS_PRIMITIVE(rval) && JSVAL_TO_OBJECT(rval) != proto)
2069 0                 proto = JSVAL_TO_OBJECT(rval);
2070         }
2071
2072         /* Connect constructor and prototype by named properties. */
2073 224         if (!js_SetClassPrototype(cx, ctor, proto,
2074                                   JSPROP_READONLY | JSPROP_PERMANENT)) {
2075 0             goto bad;
2076         }
2077
2078         /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
2079 224         if (OBJ_GET_CLASS(cx, ctor) == clasp) {
2080             /* XXXMLM - this fails in framesets that are writing over
2081              *           themselves!
2082              * JS_ASSERT(!OBJ_GET_PROTO(cx, ctor));
2083              */
2084 16             OBJ_SET_PROTO(cx, ctor, proto);
2085         }
2086     }
2087
2088     /* Add properties and methods to the prototype and the constructor. */
2089 448     if ((ps && !JS_DefineProperties(cx, proto, ps)) ||
2090         (fs && !JS_DefineFunctions(cx, proto, fs)) ||
2091         (static_ps && !JS_DefineProperties(cx, ctor, static_ps)) ||
2092         (static_fs && !JS_DefineFunctions(cx, ctor, static_fs))) {
2093 0         goto bad;
2094     }
2095
2096 out:
2097 448     JS_POP_TEMP_ROOT(cx, &tvr);
2098 448     return proto;
2099
2100 bad:
2101 0     if (named)
2102 0         (void) OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &rval);
2103 0     proto = NULL;
2104 0     goto out;
2105 }
2106
2107 #ifdef JS_THREADSAFE
2108 JS_PUBLIC_API(JSClass *)
2109 JS_GetClass(JSContext *cx, JSObject *obj)
2110 {
2111     return (JSClass *)
2112         JSVAL_TO_PRIVATE(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_CLASS));
2113 }
2114 #else
2115 JS_PUBLIC_API(JSClass *)
2116 JS_GetClass(JSObject *obj)
2117 0 {
2118 0     return LOCKED_OBJ_GET_CLASS(obj);
2119 }
2120 #endif
2121
2122 JS_PUBLIC_API(JSBool)
2123 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2124 205600 {
2125 205600     JSFunction *fun;
2126
2127 205600     CHECK_REQUEST(cx);
2128 205600     if (OBJ_GET_CLASS(cx, obj) == clasp)
2129 205600         return JS_TRUE;
2130 0     if (argv) {
2131 0         fun = js_ValueToFunction(cx, &argv[-2], 0);
2132 0         if (fun) {
2133 0             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2134                                  JSMSG_INCOMPATIBLE_PROTO,
2135                                  clasp->name, JS_GetFunctionName(fun),
2136                                  OBJ_GET_CLASS(cx, obj)->name);
2137         }
2138     }
2139 0     return JS_FALSE;
2140 }
2141
2142 JS_PUBLIC_API(JSBool)
2143 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
2144 0 {
2145 0     return js_HasInstance(cx, obj, v, bp);
2146 }
2147
2148 JS_PUBLIC_API(void *)
2149 JS_GetPrivate(JSContext *cx, JSObject *obj)
2150 1765709 {
2151 1765709     jsval v;
2152
2153 1765709     JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2154 1765709     v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
2155 1765709     if (!JSVAL_IS_INT(v))
2156 15418         return NULL;
2157 1750291     return JSVAL_TO_PRIVATE(v);
2158 }
2159
2160 JS_PUBLIC_API(JSBool)
2161 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2162 118074 {
2163 118074     JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2164 118074     OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(data));
2165 118074     return JS_TRUE;
2166 }
2167
2168 JS_PUBLIC_API(void *)
2169 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp,
2170                       jsval *argv)
2171 144384 {
2172 144384     if (!JS_InstanceOf(cx, obj, clasp, argv))
2173 0         return NULL;
2174 144384     return JS_GetPrivate(cx, obj);
2175 }
2176
2177 JS_PUBLIC_API(JSObject *)
2178 JS_GetPrototype(JSContext *cx, JSObject *obj)
2179 0 {
2180 0     JSObject *proto;
2181
2182 0     CHECK_REQUEST(cx);
2183 0     proto = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PROTO));
2184
2185     /* Beware ref to dead object (we may be called from obj's finalizer). */
2186 0     return proto && proto->map ? proto : NULL;
2187 }
2188
2189 JS_PUBLIC_API(JSBool)
2190 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
2191 0 {
2192 0     CHECK_REQUEST(cx);
2193 0     if (obj->map->ops->setProto)
2194 0         return obj->map->ops->setProto(cx, obj, JSSLOT_PROTO, proto);
2195 0     OBJ_SET_SLOT(cx, obj, JSSLOT_PROTO, OBJECT_TO_JSVAL(proto));
2196 0     return JS_TRUE;
2197 }
2198
2199 JS_PUBLIC_API(JSObject *)
2200 JS_GetParent(JSContext *cx, JSObject *obj)
2201 0 {
2202 0     JSObject *parent;
2203
2204 0     parent = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PARENT));
2205
2206     /* Beware ref to dead object (we may be called from obj's finalizer). */
2207 0     return parent && parent->map ? parent : NULL;
2208 }
2209
2210 JS_PUBLIC_API(JSBool)
2211 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
2212 0 {
2213 0     CHECK_REQUEST(cx);
2214 0     if (obj->map->ops->setParent)
2215 0         return obj->map->ops->setParent(cx, obj, JSSLOT_PARENT, parent);
2216 0     OBJ_SET_SLOT(cx, obj, JSSLOT_PARENT, OBJECT_TO_JSVAL(parent));
2217 0     return JS_TRUE;
2218 }
2219
2220 JS_PUBLIC_API(JSObject *)
2221 JS_GetConstructor(JSContext *cx, JSObject *proto)
2222 64 {
2223 64     jsval cval;
2224
2225 64     CHECK_REQUEST(cx);
2226 64     if (!OBJ_GET_PROPERTY(cx, proto,
2227                           ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
2228                           &cval)) {
2229 0         return NULL;
2230     }
2231 64     if (!JSVAL_IS_FUNCTION(cx, cval)) {
2232 0         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
2233                              OBJ_GET_CLASS(cx, proto)->name);
2234 0         return NULL;
2235     }
2236 64     return JSVAL_TO_OBJECT(cval);
2237 }
2238
2239 JS_PUBLIC_API(JSBool)
2240 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
2241 0 {
2242 0     JS_ASSERT(((jsid)obj & JSID_TAGMASK) == 0);
2243 0     *idp = OBJECT_TO_JSID(obj);
2244 0     return JS_TRUE;
2245 }
2246
2247 JS_PUBLIC_API(JSObject *)
2248 JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
2249 94336 {
2250 94336     CHECK_REQUEST(cx);
2251 94336     if (!clasp)
2252 0         clasp = &js_ObjectClass;    /* default class is Object */
2253 94336     return js_NewObject(cx, clasp, proto, parent);
2254 }
2255
2256 JS_PUBLIC_API(JSBool)
2257 JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
2258 0 {
2259 0     JSScope *scope;
2260 0     JSIdArray *ida;
2261 0     uint32 nslots;
2262 0     jsval v, *vp, *end;
2263
2264 0     if (!OBJ_IS_NATIVE(obj)) {
2265 0         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2266                              JSMSG_CANT_SEAL_OBJECT,
2267                              OBJ_GET_CLASS(cx, obj)->name);
2268 0         return JS_FALSE;
2269     }
2270
2271 0     scope = OBJ_SCOPE(obj);
2272
2273 #if defined JS_THREADSAFE && defined DEBUG
2274     /* Insist on scope being used exclusively by cx's thread. */
2275     if (scope->ownercx != cx) {
2276         JS_LOCK_OBJ(cx, obj);
2277         JS_ASSERT(OBJ_SCOPE(obj) == scope);
2278         JS_ASSERT(scope->ownercx == cx);
2279         JS_UNLOCK_SCOPE(cx, scope);
2280     }
2281 #endif
2282
2283     /* Nothing to do if obj's scope is already sealed. */
2284 0     if (SCOPE_IS_SEALED(scope))
2285 0         return JS_TRUE;
2286
2287     /* XXX Enumerate lazy properties now, as they can't be added later. */
2288 0     ida = JS_Enumerate(cx, obj);
2289 0     if (!ida)
2290 0         return JS_FALSE;
2291 0     JS_DestroyIdArray(cx, ida);
2292
2293     /* Ensure that obj has its own, mutable scope, and seal that scope. */
2294 0     JS_LOCK_OBJ(cx, obj);
2295 0     scope = js_GetMutableScope(cx, obj);
2296 0     if (scope)
2297 0         SCOPE_SET_SEALED(scope);
2298 0     JS_UNLOCK_SCOPE(cx, scope);
2299 0     if (!scope)
2300 0         return JS_FALSE;
2301
2302     /* If we are not sealing an entire object graph, we're done. */
2303 0     if (!deep)
2304 0         return JS_TRUE;
2305
2306     /* Walk obj->slots and if any value is a non-null object, seal it. */
2307 0     nslots = JS_MIN(scope->map.freeslot, scope->map.nslots);
2308 0     for (vp = obj->slots, end = vp + nslots; vp < end; vp++) {
2309 0         v = *vp;
2310 0         if (JSVAL_IS_PRIMITIVE(v))
2311 0             continue;
2312 0         if (!JS_SealObject(cx, JSVAL_TO_OBJECT(v), deep))
2313 0             return JS_FALSE;
2314     }
2315 0     return JS_TRUE;
2316 }
2317
2318 JS_PUBLIC_API(JSObject *)
2319 JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
2320                    JSObject *parent)
2321 0 {
2322 0     CHECK_REQUEST(cx);
2323 0     if (!clasp)
2324 0         clasp = &js_ObjectClass;    /* default class is Object */
2325 0     return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
2326 }
2327
2328 JS_PUBLIC_API(JSObject *)
2329 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto,
2330                                 JSObject *parent, uintN argc, jsval *argv)
2331 0 {
2332 0     CHECK_REQUEST(cx);
2333 0     if (!clasp)
2334 0         clasp = &js_ObjectClass;    /* default class is Object */
2335 0     return js_ConstructObject(cx, clasp, proto, parent, argc, argv);
2336 }
2337
2338 static JSBool
2339 DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
2340                JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
2341                uintN flags, intN tinyid)
2342 984561 {
2343 984561     jsid id;
2344 984561     JSAtom *atom;
2345
2346 984561     if (attrs & JSPROP_INDEX) {
2347 0         id = INT_TO_JSID(JS_PTR_TO_INT32(name));
2348 0         atom = NULL;
2349 0         attrs &= ~JSPROP_INDEX;
2350     } else {
2351 984561         atom = js_Atomize(cx, name, strlen(name), 0);
2352 984561         if (!atom)
2353 0             return JS_FALSE;
2354 984561         id = ATOM_TO_JSID(atom);
2355     }
2356 984561     if (flags != 0 && OBJ_IS_NATIVE(obj)) {
2357 972530         return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
2358                                        attrs, flags, tinyid, NULL);
2359     }
2360 12031     return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs,
2361                                NULL);
2362 }
2363
2364 #define AUTO_NAMELEN(s,n)   (((n) == (size_t)-1) ? js_strlen(s) : (n))
2365
2366 static JSBool
2367 DefineUCProperty(JSContext *cx, JSObject *obj,
2368                  const jschar *name, size_t namelen, jsval value,
2369                  JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
2370                  uintN flags, intN tinyid)
2371 0 {
2372 0     JSAtom *atom;
2373
2374 0     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2375 0     if (!atom)
2376 0         return JS_FALSE;
2377 0     if (flags != 0 && OBJ_IS_NATIVE(obj)) {
2378 0         return js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
2379                                        getter, setter, attrs, flags, tinyid,
2380                                        NULL);
2381     }
2382 0     return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), value,
2383                                getter, setter, attrs, NULL);
2384 }
2385
2386 JS_PUBLIC_API(JSObject *)
2387 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
2388                 JSObject *proto, uintN attrs)
2389 16 {
2390 16     JSObject *nobj;
2391
2392 16     CHECK_REQUEST(cx);
2393 16     if (!clasp)
2394 0         clasp = &js_ObjectClass;    /* default class is Object */
2395 16     nobj = js_NewObject(cx, clasp, proto, obj);
2396 16     if (!nobj)
2397 0         return NULL;
2398 16     if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs,
2399                         0, 0)) {
2400 0         cx->newborn[GCX_OBJECT] = NULL;
2401 0         return NULL;
2402     }
2403 16     return nobj;
2404 }
2405
2406 JS_PUBLIC_API(JSBool)
2407 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
2408 32 {
2409 32     JSBool ok;
2410 32     jsval value;
2411 32     uintN flags;
2412
2413 32     CHECK_REQUEST(cx);
2414 240     for (ok = JS_TRUE; cds->name; cds++) {
2415 208         ok = js_NewNumberValue(cx, cds->dval, &value);
2416 208         if (!ok)
2417 0             break;
2418 208         flags = cds->flags;
2419 208         if (!flags)
2420 208             flags = JSPROP_READONLY | JSPROP_PERMANENT;
2421 208         ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, flags, 0, 0);
2422 208         if (!ok)
2423 0             break;
2424     }
2425 32     return ok;
2426 }
2427
2428 JS_PUBLIC_API(JSBool)
2429 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
2430 52635 {
2431 52635     JSBool ok;
2432
2433 52635     CHECK_REQUEST(cx);
2434 1025165     for (ok = JS_TRUE; ps->name; ps++) {
2435 972530         ok = DefineProperty(cx, obj, ps->name, JSVAL_VOID,
2436                             ps->getter, ps->setter, ps->flags,
2437                             SPROP_HAS_SHORTID, ps->tinyid);
2438 972530         if (!ok)
2439 0             break;
2440     }
2441 52635     return ok;
2442 }
2443
2444 JS_PUBLIC_API(JSBool)
2445 JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
2446                   JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
2447 11807 {
2448 11807     CHECK_REQUEST(cx);
2449 11807     return DefineProperty(cx, obj, name, value, getter, setter, attrs, 0, 0);
2450 }
2451
2452 JS_PUBLIC_API(JSBool)
2453 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
2454                             int8 tinyid, jsval value,
2455                             JSPropertyOp getter, JSPropertyOp setter,
2456                             uintN attrs)
2457 0 {
2458 0     CHECK_REQUEST(cx);
2459 0     return DefineProperty(cx, obj, name, value, getter, setter, attrs,
2460                           SPROP_HAS_SHORTID, tinyid);
2461 }
2462
2463 static JSBool
2464 LookupProperty(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
2465                JSProperty **propp)
2466 112 {
2467 112     JSAtom *atom;
2468
2469 112     atom = js_Atomize(cx, name, strlen(name), 0);
2470 112     if (!atom)
2471 0         return JS_FALSE;
2472 112     return OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), objp, propp);
2473 }
2474
2475 static JSBool
2476 LookupUCProperty(JSContext *cx, JSObject *obj,
2477                  const jschar *name, size_t namelen,
2478                  JSObject **objp, JSProperty **propp)
2479 0 {
2480 0     JSAtom *atom;
2481
2482 0     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2483 0     if (!atom)
2484 0         return JS_FALSE;
2485 0     return OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), objp, propp);
2486 }
2487
2488 JS_PUBLIC_API(JSBool)
2489 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
2490                  const char *alias)
2491 112 {
2492 112     JSObject *obj2;
2493 112     JSProperty *prop;
2494 112     JSAtom *atom;
2495 112     JSBool ok;
2496 112     JSScopeProperty *sprop;
2497
2498 112     CHECK_REQUEST(cx);
2499 112     if (!LookupProperty(cx, obj, name, &obj2, &prop))
2500 0         return JS_FALSE;
2501 112     if (!prop) {
2502 0         js_ReportIsNotDefined(cx, name);
2503 0         return JS_FALSE;
2504     }
2505 112     if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
2506 0         OBJ_DROP_PROPERTY(cx, obj2, prop);
2507 0         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
2508                              alias, name, OBJ_GET_CLASS(cx, obj2)->name);
2509 0         return JS_FALSE;
2510     }
2511 112     atom = js_Atomize(cx, alias, strlen(alias), 0);
2512 112     if (!atom) {
2513 0         ok = JS_FALSE;
2514     } else {
2515 112         sprop = (JSScopeProperty *)prop;
2516 112         ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
2517                                    sprop->getter, sprop->setter, sprop->slot,
2518                                    sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
2519                                    sprop->shortid)
2520               != NULL);
2521     }
2522 112     OBJ_DROP_PROPERTY(cx, obj, prop);
2523 112     return ok;
2524 }
2525
2526 static jsval
2527 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop)
2528 0 {
2529 0     JSScopeProperty *sprop;
2530 0     jsval rval;
2531
2532 0     if (!prop) {
2533         /* XXX bad API: no way to tell "not defined" from "void value" */
2534 0         return JSVAL_VOID;
2535     }
2536 0     if (OBJ_IS_NATIVE(obj2)) {
2537         /* Peek at the native property's slot value, without doing a Get. */
2538 0         sprop = (JSScopeProperty *)prop;
2539 0         rval = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2))
2540                ? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot)
2541                : JSVAL_TRUE;
2542     } else {
2543         /* XXX bad API: no way to return "defined but value unknown" */
2544 0         rval = JSVAL_TRUE;
2545     }
2546 0     OBJ_DROP_PROPERTY(cx, obj2, prop);
2547 0     return rval;
2548 }
2549
2550 static JSBool
2551 GetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
2552                       uintN *attrsp, JSBool *foundp,
2553                       JSPropertyOp *getterp, JSPropertyOp *setterp)
2554 0 {
2555 0     JSObject *obj2;
2556 0     JSProperty *prop;
2557 0     JSBool ok;
2558
2559 0     if (!atom)
2560 0         return JS_FALSE;
2561 0     if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop))
2562 0         return JS_FALSE;
2563
2564 0     if (!prop || obj != obj2) {
2565 0         *attrsp = 0;
2566 0         *foundp = JS_FALSE;
2567 0         if (getterp)
2568 0             *getterp = NULL;
2569 0         if (setterp)
2570 0             *setterp = NULL;
2571 0         if (prop)
2572 0             OBJ_DROP_PROPERTY(cx, obj2, prop);
2573 0         return JS_TRUE;
2574     }
2575
2576 0     *foundp = JS_TRUE;
2577 0     ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, attrsp);
2578 0     if (ok && OBJ_IS_NATIVE(obj)) {
2579 0         JSScopeProperty *sprop = (JSScopeProperty *) prop;
2580
2581 0         if (getterp)
2582 0             *getterp = sprop->getter;
2583 0         if (setterp)
2584 0             *setterp = sprop->setter;
2585     }
2586 0     OBJ_DROP_PROPERTY(cx, obj, prop);
2587 0     return ok;
2588 }
2589
2590 static JSBool
2591 SetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
2592                       uintN attrs, JSBool *foundp)
2593 0 {
2594 0     JSObject *obj2;
2595 0     JSProperty *prop;
2596 0     JSBool ok;
2597
2598 0     if (!atom)
2599 0         return JS_FALSE;
2600 0     if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop))
2601 0         return JS_FALSE;
2602 0     if (!prop || obj != obj2) {
2603 0         *foundp = JS_FALSE;
2604 0         if (prop)
2605 0             OBJ_DROP_PROPERTY(cx, obj2, prop);
2606 0         return JS_TRUE;
2607     }
2608
2609 0     *foundp = JS_TRUE;
2610 0     ok = OBJ_SET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs);
2611 0     OBJ_DROP_PROPERTY(cx, obj, prop);
2612 0     return ok;
2613 }
2614
2615 JS_PUBLIC_API(JSBool)
2616 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
2617                          uintN *attrsp, JSBool *foundp)
2618 0 {
2619 0     CHECK_REQUEST(cx);
2620 0     return GetPropertyAttributes(cx, obj,
2621                                  js_Atomize(cx, name, strlen(name), 0),
2622                                  attrsp, foundp, NULL, NULL);
2623 }
2624
2625 JS_PUBLIC_API(JSBool)
2626 JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
2627                                    const char *name,
2628                                    uintN *attrsp, JSBool *foundp,
2629                                    JSPropertyOp *getterp,
2630                                    JSPropertyOp *setterp)
2631 0 {
2632 0     CHECK_REQUEST(cx);
2633 0     return GetPropertyAttributes(cx, obj,
2634                                  js_Atomize(cx, name, strlen(name), 0),
2635                                  attrsp, foundp, getterp, setterp);
2636 }
2637
2638 JS_PUBLIC_API(JSBool)
2639 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
2640                          uintN attrs, JSBool *foundp)
2641 0 {
2642 0     CHECK_REQUEST(cx);
2643 0     return SetPropertyAttributes(cx, obj,
2644                                  js_Atomize(cx, name, strlen(name), 0),
2645                                  attrs, foundp);
2646 }
2647
2648 JS_PUBLIC_API(JSBool)
2649 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
2650 0 {
2651 0     JSBool ok;
2652 0     JSObject *obj2;
2653 0     JSProperty *prop;
2654
2655 0     CHECK_REQUEST(cx);
2656 0     ok = LookupProperty(cx, obj, name, &obj2, &prop);
2657 0     if (ok) {
2658 0         *foundp = (prop != NULL);
2659 0         if (prop)
2660 0             OBJ_DROP_PROPERTY(cx, obj2, prop);
2661     }
2662 0     return ok;
2663 }
2664
2665 JS_PUBLIC_API(JSBool)
2666 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2667 0 {
2668 0     JSBool ok;
2669 0     JSObject *obj2;
2670 0     JSProperty *prop;
2671
2672 0     CHECK_REQUEST(cx);
2673 0     ok = LookupProperty(cx, obj, name, &obj2, &prop);
2674 0     if (ok)
2675 0         *vp = LookupResult(cx, obj, obj2, prop);
2676 0     return ok;
2677 }
2678
2679 JS_PUBLIC_API(JSBool)
2680 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name,
2681                            uintN flags, jsval *vp)
2682 0 {
2683 0     JSAtom *atom;
2684 0     JSBool ok;
2685 0     JSObject *obj2;
2686 0     JSProperty *prop;
2687
2688 0     CHECK_REQUEST(cx);
2689 0     atom = js_Atomize(cx, name, strlen(name), 0);
2690 0     if (!atom)
2691 0         return JS_FALSE;
2692 0     ok = OBJ_IS_NATIVE(obj)
2693          ? js_LookupPropertyWithFlags(cx, obj, ATOM_TO_JSID(atom), flags,
2694                                       &obj2, &prop)
2695          : OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop);
2696 0     if (ok)
2697 0         *vp = LookupResult(cx, obj, obj2, prop);
2698 0     return ok;
2699 }
2700
2701 JS_PUBLIC_API(JSBool)
2702 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2703 646 {
2704 646     JSAtom *atom;
2705
2706 646     CHECK_REQUEST(cx);
2707 646     atom = js_Atomize(cx, name, strlen(name), 0);
2708 646     if (!atom)
2709 0         return JS_FALSE;
2710 646     return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2711 }
2712
2713 JS_PUBLIC_API(JSBool)
2714 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
2715              jsval *vp)
2716 0 {
2717 0     JSAtom *atom;
2718 0     jsid id;
2719
2720 0     CHECK_REQUEST(cx);
2721 0     atom = js_Atomize(cx, name, strlen(name), 0);
2722 0     if (!atom)
2723 0         return JS_FALSE;
2724 0     id = ATOM_TO_JSID(atom);
2725
2726 #if JS_HAS_XML_SUPPORT
2727 0     if (OBJECT_IS_XML(cx, obj)) {
2728 0         JSXMLObjectOps *ops;
2729
2730 0         ops = (JSXMLObjectOps *) obj->map->ops;
2731 0         obj = ops->getMethod(cx, obj, id, vp);
2732 0         if (!obj)
2733 0             return JS_FALSE;
2734     } else
2735 #endif
2736     {
2737 0         if (!OBJ_GET_PROPERTY(cx, obj, id, vp))
2738 0             return JS_FALSE;
2739     }
2740
2741 0     *objp = obj;
2742 0     return JS_TRUE;
2743 }
2744
2745 JS_PUBLIC_API(JSBool)
2746 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2747 176 {
2748 176     JSAtom *atom;
2749
2750 176     CHECK_REQUEST(cx);
2751 176     atom = js_Atomize(cx, name, strlen(name), 0);
2752 176     if (!atom)
2753 0         return JS_FALSE;
2754 176     return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2755 }
2756
2757 JS_PUBLIC_API(JSBool)
2758 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
2759 0 {
2760 0     jsval junk;
2761
2762 0     CHECK_REQUEST(cx);
2763 0     return JS_DeleteProperty2(cx, obj, name, &junk);
2764 }
2765
2766 JS_PUBLIC_API(JSBool)
2767 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name,
2768                    jsval *rval)
2769 0 {
2770 0     JSAtom *atom;
2771
2772 0     CHECK_REQUEST(cx);
2773 0     atom = js_Atomize(cx, name, strlen(name), 0);
2774 0     if (!atom)
2775 0         return JS_FALSE;
2776 0     return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
2777 }
2778
2779 JS_PUBLIC_API(JSBool)
2780 JS_DefineUCProperty(JSContext *cx, JSObject *obj,
2781                     const jschar *name, size_t namelen, jsval value,
2782                     JSPropertyOp getter, JSPropertyOp setter,
2783                     uintN attrs)
2784 0 {
2785 0     CHECK_REQUEST(cx);
2786 0     return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
2787                             attrs, 0, 0);
2788 }
2789
2790 JS_PUBLIC_API(JSBool)
2791 JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj,
2792                            const jschar *name, size_t namelen,
2793                            uintN *attrsp, JSBool *foundp)
2794 0 {
2795 0     CHECK_REQUEST(cx);
2796 0     return GetPropertyAttributes(cx, obj,
2797                     js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2798                     attrsp, foundp, NULL, NULL);
2799 }
2800
2801 JS_PUBLIC_API(JSBool)
2802 JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
2803                                      const jschar *name, size_t namelen,
2804                                      uintN *attrsp, JSBool *foundp,
2805                                      JSPropertyOp *getterp,
2806                                      JSPropertyOp *setterp)
2807 0 {
2808 0     CHECK_REQUEST(cx);
2809 0     return GetPropertyAttributes(cx, obj,
2810                     js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2811                     attrsp, foundp, getterp, setterp);
2812 }
2813
2814 JS_PUBLIC_API(JSBool)
2815 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj,
2816                            const jschar *name, size_t namelen,
2817                            uintN attrs, JSBool *foundp)
2818 0 {
2819 0     CHECK_REQUEST(cx);
2820 0     return SetPropertyAttributes(cx, obj,
2821                     js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2822                     attrs, foundp);
2823 }
2824
2825 JS_PUBLIC_API(JSBool)
2826 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
2827                               const jschar *name, size_t namelen,
2828                               int8 tinyid, jsval value,
2829                               JSPropertyOp getter, JSPropertyOp setter,
2830                               uintN attrs)
2831 0 {
2832 0     CHECK_REQUEST(cx);
2833 0     return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
2834                             attrs, SPROP_HAS_SHORTID, tinyid);
2835 }
2836
2837 JS_PUBLIC_API(JSBool)
2838 JS_HasUCProperty(JSContext *cx, JSObject *obj,
2839                  const jschar *name, size_t namelen,
2840                  JSBool *vp)
2841 0 {
2842 0     JSBool ok;
2843 0     JSObject *obj2;
2844 0     JSProperty *prop;
2845
2846 0     CHECK_REQUEST(cx);
2847 0     ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop);
2848 0     if (ok) {
2849 0         *vp = (prop != NULL);
2850 0         if (prop)
2851 0             OBJ_DROP_PROPERTY(cx, obj2, prop);
2852     }
2853 0     return ok;
2854 }
2855
2856 JS_PUBLIC_API(JSBool)
2857 JS_LookupUCProperty(JSContext *cx, JSObject *obj,
2858                     const jschar *name, size_t namelen,
2859                     jsval *vp)
2860 0 {
2861 0     JSBool ok;
2862 0     JSObject *obj2;
2863 0     JSProperty *prop;
2864
2865 0     CHECK_REQUEST(cx);
2866 0     ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop);
2867 0     if (ok)
2868 0         *vp = LookupResult(cx, obj, obj2, prop);
2869 0     return ok;
2870 }
2871
2872 JS_PUBLIC_API(JSBool)
2873 JS_GetUCProperty(JSContext *cx, JSObject *obj,
2874                  const jschar *name, size_t namelen,
2875                  jsval *vp)
2876 0 {
2877 0     JSAtom *atom;
2878
2879 0     CHECK_REQUEST(cx);
2880 0     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2881 0     if (!atom)
2882 0         return JS_FALSE;
2883 0     return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2884 }
2885
2886 JS_PUBLIC_API(JSBool)
2887 JS_SetUCProperty(JSContext *cx, JSObject *obj,
2888                  const jschar *name, size_t namelen,
2889                  jsval *vp)
2890 0 {
2891 0     JSAtom *atom;
2892
2893 0     CHECK_REQUEST(cx);
2894 0     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2895 0     if (!atom)
2896 0         return JS_FALSE;
2897 0     return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2898 }
2899
2900 JS_PUBLIC_API(JSBool)
2901 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
2902                      const jschar *name, size_t namelen,
2903                      jsval *rval)
2904 0 {
2905 0     JSAtom *atom;
2906
2907 0     CHECK_REQUEST(cx);
2908 0     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2909 0     if (!atom)
2910 0         return JS_FALSE;
2911 0     return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
2912 }
2913
2914 JS_PUBLIC_API(JSObject *)
2915 JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
2916 0 {
2917 0     CHECK_REQUEST(cx);
2918     /* NB: jsuint cast does ToUint32. */
2919 0     return js_NewArrayObject(cx, (jsuint)length, vector);
2920 }
2921
2922 JS_PUBLIC_API(JSBool)
2923 JS_IsArrayObject(JSContext *cx, JSObject *obj)
2924 0 {
2925 0     return OBJ_GET_CLASS(cx, obj) == &js_ArrayClass;
2926 }
2927
2928 JS_PUBLIC_API(JSBool)
2929 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
2930 0 {
2931 0     CHECK_REQUEST(cx);
2932 0     return js_GetLengthProperty(cx, obj, lengthp);
2933 }
2934
2935 JS_PUBLIC_API(JSBool)
2936 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
2937 0 {
2938 0     CHECK_REQUEST(cx);
2939 0     return js_SetLengthProperty(cx, obj, length);
2940 }
2941
2942 JS_PUBLIC_API(JSBool)
2943 JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
2944 0 {
2945 0     CHECK_REQUEST(cx);
2946 0     return js_HasLengthProperty(cx, obj, lengthp);
2947 }
2948
2949 JS_PUBLIC_API(JSBool)
2950 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
2951                  JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
2952 44269 {
2953 44269     CHECK_REQUEST(cx);
2954 44269     return OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(index), value,
2955                                getter, setter, attrs, NULL);
2956 }
2957
2958 JS_PUBLIC_API(JSBool)
2959 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
2960 0 {
2961 0     JSObject *obj2;
2962 0     JSProperty *prop;
2963 0     JSScopeProperty *sprop;
2964 0     JSBool ok;
2965
2966 0     CHECK_REQUEST(cx);
2967 0     if (!LookupProperty(cx, obj, name, &obj2, &prop))
2968 0         return JS_FALSE;
2969 0     if (!prop) {
2970 0         js_ReportIsNotDefined(cx, name);
2971 0         return JS_FALSE;
2972     }
2973 0     if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
2974 0         char numBuf[12];
2975 0         OBJ_DROP_PROPERTY(cx, obj2, prop);
2976 0         JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
2977 0         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
2978                              numBuf, name, OBJ_GET_CLASS(cx, obj2)->name);
2979 0         return JS_FALSE;
2980     }
2981 0     sprop = (JSScopeProperty *)prop;
2982 0     ok = (js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
2983                                sprop->getter, sprop->setter, sprop->slot,
2984                                sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
2985                                sprop->shortid)
2986           != NULL);
2987 0     OBJ_DROP_PROPERTY(cx, obj, prop);
2988 0     return ok;
2989 }
2990
2991 JS_PUBLIC_API(JSBool)
2992 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
2993 0 {
2994 0     JSBool ok;
2995 0     JSObject *obj2;
2996 0     JSProperty *prop;
2997
2998 0     CHECK_REQUEST(cx);
2999 0     ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSID(index), &obj2, &prop);
3000 0     if (ok) {
3001 0         *foundp = (prop != NULL);
3002 0         if (prop)
3003 0             OBJ_DROP_PROPERTY(cx, obj2, prop);
3004     }
3005 0     return ok;
3006 }
3007
3008 JS_PUBLIC_API(JSBool)
3009 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3010 0 {
3011 0     JSBool ok;
3012 0     JSObject *obj2;
3013 0     JSProperty *prop;
3014
3015 0     CHECK_REQUEST(cx);
3016 0     ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSID(index), &obj2, &prop);
3017 0     if (ok)
3018 0         *vp = LookupResult(cx, obj, obj2, prop);
3019 0     return ok;
3020 }
3021
3022 JS_PUBLIC_API(JSBool)
3023 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3024 0 {
3025 0     CHECK_REQUEST(cx);
3026 0     return OBJ_GET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
3027 }
3028
3029 JS_PUBLIC_API(JSBool)
3030 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3031 162 {
3032 162     CHECK_REQUEST(cx);
3033 162     return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
3034 }
3035
3036 JS_PUBLIC_API(JSBool)
3037 JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
3038 0 {
3039 0     jsval junk;
3040
3041 0     CHECK_REQUEST(cx);
3042 0     return JS_DeleteElement2(cx, obj, index, &junk);
3043 }
3044
3045 JS_PUBLIC_API(JSBool)
3046 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
3047 0 {
3048 0     CHECK_REQUEST(cx);
3049 0     return OBJ_DELETE_PROPERTY(cx, obj, INT_TO_JSID(index), rval);
3050 }
3051
3052 JS_PUBLIC_API(void)
3053 JS_ClearScope(JSContext *cx, JSObject *obj)
3054 0 {
3055 0     CHECK_REQUEST(cx);
3056
3057 0     if (obj->map->ops->clear)
3058 0         obj->map->ops->clear(cx, obj);
3059 }
3060
3061 JS_PUBLIC_API(JSIdArray *)
3062 JS_Enumerate(JSContext *cx, JSObject *obj)
3063 0 {
3064 0     jsint i, n;
3065 0     jsval iter_state, num_properties;
3066 0     jsid id;
3067 0     JSIdArray *ida;
3068 0     jsval *vector;
3069
3070 0     CHECK_REQUEST(cx);
3071
3072 0     ida = NULL;
3073 0     iter_state = JSVAL_NULL;
3074
3075     /* Get the number of properties to enumerate. */
3076 0     if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, &num_properties))
3077 0         goto error;
3078 0     if (!JSVAL_IS_INT(num_properties)) {
3079 0         JS_ASSERT(0);
3080 0         goto error;
3081     }
3082
3083     /* Grow as needed if we don't know the exact amount ahead of time. */
3084 0     n = JSVAL_TO_INT(num_properties);
3085 0     if (n <= 0)
3086 0         n = 8;
3087
3088     /* Create an array of jsids large enough to hold all the properties */
3089 0     ida = js_NewIdArray(cx, n);
3090 0     if (!ida)
3091 0         goto error;
3092
3093 0     i = 0;
3094 0     vector = &ida->vector[0];
3095 0     for (;;) {
3096 0         if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &id))
3097 0             goto error;
3098
3099         /* No more jsid's to enumerate ? */
3100 0         if (iter_state == JSVAL_NULL)
3101 0             break;
3102
3103 0         if (i == ida->length) {
3104 0             ida = js_SetIdArrayLength(cx, ida, ida->length * 2);
3105 0             if (!ida)
3106 0                 goto error;
3107 0             vector = &ida->vector[0];
3108         }
3109 0         vector[i++] = id;
3110     }
3111 0     return js_SetIdArrayLength(cx, ida, i);
3112
3113 error:
3114 0     if (iter_state != JSVAL_NULL)
3115 0         OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0);
3116 0     if (ida)
3117 0         JS_DestroyIdArray(cx, ida);
3118 0     return NULL;
3119 }
3120
3121 /*
3122  * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
3123  *     prop_iterator_class somehow...
3124  * + preserve the OBJ_ENUMERATE API while optimizing the native object case
3125  * + native case here uses a JSScopeProperty *, but that iterates in reverse!
3126  * + so we make non-native match, by reverse-iterating after JS_Enumerating
3127  */
3128 #define JSSLOT_ITER_INDEX       (JSSLOT_PRIVATE + 1)
3129
3130 #if JSSLOT_ITER_INDEX >= JS_INITIAL_NSLOTS
3131 # error "JSSLOT_ITER_INDEX botch!"
3132 #endif
3133
3134 static void
3135 prop_iter_finalize(JSContext *cx, JSObject *obj)
3136 0 {
3137 0     jsval v;
3138 0     jsint i;
3139 0     JSIdArray *ida;
3140
3141 0     v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_ITER_INDEX);
3142 0     if (JSVAL_IS_VOID(v))
3143 0         return;
3144
3145 0     i = JSVAL_TO_INT(v);
3146 0     if (i >= 0) {
3147         /* Non-native case: destroy the ida enumerated when obj was created. */
3148 0         ida = (JSIdArray *) JS_GetPrivate(cx, obj);
3149 0         if (ida)
3150 0             JS_DestroyIdArray(cx, ida);
3151     }
3152 }
3153
3154 static uint32
3155 prop_iter_mark(JSContext *cx, JSObject *obj, void *arg)
3156 0 {
3157 0     jsval v;
3158 0     jsint i, n;
3159 0     JSScopeProperty *sprop;
3160 0     JSIdArray *ida;
3161 0     jsid id;
3162
3163 0     v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
3164 0     JS_ASSERT(!JSVAL_IS_VOID(v));
3165
3166 0     i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_INDEX));
3167 0     if (i < 0) {
3168         /* Native case: just mark the next property to visit. */
3169 0         sprop = (JSScopeProperty *) JSVAL_TO_PRIVATE(v);
3170 0         if (sprop)
3171 0             MARK_SCOPE_PROPERTY(sprop);
3172     } else {
3173         /* Non-native case: mark each id in the JSIdArray private. */
3174 0         ida = (JSIdArray *) JSVAL_TO_PRIVATE(v);
3175 0         for (i = 0, n = ida->length; i < n; i++) {
3176 0             id = ida->vector[i];
3177 0             if (JSID_IS_ATOM(id))
3178 0                 GC_MARK_ATOM(cx, JSID_TO_ATOM(id), arg);
3179 0             else if (JSID_IS_OBJECT(id))
3180 0                 GC_MARK(cx, JSID_TO_OBJECT(id), "id", arg);
3181         }
3182     }
3183 0     return 0;
3184 }
3185
3186 static JSClass prop_iter_class = {
3187     "PropertyIterator",
3188     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1),
3189     JS_PropertyStub,  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
3190     JS_EnumerateStub, JS_ResolveStub,  JS_ConvertStub,  prop_iter_finalize,
3191     NULL,             NULL,            NULL,            NULL,
3192     NULL,             NULL,            prop_iter_mark,  NULL
3193 };
3194
3195 JS_PUBLIC_API(JSObject *)
3196 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
3197 0 {
3198 0     JSObject *iterobj;
3199 0     JSScope *scope;
3200 0     void *pdata;
3201 0     jsint index;
3202 0     JSIdArray *ida;
3203     
3204 0     CHECK_REQUEST(cx);
3205 0     iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj);
3206 0     if (!iterobj)
3207 0         return NULL;
3208
3209 0     if (OBJ_IS_NATIVE(obj)) {
3210         /* Native case: start with the last property in obj's own scope. */
3211 0         scope = OBJ_SCOPE(obj);
3212 0         pdata = (scope->object == obj) ? scope->lastProp : NULL;
3213 0         index = -1;
3214     } else {
3215 0         JSTempValueRooter tvr;
3216
3217         /*
3218          * Non-native case: enumerate a JSIdArray and keep it via private.
3219          *
3220          * Note: we have to make sure that we root obj around the call to
3221          * JS_Enumerate to protect against multiple allocations under it.
3222          */
3223 0         JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(iterobj), &tvr);
3224 0         ida = JS_Enumerate(cx, obj);
3225 0         JS_POP_TEMP_ROOT(cx, &tvr);
3226 0         if (!ida)
3227 0             goto bad;
3228 0         pdata = ida;
3229 0         index = ida->length;
3230     }
3231
3232     /* iterobj can not escape to other threads here. */
3233 0     iterobj->slots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(pdata);
3234 0     iterobj->slots[JSSLOT_ITER_INDEX] = INT_TO_JSVAL(index);
3235 0     return iterobj;
3236
3237 bad:
3238 0     cx->newborn[GCX_OBJECT] = NULL;
3239 0     return NULL;
3240 }
3241
3242 JS_PUBLIC_API(JSBool)
3243 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
3244 0 {
3245 0     jsint i;
3246 0     JSObject *obj;
3247 0     JSScope *scope;
3248 0     JSScopeProperty *sprop;
3249 0     JSIdArray *ida;
3250
3251 0     CHECK_REQUEST(cx);
3252 0     i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX));
3253 0     if (i < 0) {
3254         /* Native case: private data is a property tree node pointer. */
3255 0         obj = OBJ_GET_PARENT(cx, iterobj);
3256 0         JS_ASSERT(OBJ_IS_NATIVE(obj));
3257 0         scope = OBJ_SCOPE(obj);
3258 0         JS_ASSERT(scope->object == obj);
3259 0         sprop = (JSScopeProperty *) JS_GetPrivate(cx, iterobj);
3260
3261         /*
3262          * If the next property mapped by scope in the property tree ancestor
3263          * line is not enumerable, or it's an alias, or one or more properties
3264          * were deleted from the "middle" of the scope-mapped ancestor line
3265          * and the next property was among those deleted, skip it and keep on
3266          * trying to find an enumerable property that is still in scope.
3267          */
3268 0         while (sprop &&
3269                (!(sprop->attrs & JSPROP_ENUMERATE) ||
3270                 (sprop->flags & SPROP_IS_ALIAS) ||
3271                 (SCOPE_HAD_MIDDLE_DELETE(scope) &&
3272                  !SCOPE_HAS_PROPERTY(scope, sprop)))) {
3273 0             sprop = sprop->parent;
3274         }
3275
3276 0         if (!sprop) {
3277 0             *idp = JSVAL_VOID;
3278         } else {
3279 0             if (!JS_SetPrivate(cx, iterobj, sprop->parent))
3280 0                 return JS_FALSE;
3281 0             *idp = sprop->id;
3282         }
3283     } else {
3284         /* Non-native case: use the ida enumerated when iterobj was created. */
3285 0         ida = (JSIdArray *) JS_GetPrivate(cx, iterobj);
3286 0         JS_ASSERT(i <= ida->length);
3287 0         if (i == 0) {
3288 0             *idp = JSVAL_VOID; 
3289         } else {
3290 0             *idp = ida->vector[--i];
3291 0             OBJ_SET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(i));
3292         }
3293     }
3294 0     return JS_TRUE;
3295 }
3296
3297 JS_PUBLIC_API(JSBool)
3298 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
3299                jsval *vp, uintN *attrsp)
3300 0 {
3301 0     CHECK_REQUEST(cx);
3302 0     return OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, attrsp);
3303 }
3304
3305 JS_PUBLIC_API(JSCheckAccessOp)
3306 JS_SetCheckObjectAccessCallback(JSRuntime *rt, JSCheckAccessOp acb)
3307 0 {
3308 0     JSCheckAccessOp oldacb;
3309
3310 0     oldacb = rt->checkObjectAccess;
3311 0     rt->checkObjectAccess = acb;
3312 0     return oldacb;
3313 }
3314
3315 static JSBool
3316 ReservedSlotIndexOK(JSContext *cx, JSObject *obj, JSClass *clasp,
3317                     uint32 index, uint32 limit)
3318 0 {
3319     /* Check the computed, possibly per-instance, upper bound. */
3320 0     if (clasp->reserveSlots)
3321 0         JS_LOCK_OBJ_VOID(cx, obj, limit += clasp->reserveSlots(cx, obj));
3322 0     if (index >= limit) {
3323 0         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3324                              JSMSG_RESERVED_SLOT_RANGE);
3325 0         return JS_FALSE;
3326     }
3327 0     return JS_TRUE;
3328 }
3329
3330 JS_PUBLIC_API(JSBool)
3331 JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
3332 0 {
3333 0     JSClass *clasp;
3334 0     uint32 limit, slot;
3335
3336 0     CHECK_REQUEST(cx);
3337 0     clasp = OBJ_GET_CLASS(cx, obj);
3338 0     limit = JSCLASS_RESERVED_SLOTS(clasp);
3339 0     if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
3340 0         return JS_FALSE;
3341 0     slot = JSSLOT_START(clasp) + index;
3342 0     *vp = OBJ_GET_REQUIRED_SLOT(cx, obj, slot);
3343 0     return JS_TRUE;
3344 }
3345
3346 JS_PUBLIC_API(JSBool)
3347 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
3348 16314 {
3349 16314     JSClass *clasp;
3350 16314     uint32 limit, slot;
3351
3352 16314     CHECK_REQUEST(cx);
3353 16314     clasp = OBJ_GET_CLASS(cx, obj);
3354 16314     limit = JSCLASS_RESERVED_SLOTS(clasp);
3355 16314     if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
3356 0         return JS_FALSE;
3357 16314     slot = JSSLOT_START(clasp) + index;
3358 16314     return OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v);
3359 }
3360
3361 #ifdef JS_THREADSAFE
3362 JS_PUBLIC_API(jsrefcount)
3363 JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
3364 {
3365     return JS_ATOMIC_INCREMENT(&principals->refcount);
3366 }
3367
3368 JS_PUBLIC_API(jsrefcount)
3369 JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
3370 {
3371     jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
3372     if (rc == 0)
3373         principals->destroy(cx, principals);
3374     return rc;
3375 }
3376 #endif
3377
3378 JS_PUBLIC_API(JSPrincipalsTranscoder)
3379 JS_SetPrincipalsTranscoder(JSRuntime *rt, JSPrincipalsTranscoder px)
3380 0 {
3381 0     JSPrincipalsTranscoder oldpx;
3382
3383 0     oldpx = rt->principalsTranscoder;
3384 0     rt->principalsTranscoder = px;
3385 0     return oldpx;
3386 }
3387
3388 JS_PUBLIC_API(JSObjectPrincipalsFinder)
3389 JS_SetObjectPrincipalsFinder(JSRuntime *rt, JSObjectPrincipalsFinder fop)
3390 0 {
3391 0     JSObjectPrincipalsFinder oldfop;
3392
3393 0     oldfop = rt->findObjectPrincipals;
3394 0     rt->findObjectPrincipals = fop;
3395 0     return oldfop;
3396 }
3397
3398 JS_PUBLIC_API(JSFunction *)
3399 JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
3400                JSObject *parent, const char *name)
3401 0 {
3402 0     JSAtom *atom;
3403
3404 0     CHECK_REQUEST(cx);
3405
3406 0     if (!name) {
3407 0         atom = NULL;
3408     } else {
3409 0         atom = js_Atomize(cx, name, strlen(name), 0);
3410 0         if (!atom)
3411 0             return NULL;
3412     }
3413 0     return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom);
3414 }
3415
3416 JS_PUBLIC_API(JSObject *)
3417 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
3418 0 {
3419 0     CHECK_REQUEST(cx);
3420 0     if (OBJ_GET_CLASS(cx, funobj) != &js_FunctionClass) {
3421         /* Indicate we cannot clone this object. */
3422 0         return funobj;
3423     }
3424 0     return js_CloneFunctionObject(cx, funobj, parent);
3425 }
3426
3427 JS_PUBLIC_API(JSObject *)
3428 JS_GetFunctionObject(JSFunction *fun)
3429 0 {
3430 0     return fun->object;
3431 }
3432
3433 JS_PUBLIC_API(const char *)
3434 JS_GetFunctionName(JSFunction *fun)
3435 0 {
3436 0     return fun->atom
3437            ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
3438            : js_anonymous_str;
3439 }
3440
3441 JS_PUBLIC_API(JSString *)
3442 JS_GetFunctionId(JSFunction *fun)
3443 0 {
3444 0     return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
3445 }
3446
3447 JS_PUBLIC_API(uintN)
3448 JS_GetFunctionFlags(JSFunction *fun)
3449 0 {
3450 0     return fun->flags;
3451 }
3452
3453 JS_PUBLIC_API(uint16)
3454 JS_GetFunctionArity(JSFunction *fun)
3455 0 {
3456 0     return fun->nargs;
3457 }
3458
3459 JS_PUBLIC_API(JSBool)
3460 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
3461 0 {
3462 0     return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass;
3463 }
3464
3465 JS_STATIC_DLL_CALLBACK(JSBool)
3466 js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
3467                                     uintN argc, jsval *argv, jsval *rval)
3468 0 {
3469 0     jsval fsv;
3470 0     JSFunctionSpec *fs;
3471 0     JSObject *tmp;
3472
3473 0     if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &fsv))
3474 0         return JS_FALSE;
3475 0     fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv);
3476
3477     /*
3478      * We know that argv[0] is valid because JS_DefineFunctions, which is our
3479      * only (indirect) referrer, defined us as requiring at least one argument
3480      * (notice how it passes fs->nargs + 1 as the next-to-last argument to
3481      * JS_DefineFunction).
3482      */
3483 0     if (JSVAL_IS_PRIMITIVE(argv[0])) {
3484         /*
3485          * Make sure that this is an object or null, as required by the generic
3486          * functions.
3487          */
3488 0         if (!js_ValueToObject(cx, argv[0], &tmp))
3489 0             return JS_FALSE;
3490 0         argv[0] = OBJECT_TO_JSVAL(tmp);
3491     }
3492
3493     /*
3494      * Copy all actual (argc) and required but missing (fs->nargs + 1 - argc)
3495      * args down over our |this| parameter, argv[-1], which is almost always
3496      * the class constructor object, e.g. Array.  Then call the corresponding
3497      * prototype native method with our first argument passed as |this|.
3498      */
3499 0     memmove(argv - 1, argv, JS_MAX(fs->nargs + 1U, argc) * sizeof(jsval));
3500
3501     /*
3502      * Follow Function.prototype.apply and .call by using the global object as
3503      * the 'this' param if no args.
3504      */
3505 0     JS_ASSERT(cx->fp->argv == argv);
3506 0     if (!js_ComputeThis(cx, JSVAL_TO_OBJECT(argv[-1]), cx->fp))
3507 0         return JS_FALSE;
3508
3509     /*
3510      * Protect against argc - 1 underflowing below. By calling js_ComputeThis,
3511      * we made it as if the static was called with one parameter.
3512      */
3513 0     if (argc == 0)
3514 0         argc = 1;
3515
3516 0     return fs->call(cx, JSVAL_TO_OBJECT(argv[-1]), argc - 1, argv, rval);
3517 }
3518
3519 JS_PUBLIC_API(JSBool)
3520 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
3521 320 {
3522 320     uintN flags;
3523 320     JSObject *ctor;
3524 320     JSFunction *fun;
3525
3526 320     CHECK_REQUEST(cx);
3527 320     ctor = NULL;
3528 6336     for (; fs->name; fs++) {
3529 3008         flags = fs->flags;
3530
3531         /*
3532          * Define a generic arity N+1 static method for the arity N prototype
3533          * method if flags contains JSFUN_GENERIC_NATIVE.
3534          */
3535 3008         if (flags & JSFUN_GENERIC_NATIVE) {
3536 560             if (!ctor) {
3537 32                 ctor = JS_GetConstructor(cx, obj);
3538 32                 if (!ctor)
3539 0                     return JS_FALSE;
3540             }
3541
3542 560             flags &= ~JSFUN_GENERIC_NATIVE;
3543 560             fun = JS_DefineFunction(cx, ctor, fs->name,
3544                                     js_generic_native_method_dispatcher,
3545                                     fs->nargs + 1, flags);
3546 560             if (!fun)
3547 0                 return JS_FALSE;
3548 560             fun->extra = fs->extra;
3549
3550             /*
3551              * As jsapi.h notes, fs must point to storage that lives as long
3552              * as fun->object lives.
3553              */
3554 560             if (!JS_SetReservedSlot(cx, fun->object, 0, PRIVATE_TO_JSVAL(fs)))
3555 0                 return JS_FALSE;
3556         }
3557
3558 3008         fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
3559 3008         if (!fun)
3560 0             return JS_FALSE;
3561 3008         fun->extra = fs->extra;
3562     }
3563 320     return JS_TRUE;
3564 }
3565
3566 JS_PUBLIC_API(JSFunction *)
3567 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
3568                   uintN nargs, uintN attrs)
3569 4256 {
3570 4256     JSAtom *atom;
3571
3572 4256     CHECK_REQUEST(cx);
3573 4256     atom = js_Atomize(cx, name, strlen(name), 0);
3574 4256     if (!atom)
3575 0         return NULL;
3576 4256     return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
3577 }
3578
3579 JS_PUBLIC_API(JSFunction *)
3580 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
3581                     const jschar *name, size_t namelen, JSNative call,
3582                     uintN nargs, uintN attrs)
3583 0 {
3584 0     JSAtom *atom;
3585
3586 0     atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3587 0     if (!atom)
3588 0         return NULL;
3589 0     return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
3590 }
3591
3592 static JSScript *
3593 CompileTokenStream(JSContext *cx, JSObject *obj, JSTokenStream *ts,
3594                    void *tempMark, JSBool *eofp)
3595 1207 {
3596 1207     JSBool eof;
3597 1207     JSArenaPool codePool, notePool;
3598 1207     JSCodeGenerator cg;
3599 1207     JSScript *script;
3600
3601 1207     CHECK_REQUEST(cx);
3602 1207     eof = JS_FALSE;
3603 1207     JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode));
3604 1207     JS_InitArenaPool(&notePool, "note", 1024, sizeof(jssrcnote));
3605 1207     if (!js_InitCodeGenerator(cx, &cg, &codePool, &notePool,
3606                               ts->filename, ts->lineno,
3607                               ts->principals)) {
3608 0         script = NULL;
3609 1207     } else if (!js_CompileTokenStream(cx, obj, ts, &cg)) {
3610 0         script = NULL;
3611 0         eof = (ts->flags & TSF_EOF) != 0;
3612     } else {
3613 1207         script = js_NewScriptFromCG(cx, &cg, NULL);
3614     }
3615 1207     if (eofp)
3616 0         *eofp = eof;
3617 1207     if (!js_CloseTokenStream(cx, ts)) {
3618 0         if (script)
3619 0             js_DestroyScript(cx, script);
3620 0         script = NULL;
3621     }
3622 1207     cg.tempMark = tempMark;
3623 1207     js_FinishCodeGenerator(cx, &cg);
3624 1207     JS_FinishArenaPool(&codePool);
3625 1207     JS_FinishArenaPool(&notePool);
3626 1207     return script;
3627 }
3628
3629 JS_PUBLIC_API(JSScript *)
3630 JS_CompileScript(JSContext *cx, JSObject *obj,
3631                  const char *bytes, size_t length,
3632                  const char *filename, uintN lineno)
3633 0 {
3634 0     jschar *chars;
3635 0     JSScript *script;
3636
3637 0     CHECK_REQUEST(cx);
3638 0     chars = js_InflateString(cx, bytes, &length);
3639 0     if (!chars)
3640 0         return NULL;
3641 0     script = JS_CompileUCScript(cx, obj, chars, length, filename, lineno);
3642 0     JS_free(cx, chars);
3643 0     return script;
3644 }
3645
3646 JS_PUBLIC_API(JSScript *)
3647 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
3648                               JSPrincipals *principals,
3649                               const char *bytes, size_t length,
3650                               const char *filename, uintN lineno)
3651 0 {
3652 0     jschar *chars;
3653 0     JSScript *script;
3654
3655 0     CHECK_REQUEST(cx);
3656 0     chars = js_InflateString(cx, bytes, &length);
3657 0     if (!chars)
3658 0         return NULL;
3659 0     script = JS_CompileUCScriptForPrincipals(cx, obj, principals,
3660                                              chars, length, filename, lineno);
3661 0     JS_free(cx, chars);
3662 0     return script;
3663 }
3664
3665 JS_PUBLIC_API(JSScript *)
3666 JS_CompileUCScript(JSContext *cx, JSObject *obj,
3667                    const jschar *chars, size_t length,
3668                    const char *filename, uintN lineno)
3669 0 {
3670 0     CHECK_REQUEST(cx);
3671 0     return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length,
3672                                            filename, lineno);
3673 }
3674
3675 #if JS_HAS_EXCEPTIONS
3676 # define LAST_FRAME_EXCEPTION_CHECK(cx,result)                                \
3677     JS_BEGIN_MACRO                                                            \
3678         if (!(result))                                                        \
3679             js_ReportUncaughtException(cx);                                   \
3680     JS_END_MACRO
3681 #else
3682 # define LAST_FRAME_EXCEPTION_CHECK(cx,result)  /* nothing */
3683 #endif
3684
3685 #define LAST_FRAME_CHECKS(cx,result)                                          \
3686     JS_BEGIN_MACRO                                                            \
3687         if (!(cx)->fp) {                                                      \
3688             (cx)->lastInternalResult = JSVAL_NULL;                            \
3689             LAST_FRAME_EXCEPTION_CHECK(cx, result);                           \
3690         }                                                                     \
3691     JS_END_MACRO
3692
3693 JS_PUBLIC_API(JSScript *)
3694 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
3695                                 JSPrincipals *principals,
3696                                 const jschar *chars, size_t length,
3697                                 const char *filename, uintN lineno)
3698 1207 {
3699 1207     void *mark;
3700 1207     JSTokenStream *ts;
3701 1207     JSScript *script;
3702
3703 1207     CHECK_REQUEST(cx);
3704 1207     mark = JS_ARENA_MARK(&cx->tempPool);
3705 1207     ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
3706 1207     if (!ts)
3707 0         return NULL;
3708 1207     script = CompileTokenStream(cx, obj, ts, mark, NULL);
3709 1207     LAST_FRAME_CHECKS(cx, script);
3710 1207     return script;
3711 }
3712
3713 JS_PUBLIC_API(JSBool)
3714 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
3715                           const char *bytes, size_t length)
3716 0 {
3717 0     jschar *chars;
3718 0     JSBool result;
3719 0     JSExceptionState *exnState;
3720 0     void *tempMark;
3721 0     JSTokenStream *ts;
3722 0     JSErrorReporter older;
3723
3724 0     CHECK_REQUEST(cx);
3725 0     chars = js_InflateString(cx, bytes, &length);
3726 0     if (!chars)
3727 0         return JS_TRUE;
3728
3729     /*
3730      * Return true on any out-of-memory error, so our caller doesn't try to
3731      * collect more buffered source.
3732      */
3733 0     result = JS_TRUE;
3734 0     exnState = JS_SaveExceptionState(cx);
3735 0     tempMark = JS_ARENA_MARK(&cx->tempPool);
3736 0     ts = js_NewTokenStream(cx, chars, length, NULL, 0, NULL);
3737 0     if (ts) {
3738 0         older = JS_SetErrorReporter(cx, NULL);
3739 0         if (!js_ParseTokenStream(cx, obj, ts) &&
3740             (ts->flags & TSF_UNEXPECTED_EOF)) {
3741             /*
3742              * We ran into an error.  If it was because we ran out of source,
3743              * we return false, so our caller will know to try to collect more
3744              * buffered source.
3745              */
3746 0             result = JS_FALSE;
3747         }
3748
3749 0         JS_SetErrorReporter(cx, older);
3750 0         js_CloseTokenStream(cx, ts);
3751 0         JS_ARENA_RELEASE(&cx->tempPool, tempMark);
3752     }
3753
3754 0     JS_free(cx, chars);
3755 0     JS_RestoreExceptionState(cx, exnState);
3756 0     return result;
3757 }
3758
3759 JS_PUBLIC_API(JSScript *)
3760 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
3761 0 {
3762 0     void *mark;
3763 0     JSTokenStream *ts;
3764 0     JSScript *script;
3765
3766 0     CHECK_REQUEST(cx);
3767 0     mark = JS_ARENA_MARK(&cx->tempPool);
3768 0     ts = js_NewFileTokenStream(cx, filename, stdin);
3769 0     if (!ts)
3770 0         return NULL;
3771 0     script = CompileTokenStream(cx, obj, ts, mark, NULL);
3772 0     LAST_FRAME_CHECKS(cx, script);
3773 0     return script;
3774 }
3775
3776 JS_PUBLIC_API(JSScript *)
3777 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename,
3778                      FILE *file)
3779 0 {
3780 0     return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
3781 }
3782
3783 JS_PUBLIC_API(JSScript *)
3784 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
3785                                   const char *filename, FILE *file,
3786                                   JSPrincipals *principals)
3787 0 {
3788 0     void *mark;
3789 0     JSTokenStream *ts;
3790 0     JSScript *script;
3791
3792 0     CHECK_REQUEST(cx);
3793 0     mark = JS_ARENA_MARK(&cx->tempPool);
3794 0     ts = js_NewFileTokenStream(cx, NULL, file);
3795 0     if (!ts)
3796 0         return NULL;
3797 0     ts->filename = filename;
3798     /* XXXshaver js_NewFileTokenStream should do this, because it drops */
3799 0     if (principals) {
3800 0         ts->principals = principals;
3801 0         JSPRINCIPALS_HOLD(cx, ts->principals);
3802     }
3803 0     script = CompileTokenStream(cx, obj, ts, mark, NULL);
3804 0     LAST_FRAME_CHECKS(cx, script);
3805 0     return script;
3806 }
3807
3808 JS_PUBLIC_API(JSObject *)
3809 JS_NewScriptObject(JSContext *cx, JSScript *script)
3810 0 {
3811 0     JSObject *obj;
3812
3813 0     obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
3814 0     if (!obj)
3815 0         return NULL;
3816
3817 0     if (script) {
3818 0         if (!JS_SetPrivate(cx, obj, script))
3819 0             return NULL;
3820 0         script->object = obj;
3821     }
3822 0     return obj;
3823 }
3824
3825 JS_PUBLIC_API(JSObject *)
3826 JS_GetScriptObject(JSScript *script)
3827 0 {
3828 0     return script->object;
3829 }
3830
3831 JS_PUBLIC_API(void)
3832 JS_DestroyScript(JSContext *cx, JSScript *script)
3833 1207 {
3834 1207     CHECK_REQUEST(cx);
3835 1207     js_DestroyScript(cx, script);
3836 }
3837
3838 JS_PUBLIC_API(JSFunction *)
3839 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
3840                    uintN nargs, const char **argnames,
3841                    const char *bytes, size_t length,
3842                    const char *filename, uintN lineno)
3843 0 {
3844 0     jschar *chars;
3845 0     JSFunction *fun;
3846
3847 0     CHECK_REQUEST(cx);
3848 0     chars = js_InflateString(cx, bytes, &length);
3849 0     if (!chars)
3850 0         return NULL;
3851 0     fun = JS_CompileUCFunction(cx, obj, name, nargs, argnames, chars, length,
3852                                filename, lineno);
3853 0     JS_free(cx, chars);
3854 0     return fun;
3855 }
3856
3857 JS_PUBLIC_API(JSFunction *)
3858 JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
3859                                 JSPrincipals *principals, const char *name,
3860                                 uintN nargs, const char **argnames,
3861                                 const char *bytes, size_t length,
3862                                 const char *filename, uintN lineno)
3863 0 {
3864 0     jschar *chars;
3865 0     JSFunction *fun;
3866
3867 0     CHECK_REQUEST(cx);
3868 0     chars = js_InflateString(cx, bytes, &length);
3869 0     if (!chars)
3870 0         return NULL;
3871 0     fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
3872                                             nargs, argnames, chars, length,
3873                                             filename, lineno);
3874 0     JS_free(cx, chars);
3875 0     return fun;
3876 }
3877
3878 JS_PUBLIC_API(JSFunction *)
3879 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
3880                      uintN nargs, const char **argnames,
3881                      const jschar *chars, size_t length,
3882                      const char *filename, uintN lineno)
3883 0 {
3884 0     CHECK_REQUEST(cx);
3885 0     return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name,
3886                                              nargs, argnames,
3887                                              chars, length,
3888                                              filename, lineno);
3889 }
3890
3891 JS_PUBLIC_API(JSFunction *)
3892 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
3893                                   JSPrincipals *principals, const char *name,
3894                                   uintN nargs, const char **argnames,
3895                                   const jschar *chars, size_t length,
3896                                   const char *filename, uintN lineno)
3897 0 {
3898 0     void *mark;
3899 0     JSTokenStream *ts;
3900 0     JSFunction *fun;
3901 0     JSAtom *funAtom, *argAtom;
3902 0     uintN i;
3903
3904 0     CHECK_REQUEST(cx);
3905 0     mark = JS_ARENA_MARK(&cx->tempPool);
3906 0     ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
3907 0     if (!ts) {
3908 0         fun = NULL;
3909 0         goto out;
3910     }
3911 0     if (!name) {
3912 0         funAtom = NULL;
3913     } else {
3914 0         funAtom = js_Atomize(cx, name, strlen(name), 0);
3915 0         if (!funAtom) {
3916 0             fun = NULL;
3917 0             goto out;
3918         }
3919     }
3920 0     fun = js_NewFunction(cx, NULL, NULL, nargs, 0, obj, funAtom);
3921 0     if (!fun)
3922 0         goto out;
3923 0     if (nargs) {
3924 0         for (i = 0; i < nargs; i++) {
3925 0             argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
3926 0             if (!argAtom)
3927 0                 break;
3928 0             if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom),
3929                                       js_GetArgument, js_SetArgument,
3930                                       SPROP_INVALID_SLOT,
3931                                       JSPROP_PERMANENT | JSPROP_SHARED,
3932                                       SPROP_HAS_SHORTID, i)) {
3933 0                 break;
3934             }
3935         }
3936 0         if (i < nargs) {
3937 0             fun = NULL;
3938 0             goto out;
3939         }
3940     }
3941 0     if (!js_CompileFunctionBody(cx, ts, fun)) {
3942 0         fun = NULL;
3943 0         goto out;
3944     }
3945 0     if (obj && funAtom) {
3946 0         if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(funAtom),
3947                                  OBJECT_TO_JSVAL(fun->object),
3948                                  NULL, NULL, JSPROP_ENUMERATE, NULL)) {
3949 0             return NULL;
3950         }
3951     }
3952 out:
3953 0     if (ts)
3954 0         js_CloseTokenStream(cx, ts);
3955 0     JS_ARENA_RELEASE(&cx->tempPool, mark);
3956 0     LAST_FRAME_CHECKS(cx, fun);
3957 0     return fun;
3958 }
3959
3960 JS_PUBLIC_API(JSString *)
3961 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
3962                    uintN indent)
3963 0 {
3964 0     JSPrinter *jp;
3965 0     JSString *str;
3966
3967 0     CHECK_REQUEST(cx);
3968 0     jp = js_NewPrinter(cx, name,
3969                        indent & ~JS_DONT_PRETTY_PRINT,
3970                        !(indent & JS_DONT_PRETTY_PRINT));
3971 0     if (!jp)
3972 0         return NULL;
3973 0     if (js_DecompileScript(jp, script))
3974 0         str = js_GetPrinterOutput(jp);
3975     else
3976 0         str = NULL;
3977 0     js_DestroyPrinter(jp);
3978 0     return str;
3979 }
3980
3981 JS_PUBLIC_API(JSString *)
3982 JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
3983 0 {
3984 0     JSPrinter *jp;
3985 0     JSString *str;
3986
3987 0     CHECK_REQUEST(cx);
3988 0     jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
3989                        indent & ~JS_DONT_PRETTY_PRINT,
3990                        !(indent & JS_DONT_PRETTY_PRINT));
3991 0     if (!jp)
3992 0         return NULL;
3993 0     if (js_DecompileFunction(jp, fun))
3994 0         str = js_GetPrinterOutput(jp);
3995     else
3996 0         str = NULL;
3997 0     js_DestroyPrinter(jp);
3998 0     return str;
3999 }
4000
4001 JS_PUBLIC_API(JSString *)
4002 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
4003 0 {
4004 0     JSPrinter *jp;
4005 0     JSString *str;
4006
4007 0     CHECK_REQUEST(cx);
4008 0     jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
4009                        indent & ~JS_DONT_PRETTY_PRINT,
4010                        !(indent & JS_DONT_PRETTY_PRINT));
4011 0     if (!jp)
4012 0         return NULL;
4013 0     if (js_DecompileFunctionBody(jp, fun))
4014 0         str = js_GetPrinterOutput(jp);
4015     else
4016 0         str = NULL;
4017 0     js_DestroyPrinter(jp);
4018 0     return str;
4019 }
4020
4021 JS_PUBLIC_API(JSBool)
4022 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
4023 0 {
4024 0     JSBool ok;
4025
4026 0     CHECK_REQUEST(cx);
4027 0     ok = js_Execute(cx, obj, script, NULL, 0, rval);
4028 0     LAST_FRAME_CHECKS(cx, ok);
4029 0     return ok;
4030 }
4031
4032 JS_PUBLIC_API(JSBool)
4033 JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script,
4034                      JSExecPart part, jsval *rval)
4035 0 {
4036 0     JSScript tmp;
4037 0     JSRuntime *rt;
4038 0     JSBool ok;
4039
4040     /* Make a temporary copy of the JSScript structure and farble it a bit. */
4041 0     tmp = *script;
4042 0     if (part == JSEXEC_PROLOG) {
4043 0         tmp.length = PTRDIFF(tmp.main, tmp.code, jsbytecode);
4044     } else {
4045 0         tmp.length -= PTRDIFF(tmp.main, tmp.code, jsbytecode);
4046 0         tmp.code = tmp.main;
4047     }
4048
4049     /* Tell the debugger about our temporary copy of the script structure. */
4050 0     rt = cx->runtime;
4051 0     if (rt->newScriptHook) {
4052 0         rt->newScriptHook(cx, tmp.filename, tmp.lineno, &tmp, NULL,
4053                           rt->newScriptHookData);
4054     }
4055
4056     /* Execute the farbled struct and tell the debugger to forget about it. */
4057 0     ok = JS_ExecuteScript(cx, obj, &tmp, rval);
4058 0     if (rt->destroyScriptHook)
4059 0         rt->destroyScriptHook(cx, &tmp, rt->destroyScriptHookData);
4060 0     return ok;
4061 }
4062
4063 JS_PUBLIC_API(JSBool)
4064 JS_EvaluateScript(JSContext *cx, JSObject *obj,
4065                   const char *bytes, uintN nbytes,
4066                   const char *filename, uintN lineno,
4067                   jsval *rval)
4068 1207 {
4069 1207     size_t length = nbytes;
4070 1207     jschar *chars;
4071 1207     JSBool ok;
4072
4073 1207     CHECK_REQUEST(cx);
4074 1207     chars = js_InflateString(cx, bytes, &length);
4075 1207     if (!chars)
4076 0         return JS_FALSE;
4077 1207     ok = JS_EvaluateUCScript(cx, obj, chars, length, filename, lineno, rval);
4078 1207     JS_free(cx, chars);
4079 1207     return ok;
4080 }
4081
4082 JS_PUBLIC_API(JSBool)
4083 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj,
4084                                JSPrincipals *principals,
4085                                const char *bytes, uintN nbytes,
4086                                const char *filename, uintN lineno,
4087                                jsval *rval)
4088 0 {
4089 0     size_t length = nbytes;
4090 0     jschar *chars;
4091 0     JSBool ok;
4092
4093 0     CHECK_REQUEST(cx);
4094 0     chars = js_InflateString(cx, bytes, &length);
4095 0     if (!chars)
4096 0         return JS_FALSE;
4097 0     ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
4098                                           filename, lineno, rval);
4099 0     JS_free(cx, chars);
4100 0     return ok;
4101 }
4102
4103 JS_PUBLIC_API(JSBool)
4104 JS_EvaluateUCScript(JSContext *cx, JSObject *obj,
4105                     const jschar *chars, uintN length,
4106                     const char *filename, uintN lineno,
4107                     jsval *rval)
4108 1207 {
4109 1207     CHECK_REQUEST(cx);
4110 1207     return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length,
4111                                             filename, lineno, rval);
4112 }
4113
4114 JS_PUBLIC_API(JSBool)
4115 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
4116                                  JSPrincipals *principals,
4117                                  const jschar *chars, uintN length,
4118                                  const char *filename, uintN lineno,
4119                                  jsval *rval)
4120 1207 {
4121 1207     uint32 options;
4122 1207     JSScript *script;
4123 1207     JSBool ok;
4124
4125 1207     CHECK_REQUEST(cx);
4126 1207     options = cx->options;
4127 1207     cx->options = options | JSOPTION_COMPILE_N_GO;
4128 1207     script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length,
4129                                              filename, lineno);
4130 1207     cx->options = options;
4131 1207     if (!script)
4132 0         return JS_FALSE;
4133 1207     ok = js_Execute(cx, obj, script, NULL, 0, rval);
4134 1207     LAST_FRAME_CHECKS(cx, ok);
4135 1207     JS_DestroyScript(cx, script);
4136 1207     return ok;
4137 }
4138
4139 JS_PUBLIC_API(JSBool)
4140 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc,
4141                 jsval *argv, jsval *rval)
4142 0 {
4143 0     JSBool ok;
4144
4145 0     CHECK_REQUEST(cx);
4146 0     ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(fun->object), argc, argv,
4147                          rval);
4148 0     LAST_FRAME_CHECKS(cx, ok);
4149 0     return ok;
4150 }
4151
4152 JS_PUBLIC_API(JSBool)
4153 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
4154                     jsval *argv, jsval *rval)
4155 16 {
4156 16     JSBool ok;
4157 16     jsval fval;
4158
4159 16     CHECK_REQUEST(cx);
4160 #if JS_HAS_XML_SUPPORT
4161 16     if (OBJECT_IS_XML(cx, obj)) {
4162 0         JSXMLObjectOps *ops;
4163 0         JSAtom *atom;
4164
4165 0         ops = (JSXMLObjectOps *) obj->map->ops;
4166 0         atom = js_Atomize(cx, name, strlen(name), 0);
4167 0         if (!atom)
4168 0             return JS_FALSE;
4169 0         obj = ops->getMethod(cx, obj, ATOM_TO_JSID(atom), &fval);
4170 0         if (!obj)
4171 0             return JS_FALSE;
4172     } else
4173 #endif
4174 16     if (!JS_GetProperty(cx, obj, name, &fval))
4175 0         return JS_FALSE;
4176 16     ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
4177 16     LAST_FRAME_CHECKS(cx, ok);
4178 16     return ok;
4179 }
4180
4181 JS_PUBLIC_API(JSBool)
4182 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
4183                      jsval *argv, jsval *rval)
4184 0 {
4185 0     JSBool ok;
4186
4187 0     CHECK_REQUEST(cx);
4188 0     ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
4189 0     LAST_FRAME_CHECKS(cx, ok);
4190 0     return ok;
4191 }
4192
4193 JS_PUBLIC_API(JSBranchCallback)
4194 JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb)
4195 0 {
4196 0     JSBranchCallback oldcb;
4197
4198 0     oldcb = cx->branchCallback;
4199 0     cx->branchCallback = cb;
4200 0     return oldcb;
4201 }
4202
4203 JS_PUBLIC_API(JSBool)
4204 JS_IsRunning(JSContext *cx)
4205 0 {
4206 0     return cx->fp != NULL;
4207 }
4208
4209 JS_PUBLIC_API(JSBool)
4210 JS_IsConstructing(JSContext *cx)
4211 0 {
4212 0     return cx->fp && (cx->fp->flags & JSFRAME_CONSTRUCTING);
4213 }
4214
4215 JS_FRIEND_API(JSBool)
4216 JS_IsAssigning(JSContext *cx)
4217 0 {
4218 0     JSStackFrame *fp;
4219 0     jsbytecode *pc;
4220
4221 0     for (fp = cx->fp; fp && !fp->script; fp = fp->down)
4222 0         continue;
4223 0     if (!fp || !(pc = fp->pc))
4224 0         return JS_FALSE;
4225 0     return (js_CodeSpec[*pc].format & JOF_ASSIGNING) != 0;
4226 }
4227
4228 JS_PUBLIC_API(void)
4229 JS_SetCallReturnValue2(JSContext *cx, jsval v)
4230 0 {
4231 #if JS_HAS_LVALUE_RETURN
4232 0     cx->rval2 = v;
4233 0     cx->rval2set = JS_TRUE;
4234 #endif
4235 }
4236
4237 /************************************************************************/
4238
4239 JS_PUBLIC_API(JSString *)
4240 JS_NewString(JSContext *cx, char *bytes, size_t length)
4241 0 {
4242 0     jschar *chars;
4243 0     JSString *str;
4244 0     size_t charsLength = length;
4245
4246 0     CHECK_REQUEST(cx);
4247     /* Make a Unicode vector from the 8-bit char codes in bytes. */
4248 0     chars = js_InflateString(cx, bytes, &charsLength);
4249 0     if (!chars)
4250 0         return NULL;
4251
4252     /* Free chars (but not bytes, which caller frees on error) if we fail. */
4253 0     str = js_NewString(cx, chars, charsLength, 0);
4254 0     if (!str) {
4255 0         JS_free(cx, chars);
4256 0         return NULL;
4257     }
4258
4259     /* Hand off bytes to the deflated string cache, if possible. */
4260 0     if (!js_SetStringBytes(str, bytes, length))
4261 0         JS_free(cx, bytes);
4262 0     return str;
4263 }
4264
4265 JS_PUBLIC_API(JSString *)
4266 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
4267 0 {
4268 0     jschar *js;
4269 0     JSString *str;
4270
4271 0     CHECK_REQUEST(cx);
4272 0     js = js_InflateString(cx, s, &n);
4273 0     if (!js)
4274 0         return NULL;
4275 0     str = js_NewString(cx, js, n, 0);
4276 0     if (!str)
4277 0         JS_free(cx, js);
4278 0     return str;
4279 }
4280
4281 JS_PUBLIC_API(JSString *)
4282 JS_NewStringCopyZ(JSContext *cx, const char *s)
4283 22580 {
4284 22580     size_t n;
4285 22580     jschar *js;
4286 22580     JSString *str;
4287
4288 22580     CHECK_REQUEST(cx);
4289 22580     if (!s)
4290 0         return cx->runtime->emptyString;
4291 22580     n = strlen(s);
4292 22580     js = js_InflateString(cx, s, &n);
4293 22580     if (!js)
4294 0         return NULL;
4295 22580     str = js_NewString(cx, js, n, 0);
4296 22580     if (!str)
4297 0         JS_free(cx, js);
4298 22580     return str;
4299 }
4300
4301 JS_PUBLIC_API(JSString *)
4302 JS_InternString(JSContext *cx, const char *s)
4303 176935 {
4304 176935     JSAtom *atom;
4305
4306 176935     CHECK_REQUEST(cx);
4307 176935     atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
4308 176935     if (!atom)
4309 0         return NULL;
4310 176935     return ATOM_TO_STRING(atom);
4311 }
4312
4313 JS_PUBLIC_API(JSString *)
4314 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
4315 0 {
4316 0     CHECK_REQUEST(cx);
4317 0     return js_NewString(cx, chars, length, 0);
4318 }
4319
4320 JS_PUBLIC_API(JSString *)
4321 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
4322 0 {
4323 0     CHECK_REQUEST(cx);
4324 0     return js_NewStringCopyN(cx, s, n, 0);
4325 }
4326
4327 JS_PUBLIC_API(JSString *)
4328 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
4329 0 {
4330 0     CHECK_REQUEST(cx);
4331 0     if (!s)
4332 0         return cx->runtime->emptyString;
4333 0     return js_NewStringCopyZ(cx, s, 0);
4334 }
4335
4336 JS_PUBLIC_API(JSString *)
4337 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
4338 0 {
4339 0     JSAtom *atom;
4340
4341 0     CHECK_REQUEST(cx);
4342 0     atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
4343 0     if (!atom)
4344 0         return NULL;
4345 0     return ATOM_TO_STRING(atom);
4346 }
4347
4348 JS_PUBLIC_API(JSString *)
4349 JS_InternUCString(JSContext *cx, const jschar *s)
4350 0 {
4351 0     return JS_InternUCStringN(cx, s, js_strlen(s));
4352 }
4353
4354 JS_PUBLIC_API(char *)
4355 JS_GetStringBytes(JSString *str)
4356 348149 {
4357 348149     char *bytes;
4358
4359 348149     bytes = js_GetStringBytes(str);
4360 348149     return bytes ? bytes : "";
4361 }
4362
4363 JS_PUBLIC_API(jschar *)
4364 JS_GetStringChars(JSString *str)
4365 0 {
4366     /*
4367      * API botch (again, shades of JS_GetStringBytes): we have no cx to pass
4368      * to js_UndependString (called by js_GetStringChars) for out-of-memory
4369      * error reports, so js_UndependString passes NULL and suppresses errors.
4370      * If it fails to convert a dependent string into an independent one, our
4371      * caller will not be guaranteed a \u0000 terminator as a backstop.  This
4372      * may break some clients who already misbehave on embedded NULs.
4373      *
4374      * The gain of dependent strings, which cure quadratic and cubic growth
4375      * rate bugs in string concatenation, is worth this slight loss in API
4376      * compatibility.
4377      */
4378 0     jschar *chars;
4379
4380 0     chars = js_GetStringChars(str);
4381 0     return chars ? chars : JSSTRING_CHARS(str);
4382 }
4383
4384 JS_PUBLIC_API(size_t)
4385 JS_GetStringLength(JSString *str)
4386 6248 {
4387 6248     return JSSTRING_LENGTH(str);
4388 }
4389
4390 JS_PUBLIC_API(intN)
4391 JS_CompareStrings(JSString *str1, JSString *str2)
4392 0 {
4393 0     return js_CompareStrings(str1, str2);
4394 }
4395
4396 JS_PUBLIC_API(JSString *)
4397 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
4398 0 {
4399 0     CHECK_REQUEST(cx);
4400 0     return js_NewString(cx, chars, length, GCF_MUTABLE);
4401 }
4402
4403 JS_PUBLIC_API(JSString *)
4404 JS_NewDependentString(JSContext *cx, JSString *str, size_t start,
4405                       size_t length)
4406 0 {
4407 0     CHECK_REQUEST(cx);
4408 0     return js_NewDependentString(cx, str, start, length, 0);
4409 }
4410
4411 JS_PUBLIC_API(JSString *)
4412 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
4413 0 {
4414 0     CHECK_REQUEST(cx);
4415 0     return js_ConcatStrings(cx, left, right);
4416 }
4417
4418 JS_PUBLIC_API(const jschar *)
4419 JS_UndependString(JSContext *cx, JSString *str)
4420 0 {
4421 0     CHECK_REQUEST(cx);
4422 0     return js_UndependString(cx, str);
4423 }
4424
4425 JS_PUBLIC_API(JSBool)
4426 JS_MakeStringImmutable(JSContext *cx, JSString *str)
4427 7814 {
4428 7814     CHECK_REQUEST(cx);
4429 7814     if (!js_UndependString(cx, str))
4430 0         return JS_FALSE;
4431
4432 7814     *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
4433 7814     return JS_TRUE;
4434 }
4435
4436 JS_PUBLIC_API(JSBool)
4437 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst,
4438                     size_t *dstlenp)
4439 0 {
4440 0     return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
4441 }
4442
4443 JS_PUBLIC_API(JSBool)
4444 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst,
4445                size_t *dstlenp)
4446 0 {
4447 0     return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
4448 }
4449
4450 JS_PUBLIC_API(JSBool)
4451 JS_StringsAreUTF8 ()
4452 0 {
4453 #ifdef JS_C_STRINGS_ARE_UTF8
4454     return JS_TRUE;
4455 #else
4456 0     return JS_FALSE;
4457 #endif
4458 }
4459
4460 /************************************************************************/
4461
4462 JS_PUBLIC_API(void)
4463 JS_ReportError(JSContext *cx, const char *format, ...)
4464 0 {
4465 0     va_list ap;
4466
4467 0     va_start(ap, format);
4468 0     js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
4469     va_end(ap);
4470 }
4471
4472 JS_PUBLIC_API(void)
4473 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
4474                      void *userRef, const uintN errorNumber, ...)
4475 0 {
4476 0     va_list ap;
4477
4478 0     va_start(ap, errorNumber);
4479 0     js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
4480                            errorNumber, JS_TRUE, ap);
4481     va_end(ap);
4482 }
4483
4484 JS_PUBLIC_API(void)
4485 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
4486                      void *userRef, const uintN errorNumber, ...)
4487 0 {
4488 0     va_list ap;
4489
4490 0     va_start(ap, errorNumber);
4491 0     js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
4492                            errorNumber, JS_FALSE, ap);
4493     va_end(ap);
4494 }
4495
4496 JS_PUBLIC_API(JSBool)
4497 JS_ReportWarning(JSContext *cx, const char *format, ...)
4498 0 {
4499 0     va_list ap;
4500 0     JSBool ok;
4501
4502 0     va_start(ap, format);
4503 0     ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
4504 0     va_end(ap);
4505 0     return ok;
4506 }
4507
4508 JS_PUBLIC_API(JSBool)
4509 JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
4510                              JSErrorCallback errorCallback, void *userRef,
4511                              const uintN errorNumber, ...)
4512 0 {
4513 0     va_list ap;
4514 0     JSBool ok;
4515
4516 0     va_start(ap, errorNumber);
4517 0     ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
4518                                 errorNumber, JS_TRUE, ap);
4519 0     va_end(ap);
4520 0     return ok;
4521 }
4522
4523 JS_PUBLIC_API(JSBool)
4524 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
4525                                JSErrorCallback errorCallback, void *userRef,
4526                                const uintN errorNumber, ...)
4527 0 {
4528 0     va_list ap;
4529 0     JSBool ok;
4530
4531 0     va_start(ap, errorNumber);
4532 0     ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
4533                                 errorNumber, JS_FALSE, ap);
4534 0     va_end(ap);
4535 0     return ok;
4536 }
4537
4538 JS_PUBLIC_API(void)
4539 JS_ReportOutOfMemory(JSContext *cx)
4540 0 {
4541 0     js_ReportOutOfMemory(cx, js_GetErrorMessage);
4542 }
4543
4544 JS_PUBLIC_API(JSErrorReporter)
4545 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
4546 91708 {
4547 91708     JSErrorReporter older;
4548
4549 91708     older = cx->errorReporter;
4550 91708     cx->errorReporter = er;
4551 91708     return older;
4552 }
4553
4554 /************************************************************************/
4555
4556 /*
4557  * Regular Expressions.
4558  */
4559 JS_PUBLIC_API(JSObject *)
4560 JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags)
4561 0 {
4562 #if JS_HAS_REGEXPS
4563 0     jschar *chars;
4564 0     JSObject *obj;
4565
4566 0     CHECK_REQUEST(cx);
4567 0     chars = js_InflateString(cx, bytes, &length);
4568 0     if (!chars)
4569 0         return NULL;
4570 0     obj = js_NewRegExpObject(cx, NULL, chars, length, flags);
4571 0     JS_free(cx, chars);
4572 0     return obj;
4573 #else
4574     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_REG_EXPS);
4575     return NULL;
4576 #endif
4577 }
4578
4579 JS_PUBLIC_API(JSObject *)
4580 JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags)
4581 0 {
4582 0     CHECK_REQUEST(cx);
4583 #if JS_HAS_REGEXPS
4584 0     return js_NewRegExpObject(cx, NULL, chars, length, flags);
4585 #else
4586     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_REG_EXPS);
4587     return NULL;
4588 #endif
4589 }
4590
4591 JS_PUBLIC_API(void)
4592 JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline)
4593 0 {
4594 0     JSRegExpStatics *res;
4595
4596 0     CHECK_REQUEST(cx);
4597     /* No locking required, cx is thread-private and input must be live. */
4598 0     res = &cx->regExpStatics;
4599 0     res->input = input;
4600 0     res->multiline = multiline;
4601 0     cx->runtime->gcPoke = JS_TRUE;
4602 }
4603
4604 JS_PUBLIC_API(void)
4605 JS_ClearRegExpStatics(JSContext *cx)
4606 16 {
4607 16     JSRegExpStatics *res;
4608
4609     /* No locking required, cx is thread-private and input must be live. */
4610 16     res = &cx->regExpStatics;
4611 16     res->input = NULL;
4612 16     res->multiline = JS_FALSE;
4613 16     res->parenCount = 0;
4614 16     res->lastMatch = res->lastParen = js_EmptySubString;
4615 16     res->leftContext = res->rightContext = js_EmptySubString;
4616 16     cx->runtime->gcPoke = JS_TRUE;
4617 }
4618
4619 JS_PUBLIC_API(void)
4620 JS_ClearRegExpRoots(JSContext *cx)
4621 0 {
4622 0     JSRegExpStatics *res;
4623
4624     /* No locking required, cx is thread-private and input must be live. */
4625 0     res = &cx->regExpStatics;
4626 0     res->input = NULL;
4627 0     cx->runtime->gcPoke = JS_TRUE;
4628 }
4629
4630 /* TODO: compile, execute, get/set other statics... */
4631
4632 /************************************************************************/
4633
4634 JS_PUBLIC_API(void)
4635 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
4636 0 {
4637 0     cx->localeCallbacks = callbacks;
4638 }
4639
4640 JS_PUBLIC_API(JSLocaleCallbacks *)
4641 JS_GetLocaleCallbacks(JSContext *cx)
4642 0 {
4643 0     return cx->localeCallbacks;
4644 }
4645
4646 /************************************************************************/
4647
4648 JS_PUBLIC_API(JSBool)
4649 JS_IsExceptionPending(JSContext *cx)
4650 0 {
4651 #if JS_HAS_EXCEPTIONS
4652 0     return (JSBool) cx->throwing;
4653 #else
4654     return JS_FALSE;
4655 #endif
4656 }
4657
4658 JS_PUBLIC_API(JSBool)
4659 JS_GetPendingException(JSContext *cx, jsval *vp)
4660 0 {
4661 #if JS_HAS_EXCEPTIONS
4662 0     CHECK_REQUEST(cx);
4663 0     if (!cx->throwing)
4664 0         return JS_FALSE;
4665 0     *vp = cx->exception;
4666 0     return JS_TRUE;
4667 #else
4668     return JS_FALSE;
4669 #endif
4670 }
4671
4672 JS_PUBLIC_API(void)
4673 JS_SetPendingException(JSContext *cx, jsval v)
4674 0 {
4675 0     CHECK_REQUEST(cx);
4676 #if JS_HAS_EXCEPTIONS
4677 0     cx->throwing = JS_TRUE;
4678 0     cx->exception = v;
4679 #endif
4680 }
4681
4682 JS_PUBLIC_API(void)
4683 JS_ClearPendingException(JSContext *cx)
4684 0 {
4685 #if JS_HAS_EXCEPTIONS
4686 0     cx->throwing = JS_FALSE;
4687 0     cx->exception = JSVAL_VOID;
4688 #endif
4689 }
4690
4691 JS_PUBLIC_API(JSBool)
4692 JS_ReportPendingException(JSContext *cx)
4693 0 {
4694 #if JS_HAS_EXCEPTIONS
4695 0     JSBool save, ok;
4696
4697 0     CHECK_REQUEST(cx);
4698
4699     /*
4700      * Set cx->creatingException to suppress the standard error-to-exception
4701      * conversion done by all {js,JS}_Report* functions except for OOM.  The
4702      * cx->creatingException flag was added to suppress recursive divergence
4703      * under js_ErrorToException, but it serves for our purposes here too.
4704      */
4705 0     save = cx->creatingException;
4706 0     cx->creatingException = JS_TRUE;
4707 0     ok = js_ReportUncaughtException(cx);
4708 0     cx->creatingException = save;
4709 0     return ok;
4710 #else
4711     return JS_TRUE;
4712 #endif
4713 }
4714
4715 #if JS_HAS_EXCEPTIONS
4716 struct JSExceptionState {
4717     JSBool throwing;
4718     jsval  exception;
4719 };
4720 #endif
4721
4722 JS_PUBLIC_API(JSExceptionState *)
4723 JS_SaveExceptionState(JSContext *cx)
4724 0 {
4725 #if JS_HAS_EXCEPTIONS
4726 0     JSExceptionState *state;
4727
4728 0     CHECK_REQUEST(cx);
4729 0     state = (JSExceptionState *) JS_malloc(cx, sizeof(JSExceptionState));
4730 0     if (state) {
4731 0         state->throwing = JS_GetPendingException(cx, &state->exception);
4732 0         if (state->throwing && JSVAL_IS_GCTHING(state->exception))
4733 0             js_AddRoot(cx, &state->exception, "JSExceptionState.exception");
4734     }
4735 0     return state;
4736 #else
4737     return NULL;
4738 #endif
4739 }
4740
4741 JS_PUBLIC_API(void)
4742 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
4743 0 {
4744 #if JS_HAS_EXCEPTIONS
4745 0     CHECK_REQUEST(cx);
4746 0     if (state) {
4747 0         if (state->throwing)
4748 0             JS_SetPendingException(cx, state->exception);
4749         else
4750 0             JS_ClearPendingException(cx);
4751 0         JS_DropExceptionState(cx, state);
4752     }
4753 #endif
4754 }
4755
4756 JS_PUBLIC_API(void)
4757 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
4758 0 {
4759 #if JS_HAS_EXCEPTIONS
4760 0     CHECK_REQUEST(cx);
4761 0     if (state) {
4762 0         if (state->throwing && JSVAL_IS_GCTHING(state->exception))
4763 0             JS_RemoveRoot(cx, &state->exception);
4764 0         JS_free(cx, state);
4765     }
4766 #endif
4767 }
4768
4769 JS_PUBLIC_API(JSErrorReport *)
4770 JS_ErrorFromException(JSContext *cx, jsval v)
4771 0 {
4772 #if JS_HAS_ERROR_EXCEPTIONS
4773 0     CHECK_REQUEST(cx);
4774 0     return js_ErrorFromException(cx, v);
4775 #else
4776     return NULL;
4777 #endif
4778 }
4779
4780 JS_PUBLIC_API(JSBool)
4781 JS_ThrowReportedError(JSContext *cx, const char *message,
4782                       JSErrorReport *reportp)
4783 0 {
4784 0     return js_ErrorToException(cx, message, reportp);
4785 }
4786
4787 #ifdef JS_THREADSAFE
4788 JS_PUBLIC_API(jsword)
4789 JS_GetContextThread(JSContext *cx)
4790 {
4791     return cx->thread;
4792 }
4793
4794 JS_PUBLIC_API(jsword)
4795 JS_SetContextThread(JSContext *cx)
4796 {
4797     jsword old = cx->thread;
4798     cx->thread = js_CurrentThreadId();
4799     return old;
4800 }
4801
4802 JS_PUBLIC_API(jsword)
4803 JS_ClearContextThread(JSContext *cx)
4804 {
4805     jsword old = cx->thread;
4806     cx->thread = 0;
4807     return old;
4808 }
4809 #endif
4810
4811 /************************************************************************/
4812
4813 #if defined(XP_WIN)
4814 #include <windows.h>
4815 /*
4816  * Initialization routine for the JS DLL...
4817  */
4818
4819 /*
4820  * Global Instance handle...
4821  * In Win32 this is the module handle of the DLL.
4822  *
4823  * In Win16 this is the instance handle of the application
4824  * which loaded the DLL.
4825  */
4826
4827 #ifdef _WIN32
4828 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
4829 {
4830     return TRUE;
4831 }
4832
4833 #else  /* !_WIN32 */
4834
4835 int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg,
4836                       WORD cbHeapSize, LPSTR lpszCmdLine )
4837 {
4838     return TRUE;
4839 }
4840
4841 BOOL CALLBACK __loadds WEP(BOOL fSystemExit)
4842 {
4843     return TRUE;
4844 }
4845
4846 #endif /* !_WIN32 */