1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=80:
3 *
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
19 *
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
24 *
25 * Contributor(s):
26 *
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
38 *
39 * ***** END LICENSE BLOCK ***** */
40
41 /*
42 * JavaScript API.
43 */
44 #include "jsstddef.h"
45 #include <ctype.h>
46 #include <stdarg.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include "jstypes.h"
50 #include "jsarena.h" /* Added by JSIFY */
51 #include "jsutil.h" /* Added by JSIFY */
52 #include "jsclist.h"
53 #include "jsdhash.h"
54 #include "jsprf.h"
55 #include "jsapi.h"
56 #include "jsarray.h"
57 #include "jsatom.h"
58 #include "jsbool.h"
59 #include "jscntxt.h"
60 #include "jsconfig.h"
61 #include "jsdate.h"
62 #include "jsdtoa.h"
63 #include "jsemit.h"
64 #include "jsexn.h"
65 #include "jsfun.h"
66 #include "jsgc.h"
67 #include "jsinterp.h"
68 #include "jslock.h"
69 #include "jsmath.h"
70 #include "jsnum.h"
71 #include "jsobj.h"
72 #include "jsopcode.h"
73 #include "jsparse.h"
74 #include "jsregexp.h"
75 #include "jsscan.h"
76 #include "jsscope.h"
77 #include "jsscript.h"
78 #include "jsstr.h"
79 #include "prmjtime.h"
80
81 #if JS_HAS_FILE_OBJECT
82 #include "jsfile.h"
83 #endif
84
85 #if JS_HAS_XML_SUPPORT
86 #include "jsxml.h"
87 #endif
88
89 #ifdef HAVE_VA_LIST_AS_ARRAY
90 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
91 #else
92 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
93 #endif
94
95 #if defined(JS_PARANOID_REQUEST) && defined(JS_THREADSAFE)
96 #define CHECK_REQUEST(cx) JS_ASSERT(cx->requestDepth)
97 #else
98 #define CHECK_REQUEST(cx) ((void)0)
99 #endif
100
101 JS_PUBLIC_API(int64)
102 JS_Now()
103 0 {
104 0 return PRMJ_Now();
105 }
106
107 JS_PUBLIC_API(jsval)
108 JS_GetNaNValue(JSContext *cx)
109 0 {
110 0 return DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
111 }
112
113 JS_PUBLIC_API(jsval)
114 JS_GetNegativeInfinityValue(JSContext *cx)
115 0 {
116 0 return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
117 }
118
119 JS_PUBLIC_API(jsval)
120 JS_GetPositiveInfinityValue(JSContext *cx)
121 1731 {
122 1731 return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
123 }
124
125 JS_PUBLIC_API(jsval)
126 JS_GetEmptyStringValue(JSContext *cx)
127 0 {
128 0 return STRING_TO_JSVAL(cx->runtime->emptyString);
129 }
130
131 static JSBool
132 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS,
133 jsval **vpp, va_list *app)
134 0 {
135 const char *format;
136 JSArgumentFormatMap *map;
137
138 0 format = *formatp;
139 0 for (map = cx->argumentFormatMap; map; map = map->next) {
140 0 if (!strncmp(format, map->format, map->length)) {
141 0 *formatp = format + map->length;
142 0 return map->formatter(cx, format, fromJS, vpp, app);
143 }
144 }
145 0 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
146 0 return JS_FALSE;
147 }
148
149 JS_PUBLIC_API(JSBool)
150 JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
151 ...)
152 0 {
153 va_list ap;
154 JSBool ok;
155
156 0 va_start(ap, format);
157 0 ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
158 0 va_end(ap);
159 0 return ok;
160 }
161
162 JS_PUBLIC_API(JSBool)
163 JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
164 const char *format, va_list ap)
165 0 {
166 jsval *sp;
167 JSBool required;
168 char c;
169 JSFunction *fun;
170 jsdouble d;
171 JSString *str;
172 JSObject *obj;
173
174 CHECK_REQUEST(cx);
175 0 sp = argv;
176 0 required = JS_TRUE;
177 0 while ((c = *format++) != '\0') {
178 0 if (isspace(c))
179 0 continue;
180 0 if (c == '/') {
181 0 required = JS_FALSE;
182 0 continue;
183 }
184 0 if (sp == argv + argc) {
185 0 if (required) {
186 0 fun = js_ValueToFunction(cx, &argv[-2], 0);
187 0 if (fun) {
188 char numBuf[12];
189 0 JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
190 0 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
191 JSMSG_MORE_ARGS_NEEDED,
192 JS_GetFunctionName(fun), numBuf,
193 (argc == 1) ? "" : "s");
194 }
195 0 return JS_FALSE;
196 }
197 break;
198 }
199 0 switch (c) {
200 case 'b':
201 0 if (!js_ValueToBoolean(cx, *sp, va_arg(ap, JSBool *)))
202 0 return JS_FALSE;
203 break;
204 case 'c':
205 0 if (!js_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
206 0 return JS_FALSE;
207 break;
208 case 'i':
209 0 if (!js_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
210 0 return JS_FALSE;
211 break;
212 case 'u':
213 0 if (!js_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
214 0 return JS_FALSE;
215 break;
216 case 'j':
217 0 if (!js_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
218 0 return JS_FALSE;
219 break;
220 case 'd':
221 0 if (!js_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
222 0 return JS_FALSE;
223 break;
224 case 'I':
225 0 if (!js_ValueToNumber(cx, *sp, &d))
226 0 return JS_FALSE;
227 0 *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
228 0 break;
229 case 's':
230 case 'S':
231 case 'W':
232 0 str = js_ValueToString(cx, *sp);
233 0 if (!str)
234 0 return JS_FALSE;
235 0 *sp = STRING_TO_JSVAL(str);
236 0 if (c == 's')
237 0 *va_arg(ap, char **) = JS_GetStringBytes(str);
238 0 else if (c == 'W')
239 0 *va_arg(ap, jschar **) = JS_GetStringChars(str);
240 else
241 0 *va_arg(ap, JSString **) = str;
242 break;
243 case 'o':
244 0 if (!js_ValueToObject(cx, *sp, &obj))
245 0 return JS_FALSE;
246 0 *sp = OBJECT_TO_JSVAL(obj);
247 0 *va_arg(ap, JSObject **) = obj;
248 0 break;
249 case 'f':
250 0 obj = js_ValueToFunctionObject(cx, sp, 0);
251 0 if (!obj)
252 0 return JS_FALSE;
253 0 *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj);
254 0 break;
255 case 'v':
256 0 *va_arg(ap, jsval *) = *sp;
257 0 break;
258 case '*':
259 break;
260 default:
261 0 format--;
262 0 if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
263 JS_ADDRESSOF_VA_LIST(ap))) {
264 0 return JS_FALSE;
265 }
266 /* NB: the formatter already updated sp, so we continue here. */
267 continue;
268 }
269 0 sp++;
270 }
271 0 return JS_TRUE;
272 }
273
274 JS_PUBLIC_API(jsval *)
275 JS_PushArguments(JSContext *cx, void **markp, const char *format, ...)
276 0 {
277 va_list ap;
278 jsval *argv;
279
280 0 va_start(ap, format);
281 0 argv = JS_PushArgumentsVA(cx, markp, format, ap);
282 0 va_end(ap);
283 0 return argv;
284 }
285
286 JS_PUBLIC_API(jsval *)
287 JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap)
288 0 {
289 uintN argc;
290 jsval *argv, *sp;
291 char c;
292 const char *cp;
293 JSString *str;
294 JSFunction *fun;
295 JSStackHeader *sh;
296
297 CHECK_REQUEST(cx);
298 0 *markp = NULL;
299 0 argc = 0;
300 0 for (cp = format; (c = *cp) != '\0'; cp++) {
301 /*
302 * Count non-space non-star characters as individual jsval arguments.
303 * This may over-allocate stack, but we'll fix below.
304 */
305 0 if (isspace(c) || c == '*')
306 continue;
307 0 argc++;
308 }
309 0 sp = js_AllocStack(cx, argc, markp);
310 0 if (!sp)
311 0 return NULL;
312 0 argv = sp;
313 0 while ((c = *format++) != '\0') {
314 0 if (isspace(c) || c == '*')
315 continue;
316 0 switch (c) {
317 case 'b':
318 0 *sp = BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int));
319 0 break;
320 case 'c':
321 0 *sp = INT_TO_JSVAL((uint16) va_arg(ap, unsigned int));
322 0 break;
323 case 'i':
324 case 'j':
325 0 if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp))
326 goto bad;
327 break;
328 case 'u':
329 0 if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp))
330 goto bad;
331 break;
332 case 'd':
333 case 'I':
334 0 if (!js_NewDoubleValue(cx, va_arg(ap, jsdouble), sp))
335 goto bad;
336 break;
337 case 's':
338 0 str = JS_NewStringCopyZ(cx, va_arg(ap, char *));
339 0 if (!str)
340 0 goto bad;
341 0 *sp = STRING_TO_JSVAL(str);
342 0 break;
343 case 'W':
344 0 str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *));
345 0 if (!str)
346 0 goto bad;
347 0 *sp = STRING_TO_JSVAL(str);
348 0 break;
349 case 'S':
350 0 str = va_arg(ap, JSString *);
351 0 *sp = STRING_TO_JSVAL(str);
352 0 break;
353 case 'o':
354 0 *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *));
355 0 break;
356 case 'f':
357 0 fun = va_arg(ap, JSFunction *);
358 0 *sp = fun ? OBJECT_TO_JSVAL(fun->object) : JSVAL_NULL;
359 0 break;
360 case 'v':
361 0 *sp = va_arg(ap, jsval);
362 0 break;
363 default:
364 0 format--;
365 0 if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp,
366 JS_ADDRESSOF_VA_LIST(ap))) {
367 goto bad;
368 }
369 /* NB: the formatter already updated sp, so we continue here. */
370 continue;
371 }
372 0 sp++;
373 }
374
375 /*
376 * We may have overallocated stack due to a multi-character format code
377 * handled by a JSArgumentFormatter. Give back that stack space!
378 */
379 JS_ASSERT(sp <= argv + argc);
380 0 if (sp < argv + argc) {
381 /* Return slots not pushed to the current stack arena. */
382 0 cx->stackPool.current->avail = (jsuword)sp;
383
384 /* Reduce the count of slots the GC will scan in this stack segment. */
385 0 sh = cx->stackHeaders;
386 JS_ASSERT(JS_STACK_SEGMENT(sh) + sh->nslots == argv + argc);
387 0 sh->nslots -= argc - (sp - argv);
388 }
389 0 return argv;
390
391 0 bad:
392 0 js_FreeStack(cx, *markp);
393 0 return NULL;
394 }
395
396 JS_PUBLIC_API(void)
397 JS_PopArguments(JSContext *cx, void *mark)
398 0 {
399 CHECK_REQUEST(cx);
400 0 js_FreeStack(cx, mark);
401 }
402
403 JS_PUBLIC_API(JSBool)
404 JS_AddArgumentFormatter(JSContext *cx, const char *format,
405 JSArgumentFormatter formatter)
406 0 {
407 size_t length;
408 JSArgumentFormatMap **mpp, *map;
409
410 0 length = strlen(format);
411 0 mpp = &cx->argumentFormatMap;
412 0 while ((map = *mpp) != NULL) {
413 /* Insert before any shorter string to match before prefixes. */
414 0 if (map->length < length)
415 0 break;
416 0 if (map->length == length && !strcmp(map->format, format))
417 0 goto out;
418 0 mpp = &map->next;
419 }
420 0 map = (JSArgumentFormatMap *) JS_malloc(cx, sizeof *map);
421 0 if (!map)
422 0 return JS_FALSE;
423 0 map->format = format;
424 0 map->length = length;
425 0 map->next = *mpp;
426 0 *mpp = map;
427 0 out:
428 0 map->formatter = formatter;
429 0 return JS_TRUE;
430 }
431
432 JS_PUBLIC_API(void)
433 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
434 0 {
435 size_t length;
436 JSArgumentFormatMap **mpp, *map;
437
438 0 length = strlen(format);
439 0 mpp = &cx->argumentFormatMap;
440 0 while ((map = *mpp) != NULL) {
441 0 if (map->length == length && !strcmp(map->format, format)) {
442 0 *mpp = map->next;
443 0 JS_free(cx, map);
444 0 return;
445 }
446 0 mpp = &map->next;
447 }
448 }
449
450 JS_PUBLIC_API(JSBool)
451 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
452 0 {
453 JSBool ok, b;
454 JSObject *obj;
455 JSString *str;
456 jsdouble d, *dp;
457
458 CHECK_REQUEST(cx);
459 0 switch (type) {
460 case JSTYPE_VOID:
461 0 *vp = JSVAL_VOID;
462 0 ok = JS_TRUE;
463 0 break;
464 case JSTYPE_OBJECT:
465 0 ok = js_ValueToObject(cx, v, &obj);
466 0 if (ok)
467 0 *vp = OBJECT_TO_JSVAL(obj);
468 break;
469 case JSTYPE_FUNCTION:
470 0 *vp = v;
471 0 obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK);
472 0 ok = (obj != NULL);
473 0 break;
474 case JSTYPE_STRING:
475 0 str = js_ValueToString(cx, v);
476 0 ok = (str != NULL);
477 0 if (ok)
478 0 *vp = STRING_TO_JSVAL(str);
479 break;
480 case JSTYPE_NUMBER:
481 0 ok = js_ValueToNumber(cx, v, &d);
482 0 if (ok) {
483 0 dp = js_NewDouble(cx, d, 0);
484 0 ok = (dp != NULL);
485 0 if (ok)
486 0 *vp = DOUBLE_TO_JSVAL(dp);
487 }
488 break;
489 case JSTYPE_BOOLEAN:
490 0 ok = js_ValueToBoolean(cx, v, &b);
491 0 if (ok)
492 0 *vp = BOOLEAN_TO_JSVAL(b);
493 break;
494 default: {
495 char numBuf[12];
496 0 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
497 0 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
498 numBuf);
499 0 ok = JS_FALSE;
500 break;
501 }
502 }
503 0 return ok;
504 }
505
506 JS_PUBLIC_API(JSBool)
507 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
508 0 {
509 CHECK_REQUEST(cx);
510 0 return js_ValueToObject(cx, v, objp);
511 }
512
513 JS_PUBLIC_API(JSFunction *)
514 JS_ValueToFunction(JSContext *cx, jsval v)
515 0 {
516 CHECK_REQUEST(cx);
517 0 return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
518 }
519
520 JS_PUBLIC_API(JSFunction *)
521 JS_ValueToConstructor(JSContext *cx, jsval v)
522 0 {
523 CHECK_REQUEST(cx);
524 0 return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
525 }
526
527 JS_PUBLIC_API(JSString *)
528 JS_ValueToString(JSContext *cx, jsval v)
529 334313 {
530 CHECK_REQUEST(cx);
531 334313 return js_ValueToString(cx, v);
532 }
533
534 JS_PUBLIC_API(JSBool)
535 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
536 0 {
537 CHECK_REQUEST(cx);
538 0 return js_ValueToNumber(cx, v, dp);
539 }
540
541 JS_PUBLIC_API(JSBool)
542 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
543 0 {
544 CHECK_REQUEST(cx);
545 0 return js_ValueToECMAInt32(cx, v, ip);
546 }
547
548 JS_PUBLIC_API(JSBool)
549 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
550 0 {
551 CHECK_REQUEST(cx);
552 0 return js_ValueToECMAUint32(cx, v, ip);
553 }
554
555 JS_PUBLIC_API(JSBool)
556 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
557 0 {
558 CHECK_REQUEST(cx);
559 0 return js_ValueToInt32(cx, v, ip);
560 }
561
562 JS_PUBLIC_API(JSBool)
563 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
564 0 {
565 CHECK_REQUEST(cx);
566 0 return js_ValueToUint16(cx, v, ip);
567 }
568
569 JS_PUBLIC_API(JSBool)
570 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
571 0 {
572 CHECK_REQUEST(cx);
573 0 return js_ValueToBoolean(cx, v, bp);
574 }
575
576 JS_PUBLIC_API(JSType)
577 JS_TypeOfValue(JSContext *cx, jsval v)
578 0 {
579 JSType type;
580 JSObject *obj;
581 JSObjectOps *ops;
582 JSClass *clasp;
583
584 CHECK_REQUEST(cx);
585 0 if (JSVAL_IS_OBJECT(v)) {
586 0 type = JSTYPE_OBJECT; /* XXXbe JSTYPE_NULL for JS2 */
587 0 obj = JSVAL_TO_OBJECT(v);
588 0 if (obj) {
589 0 ops = obj->map->ops;
590 #if JS_HAS_XML_SUPPORT
591 0 if (ops == &js_XMLObjectOps.base) {
592 0 type = JSTYPE_XML;
593 } else
594 #endif
595 {
596 /*
597 * ECMA 262, 11.4.3 says that any native object that implements
598 * [[Call]] should be of type "function". Note that RegExp and
599 * Script are both of type "function" for compatibility with
600 * older SpiderMonkeys.
601 */
602 0 clasp = OBJ_GET_CLASS(cx, obj);
603 0 if ((ops == &js_ObjectOps)
604 ? (clasp->call
605 ? (clasp == &js_RegExpClass || clasp == &js_ScriptClass)
606 : clasp == &js_FunctionClass)
607 : ops->call != NULL) {
608 0 type = JSTYPE_FUNCTION;
609 } else {
610 #ifdef NARCISSUS
611 if (!OBJ_GET_PROPERTY(cx, obj,
612 ATOM_TO_JSID(cx->runtime->atomState
613 .callAtom),
614 &v)) {
615 JS_ClearPendingException(cx);
616 } else if (JSVAL_IS_FUNCTION(cx, v)) {
617 type = JSTYPE_FUNCTION;
618 }
619 #endif
620 }
621 }
622 }
623 0 } else if (JSVAL_IS_NUMBER(v)) {
624 0 type = JSTYPE_NUMBER;
625 0 } else if (JSVAL_IS_STRING(v)) {
626 0 type = JSTYPE_STRING;
627 0 } else if (JSVAL_IS_BOOLEAN(v)) {
628 0 type = JSTYPE_BOOLEAN;
629 } else {
630 0 type = JSTYPE_VOID;
631 }
632 0 return type;
633 }
634
635 JS_PUBLIC_API(const char *)
636 JS_GetTypeName(JSContext *cx, JSType type)
637 0 {
638 0 if ((uintN)type >= (uintN)JSTYPE_LIMIT)
639 0 return NULL;
640 0 return js_type_str[type];
641 }
642
643 /************************************************************************/
644
645 JS_PUBLIC_API(JSRuntime *)
646 JS_NewRuntime(uint32 maxbytes)
647 17 {
648 JSRuntime *rt;
649
650 #ifdef DEBUG
651 JS_BEGIN_MACRO
652 /*
653 * This code asserts that the numbers associated with the error names in
654 * jsmsg.def are monotonically increasing. It uses values for the error
655 * names enumerated in jscntxt.c. It's not a compiletime check, but it's
656 * better than nothing.
657 */
658 int errorNumber = 0;
659 #define MSG_DEF(name, number, count, exception, format) \
660 JS_ASSERT(name == errorNumber++);
661 #include "js.msg"
662 #undef MSG_DEF
663 JS_END_MACRO;
664 #endif /* DEBUG */
665
666 17 if (!js_InitStringGlobals())
667 0 return NULL;
668 17 rt = (JSRuntime *) malloc(sizeof(JSRuntime));
669 17 if (!rt)
670 0 return NULL;
671
672 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
673 17 memset(rt, 0, sizeof(JSRuntime));
674 17 JS_INIT_CLIST(&rt->contextList);
675 17 JS_INIT_CLIST(&rt->trapList);
676 17 JS_INIT_CLIST(&rt->watchPointList);
677
678 17 if (!js_InitGC(rt, maxbytes))
679 17 goto bad;
680 #ifdef JS_THREADSAFE
681 rt->gcLock = JS_NEW_LOCK();
682 if (!rt->gcLock)
683 goto bad;
684 rt->gcDone = JS_NEW_CONDVAR(rt->gcLock);
685 if (!rt->gcDone)
686 goto bad;
687 rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
688 if (!rt->requestDone)
689 goto bad;
690 /* this is asymmetric with JS_ShutDown: */
691 if (!js_SetupLocks(8, 16))
692 goto bad;
693 rt->rtLock = JS_NEW_LOCK();
694 if (!rt->rtLock)
695 goto bad;
696 rt->stateChange = JS_NEW_CONDVAR(rt->gcLock);
697 if (!rt->stateChange)
698 goto bad;
699 rt->setSlotLock = JS_NEW_LOCK();
700 if (!rt->setSlotLock)
701 goto bad;
702 rt->setSlotDone = JS_NEW_CONDVAR(rt->setSlotLock);
703 if (!rt->setSlotDone)
704 goto bad;
705 rt->scopeSharingDone = JS_NEW_CONDVAR(rt->gcLock);
706 if (!rt->scopeSharingDone)
707 goto bad;
708 rt->scopeSharingTodo = NO_SCOPE_SHARING_TODO;
709 #endif
710 17 rt->propertyCache.empty = JS_TRUE;
711 17 if (!js_InitPropertyTree(rt))
712 17 goto bad;
713 17 return rt;
714
715 0 bad:
716 0 JS_DestroyRuntime(rt);
717 0 return NULL;
718 }
719
720 JS_PUBLIC_API(void)
721 JS_DestroyRuntime(JSRuntime *rt)
722 17 {
723 #ifdef DEBUG
724 /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
725 if (!JS_CLIST_IS_EMPTY(&rt->contextList)) {
726 JSContext *cx, *iter = NULL;
727 uintN cxcount = 0;
728 while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)
729 cxcount++;
730 fprintf(stderr,
731 "JS API usage error: %u contexts left in runtime upon JS_DestroyRuntime.\n",
732 cxcount);
733 }
734 #endif
735
736 17 js_FreeRuntimeScriptState(rt);
737 17 js_FinishAtomState(&rt->atomState);
738 17 js_FinishGC(rt);
739 #ifdef JS_THREADSAFE
740 if (rt->gcLock)
741 JS_DESTROY_LOCK(rt->gcLock);
742 if (rt->gcDone)
743 JS_DESTROY_CONDVAR(rt->gcDone);
744 if (rt->requestDone)
745 JS_DESTROY_CONDVAR(rt->requestDone);
746 if (rt->rtLock)
747 JS_DESTROY_LOCK(rt->rtLock);
748 if (rt->stateChange)
749 JS_DESTROY_CONDVAR(rt->stateChange);
750 if (rt->setSlotLock)
751 JS_DESTROY_LOCK(rt->setSlotLock);
752 if (rt->setSlotDone)
753 JS_DESTROY_CONDVAR(rt->setSlotDone);
754 if (rt->scopeSharingDone)
755 JS_DESTROY_CONDVAR(rt->scopeSharingDone);
756 #endif
757 17 js_FinishPropertyTree(rt);
758 17 free(rt);
759 }
760
761 JS_PUBLIC_API(void)
762 JS_ShutDown(void)
763 0 {
764 0 JS_ArenaShutDown();
765 0 js_FinishDtoa();
766 0 js_FreeStringGlobals();
767 #ifdef JS_THREADSAFE
768 js_CleanupLocks();
769 #endif
770 }
771
772 JS_PUBLIC_API(void *)
773 JS_GetRuntimePrivate(JSRuntime *rt)
774 0 {
775 0 return rt->data;
776 }
777
778 JS_PUBLIC_API(void)
779 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
780 0 {
781 0 rt->data = data;
782 }
783
784 #ifdef JS_THREADSAFE
785
786 JS_PUBLIC_API(void)
787 JS_BeginRequest(JSContext *cx)
788 {
789 JSRuntime *rt;
790
791 JS_ASSERT(cx->thread);
792 if (!cx->requestDepth) {
793 /* Wait until the GC is finished. */
794 rt = cx->runtime;
795 JS_LOCK_GC(rt);
796
797 /* NB: we use cx->thread here, not js_CurrentThreadId(). */
798 if (rt->gcThread != cx->thread) {
799 while (rt->gcLevel > 0)
800 JS_AWAIT_GC_DONE(rt);
801 }
802
803 /* Indicate that a request is running. */
804 rt->requestCount++;
805 cx->requestDepth = 1;
806 JS_UNLOCK_GC(rt);
807 return;
808 }
809 cx->requestDepth++;
810 }
811
812 JS_PUBLIC_API(void)
813 JS_EndRequest(JSContext *cx)
814 {
815 JSRuntime *rt;
816 JSScope *scope, **todop;
817 uintN nshares;
818
819 CHECK_REQUEST(cx);
820 JS_ASSERT(cx->requestDepth > 0);
821 if (cx->requestDepth == 1) {
822 /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
823 rt = cx->runtime;
824 JS_LOCK_GC(rt);
825 cx->requestDepth = 0;
826
827 /* See whether cx has any single-threaded scopes to start sharing. */
828 todop = &rt->scopeSharingTodo;
829 nshares = 0;
830 while ((scope = *todop) != NO_SCOPE_SHARING_TODO) {
831 if (scope->ownercx != cx) {
832 todop = &scope->u.link;
833 continue;
834 }
835 *todop = scope->u.link;
836 scope->u.link = NULL; /* null u.link for sanity ASAP */
837
838 /*
839 * If js_DropObjectMap returns null, we held the last ref to scope.
840 * The waiting thread(s) must have been killed, after which the GC
841 * collected the object that held this scope. Unlikely, because it
842 * requires that the GC ran (e.g., from a branch callback) during
843 * this request, but possible.
844 */
845 if (js_DropObjectMap(cx, &scope->map, NULL)) {
846 js_InitLock(&scope->lock);
847 scope->u.count = 0; /* NULL may not pun as 0 */
848 js_FinishSharingScope(rt, scope); /* set ownercx = NULL */
849 nshares++;
850 }
851 }
852 if (nshares)
853 JS_NOTIFY_ALL_CONDVAR(rt->scopeSharingDone);
854
855 /* Give the GC a chance to run if this was the last request running. */
856 JS_ASSERT(rt->requestCount > 0);
857 rt->requestCount--;
858 if (rt->requestCount == 0)
859 JS_NOTIFY_REQUEST_DONE(rt);
860
861 JS_UNLOCK_GC(rt);
862 return;
863 }
864
865 cx->requestDepth--;
866 }
867
868 /* Yield to pending GC operations, regardless of request depth */
869 JS_PUBLIC_API(void)
870 JS_YieldRequest(JSContext *cx)
871 {
872 JSRuntime *rt;
873
874 JS_ASSERT(cx->thread);
875 CHECK_REQUEST(cx);
876
877 rt = cx->runtime;
878 JS_LOCK_GC(rt);
879 JS_ASSERT(rt->requestCount > 0);
880 rt->requestCount--;
881 if (rt->requestCount == 0)
882 JS_NOTIFY_REQUEST_DONE(rt);
883 JS_UNLOCK_GC(rt);
884 /* XXXbe give the GC or another request calling it a chance to run here?
885 Assumes FIFO scheduling */
886 JS_LOCK_GC(rt);
887 rt->requestCount++;
888 JS_UNLOCK_GC(rt);
889 }
890
891 JS_PUBLIC_API(jsrefcount)
892 JS_SuspendRequest(JSContext *cx)
893 {
894 jsrefcount saveDepth = cx->requestDepth;
895
896 while (cx->requestDepth)
897 JS_EndRequest(cx);
898 return saveDepth;
899 }
900
901 JS_PUBLIC_API(void)
902 JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
903 {
904 JS_ASSERT(!cx->requestDepth);
905 while (--saveDepth >= 0)
906 JS_BeginRequest(cx);
907 }
908
909 #endif /* JS_THREADSAFE */
910
911 JS_PUBLIC_API(void)
912 JS_Lock(JSRuntime *rt)
913 0 {
914 JS_LOCK_RUNTIME(rt);
915 }
916
917 JS_PUBLIC_API(void)
918 JS_Unlock(JSRuntime *rt)
919 0 {
920 JS_UNLOCK_RUNTIME(rt);
921 }
922
923 JS_PUBLIC_API(JSContext *)
924 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
925 17 {
926 17 return js_NewContext(rt, stackChunkSize);
927 }
928
929 JS_PUBLIC_API(void)
930 JS_DestroyContext(JSContext *cx)
931 17 {
932 17 js_DestroyContext(cx, JS_FORCE_GC);
933 }
934
935 JS_PUBLIC_API(void)
936 JS_DestroyContextNoGC(JSContext *cx)
937 0 {
938 0 js_DestroyContext(cx, JS_NO_GC);
939 }
940
941 JS_PUBLIC_API(void)
942 JS_DestroyContextMaybeGC(JSContext *cx)
943 0 {
944 0 js_DestroyContext(cx, JS_MAYBE_GC);
945 }
946
947 JS_PUBLIC_API(void *)
948 JS_GetContextPrivate(JSContext *cx)
949 332298 {
950 332298 return cx->data;
951 }
952
953 JS_PUBLIC_API(void)
954 JS_SetContextPrivate(JSContext *cx, void *data)
955 2469 {
956 2469 cx->data = data;
957 }
958
959 JS_PUBLIC_API(JSRuntime *)
960 JS_GetRuntime(JSContext *cx)
961 0 {
962 0 return cx->runtime;
963 }
964
965 JS_PUBLIC_API(JSContext *)
966 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
967 0 {
968 0 return js_ContextIterator(rt, JS_TRUE, iterp);
969 }
970
971 JS_PUBLIC_API(JSVersion)
972 JS_GetVersion(JSContext *cx)
973 0 {
974 0 return cx->version & JSVERSION_MASK;
975 }
976
977 JS_PUBLIC_API(JSVersion)
978 JS_SetVersion(JSContext *cx, JSVersion version)
979 0 {
980 JSVersion oldVersion;
981
982 JS_ASSERT(version != JSVERSION_UNKNOWN);
983 JS_ASSERT((version & ~JSVERSION_MASK) == 0);
984
985 0 oldVersion = cx->version & JSVERSION_MASK;
986 0 if (version == oldVersion)
987 0 return oldVersion;
988
989 0 cx->version = (cx->version & ~JSVERSION_MASK) | version;
990 0 js_OnVersionChange(cx);
991 0 return oldVersion;
992 }
993
994 static struct v2smap {
995 JSVersion version;
996 const char *string;
997 } v2smap[] = {
998 {JSVERSION_1_0, "1.0"},
999 {JSVERSION_1_1, "1.1"},
1000 {JSVERSION_1_2, "1.2"},
1001 {JSVERSION_1_3, "1.3"},
1002 {JSVERSION_1_4, "1.4"},
1003 {JSVERSION_ECMA_3, "ECMAv3"},
1004 {JSVERSION_1_5, "1.5"},
1005 {JSVERSION_1_6, "1.6"},
1006 {JSVERSION_DEFAULT, js_default_str},
1007 {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
1008 };
1009
1010 JS_PUBLIC_API(const char *)
1011 JS_VersionToString(JSVersion version)
1012 0 {
1013 int i;
1014
1015 0 for (i = 0; v2smap[i].string; i++)
1016 0 if (v2smap[i].version == version)
1017 0 return v2smap[i].string;
1018 0 return "unknown";
1019 }
1020
1021 JS_PUBLIC_API(JSVersion)
1022 JS_StringToVersion(const char *string)
1023 0 {
1024 int i;
1025
1026 0 for (i = 0; v2smap[i].string; i++)
1027 0 if (strcmp(v2smap[i].string, string) == 0)
1028 0 return v2smap[i].version;
1029 0 return JSVERSION_UNKNOWN;
1030 }
1031
1032 JS_PUBLIC_API(uint32)
1033 JS_GetOptions(JSContext *cx)
1034 0 {
1035 0 return cx->options;
1036 }
1037
1038 #define SYNC_OPTIONS_TO_VERSION(cx) \
1039 JS_BEGIN_MACRO \
1040 if ((cx)->options & JSOPTION_XML) \
1041 (cx)->version |= JSVERSION_HAS_XML; \
1042 else \
1043 (cx)->version &= ~JSVERSION_HAS_XML; \
1044 JS_END_MACRO
1045
1046 JS_PUBLIC_API(uint32)
1047 JS_SetOptions(JSContext *cx, uint32 options)
1048 0 {
1049 0 uint32 oldopts = cx->options;
1050 0 cx->options = options;
1051 0 SYNC_OPTIONS_TO_VERSION(cx);
1052 0 return oldopts;
1053 }
1054
1055 JS_PUBLIC_API(uint32)
1056 JS_ToggleOptions(JSContext *cx, uint32 options)
1057 0 {
1058 0 uint32 oldopts = cx->options;
1059 0 cx->options ^= options;
1060 0 SYNC_OPTIONS_TO_VERSION(cx);
1061 0 return oldopts;
1062 }
1063
1064 JS_PUBLIC_API(const char *)
1065 JS_GetImplementationVersion(void)
1066 0 {
1067 0 return "JavaScript-C 1.6 2006-11-19";
1068 }
1069
1070
1071 JS_PUBLIC_API(JSObject *)
1072 JS_GetGlobalObject(JSContext *cx)
1073 64 {
1074 64 return cx->globalObject;
1075 }
1076
1077 JS_PUBLIC_API(void)
1078 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1079 17 {
1080 17 cx->globalObject = obj;
1081 #if JS_HAS_XML_SUPPORT
1082 17 cx->xmlSettingFlags = 0;
1083 #endif
1084 }
1085
1086 static JSObject *
1087 InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1088 17 {
1089 JSDHashTable *table;
1090 JSBool resolving;
1091 JSRuntime *rt;
1092 JSResolvingKey key;
1093 JSResolvingEntry *entry;
1094 JSObject *fun_proto, *obj_proto;
1095
1096 /* If cx has no global object, use obj so prototypes can be found. */
1097 17 if (!cx->globalObject)
1098 17 JS_SetGlobalObject(cx, obj);
1099
1100 /* Record Function and Object in cx->resolvingTable, if we are resolving. */
1101 17 table = cx->resolvingTable;
1102 17 resolving = (table && table->entryCount);
1103 17 if (resolving) {
1104 0 rt = cx->runtime;
1105 0 key.obj = obj;
1106 0 key.id = ATOM_TO_JSID(rt->atomState.FunctionAtom);
1107 0 entry = (JSResolvingEntry *)
1108 JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1109 0 if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) {
1110 /* Already resolving Function, record Object too. */
1111 JS_ASSERT(entry->key.obj == obj);
1112 0 key.id = ATOM_TO_JSID(rt->atomState.ObjectAtom);
1113 0 entry = (JSResolvingEntry *)
1114 JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1115 }
1116 0 if (!entry) {
1117 0 JS_ReportOutOfMemory(cx);
1118 0 return NULL;
1119 }
1120 JS_ASSERT(!entry->key.obj && entry->flags == 0);
1121 0 entry->key = key;
1122 0 entry->flags = JSRESFLAG_LOOKUP;
1123 }
1124
1125 /* Initialize the function class first so constructors can be made. */
1126 17 fun_proto = js_InitFunctionClass(cx, obj);
1127 17 if (!fun_proto)
1128 17 goto out;
1129
1130 /* Initialize the object class next so Object.prototype works. */
1131 17 obj_proto = js_InitObjectClass(cx, obj);
1132 17 if (!obj_proto) {
1133 0 fun_proto = NULL;
1134 0 goto out;
1135 }
1136
1137 /* Function.prototype and the global object delegate to Object.prototype. */
1138 17 OBJ_SET_PROTO(cx, fun_proto, obj_proto);
1139 17 if (!OBJ_GET_PROTO(cx, obj))
1140 17 OBJ_SET_PROTO(cx, obj, obj_proto);
1141
1142 17 out:
1143 /* If resolving, remove the other entry (Object or Function) from table. */
1144 17 if (resolving)
1145 0 JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1146 17 return fun_proto;
1147 }
1148
1149 JS_PUBLIC_API(JSBool)
1150 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1151 17 {
1152 CHECK_REQUEST(cx);
1153
1154 #if JS_HAS_UNDEFINED
1155 {
1156 /* Define a top-level property 'undefined' with the undefined value. */
1157 17 JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1158 17 if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1159 NULL, NULL, JSPROP_PERMANENT, NULL)) {
1160 0 return JS_FALSE;
1161 }
1162 }
1163 #endif
1164
1165 /* Function and Object require cooperative bootstrapping magic. */
1166 17 if (!InitFunctionAndObjectClasses(cx, obj))
1167 0 return JS_FALSE;
1168
1169 /* Initialize the rest of the standard objects and functions. */
1170 17 return js_InitArrayClass(cx, obj) &&
1171 js_InitBooleanClass(cx, obj) &&
1172 js_InitMathClass(cx, obj) &&
1173 js_InitNumberClass(cx, obj) &&
1174 js_InitStringClass(cx, obj) &&
1175 #if JS_HAS_CALL_OBJECT
1176 js_InitCallClass(cx, obj) &&
1177 #endif
1178 #if JS_HAS_REGEXPS
1179 js_InitRegExpClass(cx, obj) &&
1180 #endif
1181 #if JS_HAS_SCRIPT_OBJECT
1182 js_InitScriptClass(cx, obj) &&
1183 #endif
1184 #if JS_HAS_ERROR_EXCEPTIONS
1185 js_InitExceptionClasses(cx, obj) &&
1186 #endif
1187 #if JS_HAS_XML_SUPPORT
1188 js_InitXMLClasses(cx, obj) &&
1189 #endif
1190 #if JS_HAS_FILE_OBJECT
1191 js_InitFileClass(cx, obj) &&
1192 #endif
1193 js_InitDateClass(cx, obj);
1194 }
1195
1196 #define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom)
1197 #define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
1198
1199 /*
1200 * Table of class initializers and their atom offsets in rt->atomState.
1201 * If you add a "standard" class, remember to update this table.
1202 */
1203 static struct {
1204 JSObjectOp init;
1205 size_t atomOffset;
1206 } standard_class_atoms[] = {
1207 {InitFunctionAndObjectClasses, ATOM_OFFSET(Function)},
1208 {InitFunctionAndObjectClasses, ATOM_OFFSET(Object)},
1209 {js_InitArrayClass, ATOM_OFFSET(Array)},
1210 {js_InitBooleanClass, ATOM_OFFSET(Boolean)},
1211 {js_InitDateClass, ATOM_OFFSET(Date)},
1212 {js_InitMathClass, ATOM_OFFSET(Math)},
1213 {js_InitNumberClass, ATOM_OFFSET(Number)},
1214 {js_InitStringClass, ATOM_OFFSET(String)},
1215 #if JS_HAS_CALL_OBJECT
1216 {js_InitCallClass, ATOM_OFFSET(Call)},
1217 #endif
1218 #if JS_HAS_ERROR_EXCEPTIONS
1219 {js_InitExceptionClasses, ATOM_OFFSET(Error)},
1220 #endif
1221 #if JS_HAS_REGEXPS
1222 {js_InitRegExpClass, ATOM_OFFSET(RegExp)},
1223 #endif
1224 #if JS_HAS_SCRIPT_OBJECT
1225 {js_InitScriptClass, ATOM_OFFSET(Script)},
1226 #endif
1227 #if JS_HAS_XML_SUPPORT
1228 {js_InitXMLClass, ATOM_OFFSET(XML)},
1229 {js_InitNamespaceClass, ATOM_OFFSET(Namespace)},
1230 {js_InitQNameClass, ATOM_OFFSET(QName)},
1231 #endif
1232 #if JS_HAS_FILE_OBJECT
1233 {js_InitFileClass, ATOM_OFFSET(File)},
1234 #endif
1235 {NULL, 0}
1236 };
1237
1238 /*
1239 * Table of top-level function and constant names and their init functions.
1240 * If you add a "standard" global function or property, remember to update
1241 * this table.
1242 */
1243 typedef struct JSStdName {
1244 JSObjectOp init;
1245 size_t atomOffset; /* offset of atom pointer in JSAtomState */
1246 const char *name; /* null if atom is pre-pinned, else name */
1247 } JSStdName;
1248
1249 static JSAtom *
1250 StdNameToAtom(JSContext *cx, JSStdName *stdn)
1251 0 {
1252 size_t offset;
1253 JSAtom *atom;
1254 const char *name;
1255
1256 0 offset = stdn->atomOffset;
1257 0 atom = OFFSET_TO_ATOM(cx->runtime, offset);
1258 0 if (!atom) {
1259 0 name = stdn->name;
1260 0 if (name) {
1261 0 atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1262 0 OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1263 }
1264 }
1265 0 return atom;
1266 }
1267
1268 #define EAGERLY_PINNED_ATOM(name) ATOM_OFFSET(name), NULL
1269 #define LAZILY_PINNED_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
1270
1271 static JSStdName standard_class_names[] = {
1272 /* ECMA requires that eval be a direct property of the global object. */
1273 {js_InitObjectClass, EAGERLY_PINNED_ATOM(eval)},
1274
1275 /* Global properties and functions defined by the Number class. */
1276 {js_InitNumberClass, LAZILY_PINNED_ATOM(NaN)},
1277 {js_InitNumberClass, LAZILY_PINNED_ATOM(Infinity)},
1278 {js_InitNumberClass, LAZILY_PINNED_ATOM(isNaN)},
1279 {js_InitNumberClass, LAZILY_PINNED_ATOM(isFinite)},
1280 {js_InitNumberClass, LAZILY_PINNED_ATOM(parseFloat)},
1281 {js_InitNumberClass, LAZILY_PINNED_ATOM(parseInt)},
1282
1283 /* String global functions. */
1284 {js_InitStringClass, LAZILY_PINNED_ATOM(escape)},
1285 {js_InitStringClass, LAZILY_PINNED_ATOM(unescape)},
1286 {js_InitStringClass, LAZILY_PINNED_ATOM(decodeURI)},
1287 {js_InitStringClass, LAZILY_PINNED_ATOM(encodeURI)},
1288 {js_InitStringClass, LAZILY_PINNED_ATOM(decodeURIComponent)},
1289 {js_InitStringClass, LAZILY_PINNED_ATOM(encodeURIComponent)},
1290 #if JS_HAS_UNEVAL
1291 {js_InitStringClass, LAZILY_PINNED_ATOM(uneval)},
1292 #endif
1293
1294 /* Exception constructors. */
1295 #if JS_HAS_ERROR_EXCEPTIONS
1296 {js_InitExceptionClasses, EAGERLY_PINNED_ATOM(Error)},
1297 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(InternalError)},
1298 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(EvalError)},
1299 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(RangeError)},
1300 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(ReferenceError)},
1301 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(SyntaxError)},
1302 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(TypeError)},
1303 {js_InitExceptionClasses, LAZILY_PINNED_ATOM(URIError)},
1304 #endif
1305
1306 #if JS_HAS_XML_SUPPORT
1307 {js_InitAnyNameClass, LAZILY_PINNED_ATOM(AnyName)},
1308 {js_InitAttributeNameClass, LAZILY_PINNED_ATOM(AttributeName)},
1309 {js_InitXMLClass, LAZILY_PINNED_ATOM(XMLList)},
1310 {js_InitXMLClass, LAZILY_PINNED_ATOM(isXMLName)},
1311 #endif
1312
1313 {NULL, 0, NULL}
1314 };
1315
1316 static JSStdName object_prototype_names[] = {
1317 /* Object.prototype properties (global delegates to Object.prototype). */
1318 {js_InitObjectClass, EAGERLY_PINNED_ATOM(proto)},
1319 {js_InitObjectClass, EAGERLY_PINNED_ATOM(parent)},
1320 {js_InitObjectClass, EAGERLY_PINNED_ATOM(count)},
1321 #if JS_HAS_TOSOURCE
1322 {js_InitObjectClass, EAGERLY_PINNED_ATOM(toSource)},
1323 #endif
1324 {js_InitObjectClass, EAGERLY_PINNED_ATOM(toString)},
1325 {js_InitObjectClass, EAGERLY_PINNED_ATOM(toLocaleString)},
1326 {js_InitObjectClass, EAGERLY_PINNED_ATOM(valueOf)},
1327 #if JS_HAS_OBJ_WATCHPOINT
1328 {js_InitObjectClass, LAZILY_PINNED_ATOM(watch)},
1329 {js_InitObjectClass, LAZILY_PINNED_ATOM(unwatch)},
1330 #endif
1331 #if JS_HAS_NEW_OBJ_METHODS
1332 {js_InitObjectClass, LAZILY_PINNED_ATOM(hasOwnProperty)},
1333 {js_InitObjectClass, LAZILY_PINNED_ATOM(isPrototypeOf)},
1334 {js_InitObjectClass, LAZILY_PINNED_ATOM(propertyIsEnumerable)},
1335 #endif
1336 #if JS_HAS_GETTER_SETTER
1337 {js_InitObjectClass, LAZILY_PINNED_ATOM(defineGetter)},
1338 {js_InitObjectClass, LAZILY_PINNED_ATOM(defineSetter)},
1339 {js_InitObjectClass, LAZILY_PINNED_ATOM(lookupGetter)},
1340 {js_InitObjectClass, LAZILY_PINNED_ATOM(lookupSetter)},
1341 #endif
1342
1343 {NULL, 0, NULL}
1344 };
1345
1346 #undef EAGERLY_PINNED_ATOM
1347 #undef LAZILY_PINNED_ATOM
1348
1349 JS_PUBLIC_API(JSBool)
1350 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
1351 JSBool *resolved)
1352 0 {
1353 JSString *idstr;
1354 JSRuntime *rt;
1355 JSAtom *atom;
1356 JSObjectOp init;
1357 uintN i;
1358
1359 CHECK_REQUEST(cx);
1360 0 *resolved = JS_FALSE;
1361
1362 0 if (!JSVAL_IS_STRING(id))
1363 0 return JS_TRUE;
1364 0 idstr = JSVAL_TO_STRING(id);
1365 0 rt = cx->runtime;
1366
1367 #if JS_HAS_UNDEFINED
1368 /* Check whether we're resolving 'undefined', and define it if so. */
1369 0 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1370 0 if (idstr == ATOM_TO_STRING(atom)) {
1371 0 *resolved = JS_TRUE;
1372 0 return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1373 NULL, NULL, JSPROP_PERMANENT, NULL);
1374 }
1375 #endif
1376
1377 /* Try for class constructors/prototypes named by well-known atoms. */
1378 0 init = NULL;
1379 0 for (i = 0; standard_class_atoms[i].init; i++) {
1380 0 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1381 0 if (idstr == ATOM_TO_STRING(atom)) {
1382 0 init = standard_class_atoms[i].init;
1383 0 break;
1384 }
1385 }
1386
1387 0 if (!init) {
1388 /* Try less frequently used top-level functions and constants. */
1389 0 for (i = 0; standard_class_names[i].init; i++) {
1390 0 atom = StdNameToAtom(cx, &standard_class_names[i]);
1391 0 if (!atom)
1392 0 return JS_FALSE;
1393 0 if (idstr == ATOM_TO_STRING(atom)) {
1394 0 init = standard_class_names[i].init;
1395 0 break;
1396 }
1397 }
1398
1399 0 if (!init && !OBJ_GET_PROTO(cx, obj)) {
1400 /*
1401 * Try even less frequently used names delegated from the global
1402 * object to Object.prototype, but only if the Object class hasn't
1403 * yet been initialized.
1404 */
1405 0 for (i = 0; object_prototype_names[i].init; i++) {
1406 0 atom = StdNameToAtom(cx, &object_prototype_names[i]);
1407 0 if (!atom)
1408 0 return JS_FALSE;
1409 0 if (idstr == ATOM_TO_STRING(atom)) {
1410 0 init = standard_class_names[i].init;
1411 0 break;
1412 }
1413 }
1414 }
1415 }
1416
1417 0 if (init) {
1418 0 if (!init(cx, obj))
1419 0 return JS_FALSE;
1420 0 *resolved = JS_TRUE;
1421 }
1422 0 return JS_TRUE;
1423 }
1424
1425 static JSBool
1426 AlreadyHasOwnProperty(JSObject *obj, JSAtom *atom)
1427 0 {
1428 JS_ASSERT(OBJ_IS_NATIVE(obj));
1429 0 return SCOPE_GET_PROPERTY(OBJ_SCOPE(obj), ATOM_TO_JSID(atom)) != NULL;
1430 }
1431
1432 JS_PUBLIC_API(JSBool)
1433 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1434 0 {
1435 JSRuntime *rt;
1436 JSAtom *atom;
1437 uintN i;
1438
1439 CHECK_REQUEST(cx);
1440 0 rt = cx->runtime;
1441
1442 #if JS_HAS_UNDEFINED
1443 /* Check whether we need to bind 'undefined' and define it if so. */
1444 0 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1445 0 if (!AlreadyHasOwnProperty(obj, atom) &&
1446 !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1447 NULL, NULL, JSPROP_PERMANENT, NULL)) {
1448 0 return JS_FALSE;
1449 }
1450 #endif
1451
1452 /* Initialize any classes that have not been resolved yet. */
1453 0 for (i = 0; standard_class_atoms[i].init; i++) {
1454 0 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1455 0 if (!AlreadyHasOwnProperty(obj, atom) &&
1456 !standard_class_atoms[i].init(cx, obj)) {
1457 0 return JS_FALSE;
1458 }
1459 }
1460
1461 0 return JS_TRUE;
1462 }
1463
1464 static JSIdArray *
1465 AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1466 0 {
1467 jsint i, length;
1468
1469 0 i = *ip;
1470 0 length = ida->length;
1471 0 if (i >= length) {
1472 0 ida = js_SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
1473 0 if (!ida)
1474 0 return NULL;
1475 JS_ASSERT(i < ida->length);
1476 }
1477 0 ida->vector[i] = ATOM_TO_JSID(atom);
1478 0 *ip = i + 1;
1479 0 return ida;
1480 }
1481
1482 static JSIdArray *
1483 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
1484 jsint *ip, JSBool *foundp)
1485 0 {
1486 0 *foundp = AlreadyHasOwnProperty(obj, atom);
1487 0 if (*foundp)
1488 0 ida = AddAtomToArray(cx, atom, ida, ip);
1489 0 return ida;
1490 }
1491
1492 JS_PUBLIC_API(JSIdArray *)
1493 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
1494 JSIdArray *ida)
1495 0 {
1496 JSRuntime *rt;
1497 jsint i, j, k;
1498 JSAtom *atom;
1499 JSBool found;
1500 JSObjectOp init;
1501
1502 CHECK_REQUEST(cx);
1503 0 rt = cx->runtime;
1504 0 if (ida) {
1505 0 i = ida->length;
1506 } else {
1507 0 ida = js_NewIdArray(cx, 8);
1508 0 if (!ida)
1509 0 return NULL;
1510 0 i = 0;
1511 }
1512
1513 #if JS_HAS_UNDEFINED
1514 /* Check whether 'undefined' has been resolved and enumerate it if so. */
1515 0 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1516 0 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1517 0 if (!ida)
1518 0 return NULL;
1519 #endif
1520
1521 /* Enumerate only classes that *have* been resolved. */
1522 0 for (j = 0; standard_class_atoms[j].init; j++) {
1523 0 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
1524 0 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1525 0 if (!ida)
1526 0 return NULL;
1527
1528 0 if (found) {
1529 0 init = standard_class_atoms[j].init;
1530
1531 0 for (k = 0; standard_class_names[k].init; k++) {
1532 0 if (standard_class_names[k].init == init) {
1533 0 atom = StdNameToAtom(cx, &standard_class_names[k]);
1534 0 ida = AddAtomToArray(cx, atom, ida, &i);
1535 0 if (!ida)
1536 0 return NULL;
1537 }
1538 }
1539
1540 0 if (init == js_InitObjectClass) {
1541 0 for (k = 0; object_prototype_names[k].init; k++) {
1542 0 atom = StdNameToAtom(cx, &object_prototype_names[k]);
1543 0 ida = AddAtomToArray(cx, atom, ida, &i);
1544 0 if (!ida)
1545 0 return NULL;
1546 }
1547 }
1548 }
1549 }
1550
1551 /* Trim to exact length via js_SetIdArrayLength. */
1552 0 return js_SetIdArrayLength(cx, ida, i);
1553 }
1554
1555 #undef ATOM_OFFSET
1556 #undef OFFSET_TO_ATOM
1557
1558 JS_PUBLIC_API(JSObject *)
1559 JS_GetScopeChain(JSContext *cx)
1560 0 {
1561 0 return cx->fp ? cx->fp->scopeChain : NULL;
1562 }
1563
1564 JS_PUBLIC_API(void *)
1565 JS_malloc(JSContext *cx, size_t nbytes)
1566 523600 {
1567 void *p;
1568
1569 JS_ASSERT(nbytes != 0);
1570 523600 if (nbytes == 0)
1571 0 nbytes = 1;
1572 523600 cx->runtime->gcMallocBytes += nbytes;
1573 523600 p = malloc(nbytes);
1574 523600 if (!p)
1575 0 JS_ReportOutOfMemory(cx);
1576 523600 return p;
1577 }
1578
1579 JS_PUBLIC_API(void *)
1580 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1581 84540 {
1582 84540 p = realloc(p, nbytes);
1583 84540 if (!p)
1584 0 JS_ReportOutOfMemory(cx);
1585 84540 return p;
1586 }
1587
1588 JS_PUBLIC_API(void)
1589 JS_free(JSContext *cx, void *p)
1590 584683 {
1591 584683 if (p)
1592 584683 free(p);
1593 }
1594
1595 JS_PUBLIC_API(char *)
1596 JS_strdup(JSContext *cx, const char *s)
1597 51 {
1598 size_t n;
1599 void *p;
1600
1601 51 n = strlen(s) + 1;
1602 51 p = JS_malloc(cx, n);
1603 51 if (!p)
1604 0 return NULL;
1605 51 return (char *)memcpy(p, s, n);
1606 }
1607
1608 JS_PUBLIC_API(jsdouble *)
1609 JS_NewDouble(JSContext *cx, jsdouble d)
1610 0 {
1611 CHECK_REQUEST(cx);
1612 0 return js_NewDouble(cx, d, 0);
1613 }
1614
1615 JS_PUBLIC_API(JSBool)
1616 JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
1617 0 {
1618 CHECK_REQUEST(cx);
1619 0 return js_NewDoubleValue(cx, d, rval);
1620 }
1621
1622 JS_PUBLIC_API(JSBool)
1623 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
1624 0 {
1625 CHECK_REQUEST(cx);
1626 0 return js_NewNumberValue(cx, d, rval);
1627 }
1628
1629 #undef JS_AddRoot
1630 JS_PUBLIC_API(JSBool)
1631 JS_AddRoot(JSContext *cx, void *rp)
1632 0 {
1633 CHECK_REQUEST(cx);
1634 0 return js_AddRoot(cx, rp, NULL);
1635 }
1636
1637 JS_PUBLIC_API(JSBool)
1638 JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name)
1639 0 {
1640 0 return js_AddRootRT(rt, rp, name);
1641 }
1642
1643 JS_PUBLIC_API(JSBool)
1644 JS_RemoveRoot(JSContext *cx, void *rp)
1645 0 {
1646 CHECK_REQUEST(cx);
1647 0 return js_RemoveRoot(cx->runtime, rp);
1648 }
1649
1650 JS_PUBLIC_API(JSBool)
1651 JS_RemoveRootRT(JSRuntime *rt, void *rp)
1652 0 {
1653 0 return js_RemoveRoot(rt, rp);
1654 }
1655
1656 JS_PUBLIC_API(JSBool)
1657 JS_AddNamedRoot(JSContext *cx, void *rp, const char *name)
1658 0 {
1659 CHECK_REQUEST(cx);
1660 0 return js_AddRoot(cx, rp, name);
1661 }
1662
1663 JS_PUBLIC_API(void)
1664 JS_ClearNewbornRoots(JSContext *cx)
1665 0 {
1666 uintN i;
1667
1668 0 for (i = 0; i < GCX_NTYPES; i++)
1669 0 cx->newborn[i] = NULL;
1670 0 cx->lastAtom = NULL;
1671 0 cx->lastInternalResult = JSVAL_NULL;
1672 }
1673
1674 JS_PUBLIC_API(JSBool)
1675 JS_EnterLocalRootScope(JSContext *cx)
1676 0 {
1677 CHECK_REQUEST(cx);
1678 0 return js_EnterLocalRootScope(cx);
1679 }
1680
1681 JS_PUBLIC_API(void)
1682 JS_LeaveLocalRootScope(JSContext *cx)
1683 0 {
1684 CHECK_REQUEST(cx);
1685 0 js_LeaveLocalRootScope(cx);
1686 }
1687
1688 JS_PUBLIC_API(void)
1689 JS_ForgetLocalRoot(JSContext *cx, void *thing)
1690 0 {
1691 CHECK_REQUEST(cx);
1692 0 js_ForgetLocalRoot(cx, (jsval) thing);
1693 }
1694
1695 #include "jshash.h" /* Added by JSIFY */
1696
1697 #ifdef DEBUG
1698
1699 typedef struct NamedRootDumpArgs {
1700 void (*dump)(const char *name, void *rp, void *data);
1701 void *data;
1702 } NamedRootDumpArgs;
1703
1704 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
1705 js_named_root_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
1706 void *arg)
1707 {
1708 NamedRootDumpArgs *args = (NamedRootDumpArgs *) arg;
1709 JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
1710
1711 if (rhe->name)
1712 args->dump(rhe->name, rhe->root, args->data);
1713 return JS_DHASH_NEXT;
1714 }
1715
1716 JS_PUBLIC_API(void)
1717 JS_DumpNamedRoots(JSRuntime *rt,
1718 void (*dump)(const char *name, void *rp, void *data),
1719 void *data)
1720 {
1721 NamedRootDumpArgs args;
1722
1723 args.dump = dump;
1724 args.data = data;
1725 JS_DHashTableEnumerate(&rt->gcRootsHash, js_named_root_dumper, &args);
1726 }
1727
1728 #endif /* DEBUG */
1729
1730 typedef struct GCRootMapArgs {
1731 JSGCRootMapFun map;
1732 void *data;
1733 } GCRootMapArgs;
1734
1735 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
1736 js_gcroot_mapper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
1737 void *arg)
1738 0 {
1739 0 GCRootMapArgs *args = (GCRootMapArgs *) arg;
1740 0 JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
1741 intN mapflags;
1742 JSDHashOperator op;
1743
1744 0 mapflags = args->map(rhe->root, rhe->name, args->data);
1745
1746 #if JS_MAP_GCROOT_NEXT == JS_DHASH_NEXT && \
1747 JS_MAP_GCROOT_STOP == JS_DHASH_STOP && \
1748 JS_MAP_GCROOT_REMOVE == JS_DHASH_REMOVE
1749 op = (JSDHashOperator)mapflags;
1750 #else
1751 0 op = JS_DHASH_NEXT;
1752 0 if (mapflags & JS_MAP_GCROOT_STOP)
1753 0 op |= JS_DHASH_STOP;
1754 0 if (mapflags & JS_MAP_GCROOT_REMOVE)
1755 0 op |= JS_DHASH_REMOVE;
1756 #endif
1757
1758 0 return op;
1759 }
1760
1761 JS_PUBLIC_API(uint32)
1762 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
1763 0 {
1764 GCRootMapArgs args;
1765 uint32 rv;
1766
1767 0 args.map = map;
1768 0 args.data = data;
1769 JS_LOCK_GC(rt);
1770 0 rv = JS_DHashTableEnumerate(&rt->gcRootsHash, js_gcroot_mapper, &args);
1771 JS_UNLOCK_GC(rt);
1772 0 return rv;
1773 }
1774
1775 JS_PUBLIC_API(JSBool)
1776 JS_LockGCThing(JSContext *cx, void *thing)
1777 0 {
1778 JSBool ok;
1779
1780 CHECK_REQUEST(cx);
1781 0 ok = js_LockGCThing(cx, thing);
1782 0 if (!ok)
1783 0 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_LOCK);
1784 0 return ok;
1785 }
1786
1787 JS_PUBLIC_API(JSBool)
1788 JS_LockGCThingRT(JSRuntime *rt, void *thing)
1789 0 {
1790 0 return js_LockGCThingRT(rt, thing);
1791 }
1792
1793 JS_PUBLIC_API(JSBool)
1794 JS_UnlockGCThing(JSContext *cx, void *thing)
1795 0 {
1796 JSBool ok;
1797
1798 CHECK_REQUEST(cx);
1799 0 ok = js_UnlockGCThingRT(cx->runtime, thing);
1800 0 if (!ok)
1801 0 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_UNLOCK);
1802 0 return ok;
1803 }
1804
1805 JS_PUBLIC_API(JSBool)
1806 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
1807 0 {
1808 0 return js_UnlockGCThingRT(rt, thing);
1809 }
1810
1811 JS_PUBLIC_API(void)
1812 JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg)
1813 7293 {
1814 JS_ASSERT(cx->runtime->gcLevel > 0);
1815 #ifdef JS_THREADSAFE
1816 JS_ASSERT(cx->runtime->gcThread == js_CurrentThreadId());
1817 #endif
1818
1819 7293 GC_MARK(cx, thing, name, arg);
1820 }
1821
1822 JS_PUBLIC_API(void)
1823 JS_GC(JSContext *cx)
1824 0 {
1825 /* Don't nuke active arenas if executing or compiling. */
1826 0 if (cx->stackPool.current == &cx->stackPool.first)
1827 0 JS_FinishArenaPool(&cx->stackPool);
1828 0 if (cx->tempPool.current == &cx->tempPool.first)
1829 0 JS_FinishArenaPool(&cx->tempPool);
1830 0 js_ForceGC(cx, 0);
1831 }
1832
1833 JS_PUBLIC_API(void)
1834 JS_MaybeGC(JSContext *cx)
1835 0 {
1836 #ifdef WAY_TOO_MUCH_GC
1837 JS_GC(cx);
1838 #else
1839 JSRuntime *rt;
1840 uint32 bytes, lastBytes;
1841
1842 0 rt = cx->runtime;
1843 0 bytes = rt->gcBytes;
1844 0 lastBytes = rt->gcLastBytes;
1845 0 if ((bytes > 8192 && bytes > lastBytes + lastBytes / 2) ||
1846 rt->gcMallocBytes > rt->gcMaxMallocBytes) {
1847 /*
1848 * Run the GC if we have half again as many bytes of GC-things as
1849 * the last time we GC'd, or if we have malloc'd more bytes through
1850 * JS_malloc than we were told to allocate by JS_NewRuntime.
1851 */
1852 0 JS_GC(cx);
1853 }
1854 #endif
1855 }
1856
1857 JS_PUBLIC_API(JSGCCallback)
1858 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
1859 0 {
1860 0 return JS_SetGCCallbackRT(cx->runtime, cb);
1861 }
1862
1863 JS_PUBLIC_API(JSGCCallback)
1864 JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
1865 0 {
1866 JSGCCallback oldcb;
1867
1868 0 oldcb = rt->gcCallback;
1869 0 rt->gcCallback = cb;
1870 0 return oldcb;
1871 }
1872
1873 JS_PUBLIC_API(JSBool)
1874 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
1875 0 {
1876 JS_ASSERT(thing);
1877 0 return js_IsAboutToBeFinalized(cx, thing);
1878 }
1879
1880 JS_PUBLIC_API(void)
1881 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
1882 0 {
1883 0 switch (key) {
1884 case JSGC_MAX_BYTES:
1885 0 rt->gcMaxBytes = value;
1886 0 break;
1887 case JSGC_MAX_MALLOC_BYTES:
1888 0 rt->gcMaxMallocBytes = value;
1889 break;
1890 }
1891 }
1892
1893 JS_PUBLIC_API(intN)
1894 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
1895 0 {
1896 0 return js_ChangeExternalStringFinalizer(NULL, finalizer);
1897 }
1898
1899 JS_PUBLIC_API(intN)
1900 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
1901 0 {
1902 0 return js_ChangeExternalStringFinalizer(finalizer, NULL);
1903 }
1904
1905 JS_PUBLIC_API(JSString *)
1906 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
1907 0 {
1908 JSString *str;
1909
1910 CHECK_REQUEST(cx);
1911 JS_ASSERT(GCX_EXTERNAL_STRING <= type && type < (intN) GCX_NTYPES);
1912
1913 0 str = (JSString *) js_NewGCThing(cx, (uintN) type, sizeof(JSString));
1914 0 if (!str)
1915 0 return NULL;
1916 0 str->length = length;
1917 0 str->chars = chars;
1918 0 return str;
1919 }
1920
1921 JS_PUBLIC_API(intN)
1922 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
1923 0 {
1924 0 uint8 type = (uint8) (*js_GetGCThingFlags(str) & GCF_TYPEMASK);
1925
1926 0 if (type >= GCX_EXTERNAL_STRING)
1927 0 return (intN)type;
1928 JS_ASSERT(type == GCX_STRING || type == GCX_MUTABLE_STRING);
1929 0 return -1;
1930 }
1931
1932 JS_PUBLIC_API(void)
1933 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
1934 0 {
1935 #if JS_STACK_GROWTH_DIRECTION > 0
1936 if (limitAddr == 0)
1937 limitAddr = (jsuword)-1;
1938 #endif
1939 0 cx->stackLimit = limitAddr;
1940 }
1941
1942 /************************************************************************/
1943
1944 JS_PUBLIC_API(void)
1945 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
1946 46060 {
1947 46060 JS_free(cx, ida);
1948 }
1949
1950 JS_PUBLIC_API(JSBool)
1951 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
1952 0 {
1953 JSAtom *atom;
1954
1955 CHECK_REQUEST(cx);
1956 0 if (JSVAL_IS_INT(v)) {
1957 0 *idp = v;
1958 } else {
1959 0 atom = js_ValueToStringAtom(cx, v);
1960 0 if (!atom)
1961 0 return JS_FALSE;
1962 0 *idp = ATOM_TO_JSID(atom);
1963 }
1964 0 return JS_TRUE;
1965 }
1966
1967 JS_PUBLIC_API(JSBool)
1968 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
1969 0 {
1970 CHECK_REQUEST(cx);
1971 0 *vp = ID_TO_VALUE(id);
1972 0 return JS_TRUE;
1973 }
1974
1975 JS_PUBLIC_API(JSBool)
1976 JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
1977 264229 {
1978 264229 return JS_TRUE;
1979 }
1980
1981 JS_PUBLIC_API(JSBool)
1982 JS_EnumerateStub(JSContext *cx, JSObject *obj)
1983 46060 {
1984 46060 return JS_TRUE;
1985 }
1986
1987 JS_PUBLIC_API(JSBool)
1988 JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id)
1989 0 {
1990 0 return JS_TRUE;
1991 }
1992
1993 JS_PUBLIC_API(JSBool)
1994 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
1995 0 {
1996 #if JS_BUG_EAGER_TOSTRING
1997 if (type == JSTYPE_STRING)
1998 return JS_TRUE;
1999 #endif
2000 0 js_TryValueOf(cx, obj, type, vp);
2001 0 return JS_TRUE;
2002 }
2003
2004 JS_PUBLIC_API(void)
2005 JS_FinalizeStub(JSContext *cx, JSObject *obj)
2006 191152 {
2007 }
2008
2009 JS_PUBLIC_API(JSObject *)
2010 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
2011 JSClass *clasp, JSNative constructor, uintN nargs,
2012 JSPropertySpec *ps, JSFunctionSpec *fs,
2013 JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
2014 476 {
2015 JSAtom *atom;
2016 JSObject *proto, *ctor;
2017 JSTempValueRooter tvr;
2018 jsval cval, rval;
2019 JSBool named;
2020 JSFunction *fun;
2021
2022 CHECK_REQUEST(cx);
2023 476 atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
2024 476 if (!atom)
2025 0 return NULL;
2026
2027 /* Create a prototype object for this class. */
2028 476 proto = js_NewObject(cx, clasp, parent_proto, obj);
2029 476 if (!proto)
2030 0 return NULL;
2031
2032 /* After this point, control must exit via label bad or out. */
2033 476 JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(proto), &tvr);
2034
2035 476 if (!constructor) {
2036 /* Lacking a constructor, name the prototype (e.g., Math). */
2037 238 named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
2038 OBJECT_TO_JSVAL(proto),
2039 NULL, NULL, 0, NULL);
2040 238 if (!named)
2041 238 goto bad;
2042 238 ctor = proto;
2043 } else {
2044 /* Define the constructor function in obj's scope. */
2045 238 fun = js_DefineFunction(cx, obj, atom, constructor, nargs, 0);
2046 238 named = (fun != NULL);
2047 238 if (!fun)
2048 238 goto bad;
2049
2050 /*
2051 * Remember the class this function is a constructor for so that
2052 * we know to create an object of this class when we call the
2053 * constructor.
2054 */
2055 238 fun->clasp = clasp;
2056
2057 /*
2058 * Optionally construct the prototype object, before the class has
2059 * been fully initialized. Allow the ctor to replace proto with a
2060 * different object, as is done for operator new -- and as at least
2061 * XML support requires.
2062 */
2063 238 ctor = fun->object;
2064 238 if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) {
2065 51 cval = OBJECT_TO_JSVAL(ctor);
2066 51 if (!js_InternalConstruct(cx, proto, cval, 0, NULL, &rval))
2067 51 goto bad;
2068 51 if (!JSVAL_IS_PRIMITIVE(rval) && JSVAL_TO_OBJECT(rval) != proto)
2069 0 proto = JSVAL_TO_OBJECT(rval);
2070 }
2071
2072 /* Connect constructor and prototype by named properties. */
2073 238 if (!js_SetClassPrototype(cx, ctor, proto,
2074 JSPROP_READONLY | JSPROP_PERMANENT)) {
2075 238 goto bad;
2076 }
2077
2078 /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
2079 238 if (OBJ_GET_CLASS(cx, ctor) == clasp) {
2080 /* XXXMLM - this fails in framesets that are writing over
2081 * themselves!
2082 * JS_ASSERT(!OBJ_GET_PROTO(cx, ctor));
2083 */
2084 17 OBJ_SET_PROTO(cx, ctor, proto);
2085 }
2086 }
2087
2088 /* Add properties and methods to the prototype and the constructor. */
2089 476 if ((ps && !JS_DefineProperties(cx, proto, ps)) ||
2090 (fs && !JS_DefineFunctions(cx, proto, fs)) ||
2091 (static_ps && !JS_DefineProperties(cx, ctor, static_ps)) ||
2092 (static_fs && !JS_DefineFunctions(cx, ctor, static_fs))) {
2093 goto bad;
2094 }
2095
2096 476 out:
2097 476 JS_POP_TEMP_ROOT(cx, &tvr);
2098 476 return proto;
2099
2100 0 bad:
2101 0 if (named)
2102 0 (void) OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &rval);
2103 0 proto = NULL;
2104 0 goto out;
2105 }
2106
2107 #ifdef JS_THREADSAFE
2108 JS_PUBLIC_API(JSClass *)
2109 JS_GetClass(JSContext *cx, JSObject *obj)
2110 {
2111 return (JSClass *)
2112 JSVAL_TO_PRIVATE(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_CLASS));
2113 }
2114 #else
2115 JS_PUBLIC_API(JSClass *)
2116 JS_GetClass(JSObject *obj)
2117 0 {
2118 0 return LOCKED_OBJ_GET_CLASS(obj);
2119 }
2120 #endif
2121
2122 JS_PUBLIC_API(JSBool)
2123 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2124 215210 {
2125 JSFunction *fun;
2126
2127 CHECK_REQUEST(cx);
2128 215210 if (OBJ_GET_CLASS(cx, obj) == clasp)
2129 215210 return JS_TRUE;
2130 0 if (argv) {
2131 0 fun = js_ValueToFunction(cx, &argv[-2], 0);
2132 0 if (fun) {
2133 0 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2134 JSMSG_INCOMPATIBLE_PROTO,
2135 clasp->name, JS_GetFunctionName(fun),
2136 OBJ_GET_CLASS(cx, obj)->name);
2137 }
2138 }
2139 0 return JS_FALSE;
2140 }
2141
2142 JS_PUBLIC_API(JSBool)
2143 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
2144 0 {
2145 0 return js_HasInstance(cx, obj, v, bp);
2146 }
2147
2148 JS_PUBLIC_API(void *)
2149 JS_GetPrivate(JSContext *cx, JSObject *obj)
2150 1824058 {
2151 jsval v;
2152
2153 JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2154 1824058 v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
2155 1824058 if (!JSVAL_IS_INT(v))
2156 15671 return NULL;
2157 1808387 return JSVAL_TO_PRIVATE(v);
2158 }
2159
2160 JS_PUBLIC_API(JSBool)
2161 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2162 122837 {
2163 JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2164 122837 OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(data));
2165 122837 return JS_TRUE;
2166 }
2167
2168 JS_PUBLIC_API(void *)
2169 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp,
2170 jsval *argv)
2171 153408 {
2172 153408 if (!JS_InstanceOf(cx, obj, clasp, argv))
2173 0 return NULL;
2174 153408 return JS_GetPrivate(cx, obj);
2175 }
2176
2177 JS_PUBLIC_API(JSObject *)
2178 JS_GetPrototype(JSContext *cx, JSObject *obj)
2179 0 {
2180 JSObject *proto;
2181
2182 CHECK_REQUEST(cx);
2183 0 proto = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PROTO));
2184
2185 /* Beware ref to dead object (we may be called from obj's finalizer). */
2186 0 return proto && proto->map ? proto : NULL;
2187 }
2188
2189 JS_PUBLIC_API(JSBool)
2190 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
2191 0 {
2192 CHECK_REQUEST(cx);
2193 0 if (obj->map->ops->setProto)
2194 0 return obj->map->ops->setProto(cx, obj, JSSLOT_PROTO, proto);
2195 0 OBJ_SET_SLOT(cx, obj, JSSLOT_PROTO, OBJECT_TO_JSVAL(proto));
2196 0 return JS_TRUE;
2197 }
2198
2199 JS_PUBLIC_API(JSObject *)
2200 JS_GetParent(JSContext *cx, JSObject *obj)
2201 0 {
2202 JSObject *parent;
2203
2204 0 parent = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PARENT));
2205
2206 /* Beware ref to dead object (we may be called from obj's finalizer). */
2207 0 return parent && parent->map ? parent : NULL;
2208 }
2209
2210 JS_PUBLIC_API(JSBool)
2211 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
2212 0 {
2213 CHECK_REQUEST(cx);
2214 0 if (obj->map->ops->setParent)
2215 0 return obj->map->ops->setParent(cx, obj, JSSLOT_PARENT, parent);
2216 0 OBJ_SET_SLOT(cx, obj, JSSLOT_PARENT, OBJECT_TO_JSVAL(parent));
2217 0 return JS_TRUE;
2218 }
2219
2220 JS_PUBLIC_API(JSObject *)
2221 JS_GetConstructor(JSContext *cx, JSObject *proto)
2222 68 {
2223 jsval cval;
2224
2225 CHECK_REQUEST(cx);
2226 68 if (!OBJ_GET_PROPERTY(cx, proto,
2227 ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
2228 &cval)) {
2229 0 return NULL;
2230 }
2231 68 if (!JSVAL_IS_FUNCTION(cx, cval)) {
2232 0 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
2233 OBJ_GET_CLASS(cx, proto)->name);
2234 0 return NULL;
2235 }
2236 68 return JSVAL_TO_OBJECT(cval);
2237 }
2238
2239 JS_PUBLIC_API(JSBool)
2240 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
2241 0 {
2242 JS_ASSERT(((jsid)obj & JSID_TAGMASK) == 0);
2243 0 *idp = OBJECT_TO_JSID(obj);
2244 0 return JS_TRUE;
2245 }
2246
2247 JS_PUBLIC_API(JSObject *)
2248 JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
2249 98326 {
2250 CHECK_REQUEST(cx);
2251 98326 if (!clasp)
2252 0 clasp = &js_ObjectClass; /* default class is Object */
2253 98326 return js_NewObject(cx, clasp, proto, parent);
2254 }
2255
2256 JS_PUBLIC_API(JSBool)
2257 JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
2258 0 {
2259 JSScope *scope;
2260 JSIdArray *ida;
2261 uint32 nslots;
2262 jsval v, *vp, *end;
2263
2264 0 if (!OBJ_IS_NATIVE(obj)) {
2265 0 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2266 JSMSG_CANT_SEAL_OBJECT,
2267 OBJ_GET_CLASS(cx, obj)->name);
2268 0 return JS_FALSE;
2269 }
2270
2271 0 scope = OBJ_SCOPE(obj);
2272
2273 #if defined JS_THREADSAFE && defined DEBUG
2274 /* Insist on scope being used exclusively by cx's thread. */
2275 if (scope->ownercx != cx) {
2276 JS_LOCK_OBJ(cx, obj);
2277 JS_ASSERT(OBJ_SCOPE(obj) == scope);
2278 JS_ASSERT(scope->ownercx == cx);
2279 JS_UNLOCK_SCOPE(cx, scope);
2280 }
2281 #endif
2282
2283 /* Nothing to do if obj's scope is already sealed. */
2284 0 if (SCOPE_IS_SEALED(scope))
2285 0 return JS_TRUE;
2286
2287 /* XXX Enumerate lazy properties now, as they can't be added later. */
2288 0 ida = JS_Enumerate(cx, obj);
2289 0 if (!ida)
2290 0 return JS_FALSE;
2291 0 JS_DestroyIdArray(cx, ida);
2292
2293 /* Ensure that obj has its own, mutable scope, and seal that scope. */
2294 JS_LOCK_OBJ(cx, obj);
2295 0 scope = js_GetMutableScope(cx, obj);
2296 0 if (scope)
2297 0 SCOPE_SET_SEALED(scope);
2298 JS_UNLOCK_SCOPE(cx, scope);
2299 0 if (!scope)
2300 0 return JS_FALSE;
2301
2302 /* If we are not sealing an entire object graph, we're done. */
2303 0 if (!deep)
2304 0 return JS_TRUE;
2305
2306 /* Walk obj->slots and if any value is a non-null object, seal it. */
2307 0 nslots = JS_MIN(scope->map.freeslot, scope->map.nslots);
2308 0 for (vp = obj->slots, end = vp + nslots; vp < end; vp++) {
2309 0 v = *vp;
2310 0 if (JSVAL_IS_PRIMITIVE(v))
2311 continue;
2312 0 if (!JS_SealObject(cx, JSVAL_TO_OBJECT(v), deep))
2313 0 return JS_FALSE;
2314 }
2315 0 return JS_TRUE;
2316 }
2317
2318 JS_PUBLIC_API(JSObject *)
2319 JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
2320 JSObject *parent)
2321 0 {
2322 CHECK_REQUEST(cx);
2323 0 if (!clasp)
2324 0 clasp = &js_ObjectClass; /* default class is Object */
2325 0 return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
2326 }
2327
2328 JS_PUBLIC_API(JSObject *)
2329 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto,
2330 JSObject *parent, uintN argc, jsval *argv)
2331 0 {
2332 CHECK_REQUEST(cx);
2333 0 if (!clasp)
2334 0 clasp = &js_ObjectClass; /* default class is Object */
2335 0 return js_ConstructObject(cx, clasp, proto, parent, argc, argv);
2336 }
2337
2338 static JSBool
2339 DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
2340 JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
2341 uintN flags, intN tinyid)
2342 1007255 {
2343 jsid id;
2344 JSAtom *atom;
2345
2346 1007255 if (attrs & JSPROP_INDEX) {
2347 0 id = INT_TO_JSID(JS_PTR_TO_INT32(name));
2348 0 atom = NULL;
2349 0 attrs &= ~JSPROP_INDEX;
2350 } else {
2351 1007255 atom = js_Atomize(cx, name, strlen(name), 0);
2352 1007255 if (!atom)
2353 0 return JS_FALSE;
2354 1007255 id = ATOM_TO_JSID(atom);
2355 }
2356 1007255 if (flags != 0 && OBJ_IS_NATIVE(obj)) {
2357 995149 return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
2358 attrs, flags, tinyid, NULL);
2359 }
2360 12106 return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs,
2361 NULL);
2362 }
2363
2364 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
2365
2366 static JSBool
2367 DefineUCProperty(JSContext *cx, JSObject *obj,
2368 const jschar *name, size_t namelen, jsval value,
2369 JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
2370 uintN flags, intN tinyid)
2371 0 {
2372 JSAtom *atom;
2373
2374 0 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2375 0 if (!atom)
2376 0 return JS_FALSE;
2377 0 if (flags != 0 && OBJ_IS_NATIVE(obj)) {
2378 0 return js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
2379 getter, setter, attrs, flags, tinyid,
2380 NULL);
2381 }
2382 0 return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), value,
2383 getter, setter, attrs, NULL);
2384 }
2385
2386 JS_PUBLIC_API(JSObject *)
2387 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
2388 JSObject *proto, uintN attrs)
2389 17 {
2390 JSObject *nobj;
2391
2392 CHECK_REQUEST(cx);
2393 17 if (!clasp)
2394 0 clasp = &js_ObjectClass; /* default class is Object */
2395 17 nobj = js_NewObject(cx, clasp, proto, obj);
2396 17 if (!nobj)
2397 0 return NULL;
2398 17 if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs,
2399 0, 0)) {
2400 0 cx->newborn[GCX_OBJECT] = NULL;
2401 0 return NULL;
2402 }
2403 17 return nobj;
2404 }
2405
2406 JS_PUBLIC_API(JSBool)
2407 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
2408 34 {
2409 JSBool ok;
2410 jsval value;
2411 uintN flags;
2412
2413 CHECK_REQUEST(cx);
2414 255 for (ok = JS_TRUE; cds->name; cds++) {
2415 221 ok = js_NewNumberValue(cx, cds->dval, &value);
2416 221 if (!ok)
2417 221 break;
2418 221 flags = cds->flags;
2419 221 if (!flags)
2420 221 flags = JSPROP_READONLY | JSPROP_PERMANENT;
2421 221