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