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 5702 {
122 5702 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 0 break;
198 }
199 0 switch (c) {
200 case 'b':
201 0 if (!js_ValueToBoolean(cx, *sp, va_arg(ap, JSBool *)))
202 0 return JS_FALSE;
203 0 break;
204 case 'c':
205 0 if (!js_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
206 0 return JS_FALSE;
207 0 break;
208 case 'i':
209 0 if (!js_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
210 0 return JS_FALSE;
211 0 break;
212 case 'u':
213 0 if (!js_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
214 0 return JS_FALSE;
215 0 break;
216 case 'j':
217 0 if (!js_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
218 0 return JS_FALSE;
219 0 break;
220 case 'd':
221 0 if (!js_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
222 0 return JS_FALSE;
223 0 break;
224 case 'I':
225 0 if (!js_ValueToNumber(cx, *sp, &d))
226 0 return JS_FALSE;
227 0 *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
228 0 break;
229 case 's':
230 case 'S':
231 case 'W':
232 0 str = js_ValueToString(cx, *sp);
233 0 if (!str)
234 0 return JS_FALSE;
235 0 *sp = STRING_TO_JSVAL(str);
236 0 if (c == 's')
237 0 *va_arg(ap, char **) = JS_GetStringBytes(str);
238 0 else if (c == 'W')
239 0 *va_arg(ap, jschar **) = JS_GetStringChars(str);
240 else
241 0 *va_arg(ap, JSString **) = str;
242 0 break;
243 case 'o':
244 0 if (!js_ValueToObject(cx, *sp, &obj))
245 0 return JS_FALSE;
246 0 *sp = OBJECT_TO_JSVAL(obj);
247 0 *va_arg(ap, JSObject **) = obj;
248 0 break;
249 case 'f':
250 0 obj = js_ValueToFunctionObject(cx, sp, 0);
251 0 if (!obj)
252 0 return JS_FALSE;
253 0 *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj);
254 0 break;
255 case 'v':
256 0 *va_arg(ap, jsval *) = *sp;
257 0 break;
258 case '*':
259 0 break;
260 default:
261 0 format--;
262 0 if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
263 JS_ADDRESSOF_VA_LIST(ap))) {
264 0 return JS_FALSE;
265 }
266 /* NB: the formatter already updated sp, so we continue here. */
267 0 continue;
268 }
269 0 sp++;
270 }
271 0 return JS_TRUE;
272 }
273
274 JS_PUBLIC_API(jsval *)
275 JS_PushArguments(JSContext *cx, void **markp, const char *format, ...)
276 0 {
277 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 0 goto bad;
327 0 break;
328 case 'u':
329 0 if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp))
330 0 goto bad;
331 0 break;
332 case 'd':
333 case 'I':
334 0 if (!js_NewDoubleValue(cx, va_arg(ap, jsdouble), sp))
335 0 goto bad;
336 0 break;
337 case 's':
338 0 str = JS_NewStringCopyZ(cx, va_arg(ap, char *));
339 0 if (!str)
340 0 goto bad;
341 0 *sp = STRING_TO_JSVAL(str);
342 0 break;
343 case 'W':
344 0 str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *));
345 0 if (!str)
346 0 goto bad;
347 0 *sp = STRING_TO_JSVAL(str);
348 0 break;
349 case 'S':
350 0 str = va_arg(ap, JSString *);
351 0 *sp = STRING_TO_JSVAL(str);
352 0 break;
353 case 'o':
354 0 *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *));
355 0 break;
356 case 'f':
357 0 fun = va_arg(ap, JSFunction *);
358 0 *sp = fun ? OBJECT_TO_JSVAL(fun->object) : JSVAL_NULL;
359 0 break;
360 case 'v':
361 0 *sp = va_arg(ap, jsval);
362 0 break;
363 default:
364 0 format--;
365 0 if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp,
366 JS_ADDRESSOF_VA_LIST(ap))) {
367 0 goto bad;
368 }
369 /* NB: the formatter already updated sp, so we continue here. */
370 0 continue;
371 }
372 0 sp++;
373 }
374
375 /*
376 * We may have overallocated stack due to a multi-character format code
377 * handled by a JSArgumentFormatter. Give back that stack space!
378 */
379 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 0 }
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 0 break;
469 case JSTYPE_FUNCTION:
470 0 *vp = v;
471 0 obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK);
472 0 ok = (obj != NULL);
473 0 break;
474 case JSTYPE_STRING:
475 0 str = js_ValueToString(cx, v);
476 0 ok = (str != NULL);
477 0 if (ok)
478 0 *vp = STRING_TO_JSVAL(str);
479 0 break;
480 case JSTYPE_NUMBER:
481 0 ok = js_ValueToNumber(cx, v, &d);
482 0 if (ok) {
483 0 dp = js_NewDouble(cx, d, 0);
484 0 ok = (dp != NULL);
485 0 if (ok)
486 0 *vp = DOUBLE_TO_JSVAL(dp);
487 }
488 0 break;
489 case JSTYPE_BOOLEAN:
490 0 ok = js_ValueToBoolean(cx, v, &b);
491 0 if (ok)
492 0 *vp = BOOLEAN_TO_JSVAL(b);
493 0 break;
494 default: {
495 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 570684 {
530 CHECK_REQUEST(cx);
531 570684 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 34 {
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 34 if (!js_InitStringGlobals())
667 0 return NULL;
668 34 rt = (JSRuntime *) malloc(sizeof(JSRuntime));
669 34 if (!rt)
670 0 return NULL;
671
672 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
673 34 memset(rt, 0, sizeof(JSRuntime));
674 34 JS_INIT_CLIST(&rt->contextList);
675 34 JS_INIT_CLIST(&rt->trapList);
676 34 JS_INIT_CLIST(&rt->watchPointList);
677
678 34 if (!js_InitGC(rt, maxbytes))
679 0 goto bad;
680 #ifdef JS_THREADSAFE
681 rt->gcLock = JS_NEW_LOCK();
682 if (!rt->gcLock)
683 goto bad;
684 rt->gcDone = JS_NEW_CONDVAR(rt->gcLock);
685 if (!rt->gcDone)
686 goto bad;
687 rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
688 if (!rt->requestDone)
689 goto bad;
690 /* this is asymmetric with JS_ShutDown: */
691 if (!js_SetupLocks(8, 16))
692 goto bad;
693 rt->rtLock = JS_NEW_LOCK();
694 if (!rt->rtLock)
695 goto bad;
696 rt->stateChange = JS_NEW_CONDVAR(rt->gcLock);
697 if (!rt->stateChange)
698 goto bad;
699 rt->setSlotLock = JS_NEW_LOCK();
700 if (!rt->setSlotLock)
701 goto bad;
702 rt->setSlotDone = JS_NEW_CONDVAR(rt->setSlotLock);
703 if (!rt->setSlotDone)
704 goto bad;
705 rt->scopeSharingDone = JS_NEW_CONDVAR(rt->gcLock);
706 if (!rt->scopeSharingDone)
707 goto bad;
708 rt->scopeSharingTodo = NO_SCOPE_SHARING_TODO;
709 #endif
710 34 rt->propertyCache.empty = JS_TRUE;
711 34 if (!js_InitPropertyTree(rt))
712 0 goto bad;
713 34 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 34 {
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 34 js_FreeRuntimeScriptState(rt);
737 34 js_FinishAtomState(&rt->atomState);
738 34 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 34 js_FinishPropertyTree(rt);
758 34 free(rt);
759 34 }
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 0 }
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 0 }
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 0 }
916
917 JS_PUBLIC_API(void)
918 JS_Unlock(JSRuntime *rt)
919 0 {
920 JS_UNLOCK_RUNTIME(rt);
921 0 }
922
923 JS_PUBLIC_API(JSContext *)
924 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
925 34 {
926 34 return js_NewContext(rt, stackChunkSize);
927 }
928
929 JS_PUBLIC_API(void)
930 JS_DestroyContext(JSContext *cx)
931 34 {
932 34 js_DestroyContext(cx, JS_FORCE_GC);
933 34 }
934
935 JS_PUBLIC_API(void)
936 JS_DestroyContextNoGC(JSContext *cx)
937 0 {
938 0 js_DestroyContext(cx, JS_NO_GC);
939 0 }
940
941 JS_PUBLIC_API(void)
942 JS_DestroyContextMaybeGC(JSContext *cx)
943 0 {
944 0 js_DestroyContext(cx, JS_MAYBE_GC);
945 0 }
946
947 JS_PUBLIC_API(void *)
948 JS_GetContextPrivate(JSContext *cx)
949 556681 {
950 556681 return cx->data;
951 }
952
953 JS_PUBLIC_API(void)
954 JS_SetContextPrivate(JSContext *cx, void *data)
955 4436 {
956 4436 cx->data = data;
957 4436 }
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 292 {
1074 292 return cx->globalObject;
1075 }
1076
1077 JS_PUBLIC_API(void)
1078 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1079 34 {
1080 34 cx->globalObject = obj;
1081 #if JS_HAS_XML_SUPPORT
1082 34 cx->xmlSettingFlags = 0;
1083 #endif
1084 34 }
1085
1086 static JSObject *
1087 InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1088 34 {
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 34 if (!cx->globalObject)
1098 34 JS_SetGlobalObject(cx, obj);
1099
1100 /* Record Function and Object in cx->resolvingTable, if we are resolving. */
1101 34 table = cx->resolvingTable;
1102 34 resolving = (table && table->entryCount);
1103 34 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 34 fun_proto = js_InitFunctionClass(cx, obj);
1127 34 if (!fun_proto)
1128 0 goto out;
1129
1130 /* Initialize the object class next so Object.prototype works. */
1131 34 obj_proto = js_InitObjectClass(cx, obj);
1132 34 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 34 OBJ_SET_PROTO(cx, fun_proto, obj_proto);
1139 34 if (!OBJ_GET_PROTO(cx, obj))
1140 34 OBJ_SET_PROTO(cx, obj, obj_proto);
1141
1142 34 out:
1143 /* If resolving, remove the other entry (Object or Function) from table. */
1144 34 if (resolving)
1145 0 JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1146 34 return fun_proto;
1147 }
1148
1149 JS_PUBLIC_API(JSBool)
1150 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1151 34 {
1152 CHECK_REQUEST(cx);
1153
1154 #if JS_HAS_UNDEFINED
1155 {
1156 /* Define a top-level property 'undefined' with the undefined value. */
1157 34 JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1158 34 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 34 if (!InitFunctionAndObjectClasses(cx, obj))
1167 0 return JS_FALSE;
1168
1169 /* Initialize the rest of the standard objects and functions. */
1170 34 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 1090146 {
1567 void *p;
1568
1569 JS_ASSERT(nbytes != 0);
1570 1090146 if (nbytes == 0)
1571 0 nbytes = 1;
1572 1090146 cx->runtime->gcMallocBytes += nbytes;
1573 1090146 p = malloc(nbytes);
1574 1090146 if (!p)
1575 0 JS_ReportOutOfMemory(cx);
1576 1090146 return p;
1577 }
1578
1579 JS_PUBLIC_API(void *)
1580 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1581 195174 {
1582 195174 p = realloc(p, nbytes);
1583 195174 if (!p)
1584 0 JS_ReportOutOfMemory(cx);
1585 195174 return p;
1586 }
1587
1588 JS_PUBLIC_API(void)
1589 JS_free(JSContext *cx, void *p)
1590 1173887 {
1591 1173887 if (p)
1592 1173887 free(p);
1593 1173887 }
1594
1595 JS_PUBLIC_API(char *)
1596 JS_strdup(JSContext *cx, const char *s)
1597 102 {
1598 size_t n;
1599 void *p;
1600
1601 102 n = strlen(s) + 1;
1602 102 p = JS_malloc(cx, n);
1603 102 if (!p)
1604 0 return NULL;
1605 102 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 0 }
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 0 }
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 0 }
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 14702 {
1814 JS_ASSERT(cx->runtime->gcLevel > 0);
1815 #ifdef JS_THREADSAFE
1816 JS_ASSERT(cx->runtime->gcThread == js_CurrentThreadId());
1817 #endif
1818
1819 14702 GC_MARK(cx, thing, name, arg);
1820 14702 }
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 0 }
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 0 }
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 0 }
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 0 }
1941
1942 /************************************************************************/
1943
1944 JS_PUBLIC_API(void)
1945 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
1946 60615 {
1947 60615 JS_free(cx, ida);
1948 60615 }
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 477029 {
1978 477029 return JS_TRUE;
1979 }
1980
1981 JS_PUBLIC_API(JSBool)
1982 JS_EnumerateStub(JSContext *cx, JSObject *obj)
1983 60613 {
1984 60613 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 435669 {
2007 435669 }
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 952 {
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 952 atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
2024 952 if (!atom)
2025 0 return NULL;
2026
2027 /* Create a prototype object for this class. */
2028 952 proto = js_NewObject(cx, clasp, parent_proto, obj);
2029 952 if (!proto)
2030 0 return NULL;
2031
2032 /* After this point, control must exit via label bad or out. */
2033 952 JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(proto), &tvr);
2034
2035 952 if (!constructor) {
2036 /* Lacking a constructor, name the prototype (e.g., Math). */
2037 476 named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
2038 OBJECT_TO_JSVAL(proto),
2039 NULL, NULL, 0, NULL);
2040 476 if (!named)
2041 0 goto bad;
2042 476 ctor = proto;
2043 } else {
2044 /* Define the constructor function in obj's scope. */
2045 476 fun = js_DefineFunction(cx, obj, atom, constructor, nargs, 0);
2046 476 named = (fun != NULL);
2047 476 if (!fun)
2048 0 goto bad;
2049
2050 /*
2051 * Remember the class this function is a constructor for so that
2052 * we know to create an object of this class when we call the
2053 * constructor.
2054 */
2055 476 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 476 ctor = fun->object;
2064 476 if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) {
2065 102 cval = OBJECT_TO_JSVAL(ctor);
2066 102 if (!js_InternalConstruct(cx, proto, cval, 0, NULL, &rval))
2067 0 goto bad;
2068 102 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 476 if (!js_SetClassPrototype(cx, ctor, proto,
2074 JSPROP_READONLY | JSPROP_PERMANENT)) {
2075 0 goto bad;
2076 }
2077
2078 /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
2079 476 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 34 OBJ_SET_PROTO(cx, ctor, proto);
2085 }
2086 }
2087
2088 /* Add properties and methods to the prototype and the constructor. */
2089 952 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 952 out:
2097 952 JS_POP_TEMP_ROOT(cx, &tvr);
2098 952 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 451945 {
2125 JSFunction *fun;
2126
2127 CHECK_REQUEST(cx);
2128 451945 if (OBJ_GET_CLASS(cx, obj) == clasp)
2129 451945 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 3506743 {
2151 jsval v;
2152
2153 JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2154 3506743 v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
2155 3506743 if (!JSVAL_IS_INT(v))
2156 35219 return NULL;
2157 3471524 return JSVAL_TO_PRIVATE(v);
2158 }
2159
2160 JS_PUBLIC_API(JSBool)
2161 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2162 319373 {
2163 JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2164 319373 OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(data));
2165 319373 return JS_TRUE;
2166 }
2167
2168 JS_PUBLIC_API(void *)
2169 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp,
2170 jsval *argv)
2171 324713 {
2172 324713 if (!JS_InstanceOf(cx, obj, clasp, argv))
2173 0 return NULL;
2174 324713 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 136 {
2223 jsval cval;
2224
2225 CHECK_REQUEST(cx);
2226 136 if (!OBJ_GET_PROPERTY(cx, proto,
2227 ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
2228 &cval)) {
2229 0 return NULL;
2230 }
2231 136 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 136 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 266545 {
2250 CHECK_REQUEST(cx);
2251 266545 if (!clasp)
2252 0 clasp = &js_ObjectClass; /* default class is Object */
2253 266545 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 1858539 {
2343 jsid id;
2344 JSAtom *atom;
2345
2346 1858539 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 1858539 atom = js_Atomize(cx, name, strlen(name), 0);
2352 1858539 if (!atom)
2353 0 return JS_FALSE;
2354 1858539 id = ATOM_TO_JSID(atom);
2355 }
2356 1858539 if (flags != 0 && OBJ_IS_NATIVE(obj)) {
2357 1793222 return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
2358 attrs, flags, tinyid, NULL);
2359 }
2360 65317 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 34 {
2390 JSObject *nobj;
2391
2392 CHECK_REQUEST(cx);
2393 34 if (!clasp)
2394 0 clasp = &js_ObjectClass; /* default class is Object */
2395 34 nobj = js_NewObject(cx, clasp, proto, obj);
2396 34 if (!nobj)
2397 0 return NULL;
2398 34 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 34 return nobj;
2404 }
2405
2406 JS_PUBLIC_API(JSBool)
2407 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
2408 68 {
2409 JSBool ok;
2410 jsval value;
2411 uintN flags;
2412
2413 CHECK_REQUEST(cx);
2414 510 for (ok = JS_TRUE; cds->name; cds++) {
2415 442 ok = js_NewNumberValue(cx, cds->dval, &value);
2416 442 if (!ok)
2417 0 break;
2418 442 flags = cds->flags;
2419 442 if (!flags)
2420 442 flags = JSPROP_READONLY | JSPROP_PERMANENT;
2421 442 ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, flags, 0, 0);
2422 442 if (!ok)
2423 0 break;
2424 }
2425 68 return ok;
2426 }
2427
2428 JS_PUBLIC_API(JSBool)
2429 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
2430 96872 {
2431 JSBool ok;
2432
2433 CHECK_REQUEST(cx);
2434 1890094 for (ok = JS_TRUE; ps->name; ps++) {
2435 1793222 ok = DefineProperty(cx, obj, ps->name, JSVAL_VOID,
2436 ps->getter, ps->setter, ps->flags,
2437 SPROP_HAS_SHORTID, ps->tinyid);
2438 1793222 if (!ok)
2439 0 break;
2440 }
2441 96872 return ok;
2442 }
2443
2444 JS_PUBLIC_API(JSBool)
2445 JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
2446 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
2447 64841 {
2448 CHECK_REQUEST(cx);
2449 64841 return DefineProperty(cx, obj, name, value, getter, setter, attrs, 0, 0);
2450 }
2451
2452 JS_PUBLIC_API(JSBool)
2453 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
2454 int8 tinyid, jsval value,
2455 JSPropertyOp getter, JSPropertyOp setter,
2456 uintN attrs)
2457 0 {
2458 CHECK_REQUEST(cx);
2459 0 return DefineProperty(cx, obj, name, value, getter, setter, attrs,
2460 SPROP_HAS_SHORTID, tinyid);
2461 }
2462
2463 static JSBool
2464 LookupProperty(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
2465 JSProperty **propp)
2466 238 {
2467 JSAtom *atom;
2468
2469 238 atom = js_Atomize(cx, name, strlen(name), 0);
2470 238 if (!atom)
2471 0 return JS_FALSE;
2472 238 return OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), objp, propp);
2473 }
2474
2475 static JSBool
2476 LookupUCProperty(JSContext *cx, JSObject *obj,
2477 const jschar *name, size_t namelen,
2478 JSObject **objp, JSProperty **propp)
2479 0 {
2480 JSAtom *atom;
2481
2482 0 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2483 0 if (!atom)
2484 0 return JS_FALSE;
2485 0 return OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), objp, propp);
2486 }
2487
2488 JS_PUBLIC_API(JSBool)
2489 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
2490 const char *alias)
2491 238 {
2492 JSObject *obj2;
2493 JSProperty *prop;
2494 JSAtom *atom;
2495 JSBool ok;
2496 JSScopeProperty *sprop;
2497
2498 CHECK_REQUEST(cx);
2499 238 if (!LookupProperty(cx, obj, name, &obj2, &prop))
2500 0 return JS_FALSE;
2501 238 if (!prop) {
2502 0 js_ReportIsNotDefined(cx, name);
2503 0 return JS_FALSE;
2504 }
2505 238 if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
2506 0 OBJ_DROP_PROPERTY(cx, obj2, prop);
2507 0 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
2508 alias, name, OBJ_GET_CLASS(cx, obj2)->name);
2509 0 return JS_FALSE;
2510 }
2511 238 atom = js_Atomize(cx, alias, strlen(alias), 0);
2512 238 if (!atom) {
2513 0 ok = JS_FALSE;
2514 } else {
2515 238 sprop = (JSScopeProperty *)prop;
2516 238 ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
2517 sprop->getter, sprop->setter, sprop->slot,
2518 sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
2519 sprop->shortid)
2520 != NULL);
2521 }
2522 238 OBJ_DROP_PROPERTY(cx, obj, prop);
2523 238 return ok;
2524 }
2525
2526 static jsval
2527 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop)
2528 0 {
2529 JSScopeProperty *sprop;
2530 jsval rval;
2531
2532 0 if (!prop) {
2533 /* XXX bad API: no way to tell "not defined" from "void value" */
2534 0 return JSVAL_VOID;
2535 }
2536 0 if (OBJ_IS_NATIVE(obj2)) {
2537 /* Peek at the native property's slot value, without doing a Get. */
2538 0 sprop = (JSScopeProperty *)prop;
2539 0 rval = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2))
2540 ? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot)
2541 : JSVAL_TRUE;
2542 } else {
2543 /* XXX bad API: no way to return "defined but value unknown" */
2544 0 rval = JSVAL_TRUE;
2545 }
2546 0 OBJ_DROP_PROPERTY(cx, obj2, prop);
2547 0 return rval;
2548 }
2549
2550 static JSBool
2551 GetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
2552 uintN *attrsp, JSBool *foundp,
2553 JSPropertyOp *getterp, JSPropertyOp *setterp)
2554 0 {
2555 JSObject *obj2;
2556 JSProperty *prop;
2557 JSBool ok;
2558
2559 0 if (!atom)
2560 0 return JS_FALSE;
2561 0 if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop))
2562 0 return JS_FALSE;
2563
2564 0 if (!prop || obj != obj2) {
2565 0 *attrsp = 0;
2566 0 *foundp = JS_FALSE;
2567 0 if (getterp)
2568 0 *getterp = NULL;
2569 0 if (setterp)
2570 0 *setterp = NULL;
2571 0 if (prop)
2572 0 OBJ_DROP_PROPERTY(cx, obj2, prop);
2573 0 return JS_TRUE;
2574 }
2575
2576 0 *foundp = JS_TRUE;
2577 0 ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, attrsp);
2578 0 if (ok && OBJ_IS_NATIVE(obj)) {
2579 0 JSScopeProperty *sprop = (JSScopeProperty *) prop;
2580
2581 0 if (getterp)
2582 0 *getterp = sprop->getter;
2583 0 if (setterp)
2584 0 *setterp = sprop->setter;
2585 }
2586 0 OBJ_DROP_PROPERTY(cx, obj, prop);
2587 0 return ok;
2588 }
2589
2590 static JSBool
2591 SetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
2592 uintN attrs, JSBool *foundp)
2593 0 {
2594 JSObject *obj2;
2595 JSProperty *prop;
2596 JSBool ok;
2597
2598 0 if (!atom)
2599 0 return JS_FALSE;
2600 0 if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop))
2601 0 return JS_FALSE;
2602 0 if (!prop || obj != obj2) {
2603 0 *foundp = JS_FALSE;
2604 0 if (prop)
2605 0 OBJ_DROP_PROPERTY(cx, obj2, prop);
2606 0 return JS_TRUE;
2607 }
2608
2609 0 *foundp = JS_TRUE;
2610 0 ok = OBJ_SET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs);
2611 0 OBJ_DROP_PROPERTY(cx, obj, prop);
2612 0 return ok;
2613 }
2614
2615 JS_PUBLIC_API(JSBool)
2616 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
2617 uintN *attrsp, JSBool *foundp)
2618 0 {
2619 CHECK_REQUEST(cx);
2620 0 return GetPropertyAttributes(cx, obj,
2621 js_Atomize(cx, name, strlen(name), 0),
2622 attrsp, foundp, NULL, NULL);
2623 }
2624
2625 JS_PUBLIC_API(JSBool)
2626 JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
2627 const char *name,
2628 uintN *attrsp, JSBool *foundp,
2629 JSPropertyOp *getterp,
2630 JSPropertyOp *setterp)
2631 0 {
2632 CHECK_REQUEST(cx);
2633 0 return GetPropertyAttributes(cx, obj,
2634 js_Atomize(cx, name, strlen(name), 0),
2635 attrsp, foundp, getterp, setterp);
2636 }
2637
2638 JS_PUBLIC_API(JSBool)
2639 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
2640 uintN attrs, JSBool *foundp)
2641 0 {
2642 CHECK_REQUEST(cx);
2643 0 return SetPropertyAttributes(cx, obj,
2644 js_Atomize(cx, name, strlen(name), 0),
2645 attrs, foundp);
2646 }
2647
2648 JS_PUBLIC_API(JSBool)
2649 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
2650 0 {
2651 JSBool ok;
2652 JSObject *obj2;
2653 JSProperty *prop;
2654
2655 CHECK_REQUEST(cx);
2656 0 ok = LookupProperty(cx, obj, name, &obj2, &prop);
2657 0 if (ok) {
2658 0 *foundp = (prop != NULL);
2659 0 if (prop)
2660 0 OBJ_DROP_PROPERTY(cx, obj2, prop);
2661 }
2662 0 return ok;
2663 }
2664
2665 JS_PUBLIC_API(JSBool)
2666 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2667 0 {
2668 JSBool ok;
2669 JSObject *obj2;
2670 JSProperty *prop;
2671
2672 CHECK_REQUEST(cx);
2673 0 ok = LookupProperty(cx, obj, name, &obj2, &prop);
2674 0 if (ok)
2675 0 *vp = LookupResult(cx, obj, obj2, prop);
2676 0 return ok;
2677 }
2678
2679 JS_PUBLIC_API(JSBool)
2680 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name,
2681 uintN flags, jsval *vp)
2682 0 {
2683 JSAtom *atom;
2684 JSBool ok;
2685 JSObject *obj2;
2686 JSProperty *prop;
2687
2688 CHECK_REQUEST(cx);
2689 0 atom = js_Atomize(cx, name, strlen(name), 0);
2690 0 if (!atom)
2691 0 return JS_FALSE;
2692 0 ok = OBJ_IS_NATIVE(obj)
2693 ? js_LookupPropertyWithFlags(cx, obj, ATOM_TO_JSID(atom), flags,
2694 &obj2, &prop)
2695 : OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop);
2696 0 if (ok)
2697 0 *vp = LookupResult(cx, obj, obj2, prop);
2698 0 return ok;
2699 }
2700
2701 JS_PUBLIC_API(JSBool)
2702 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2703 2954 {
2704 JSAtom *atom;
2705
2706 CHECK_REQUEST(cx);
2707 2954 atom = js_Atomize(cx, name, strlen(name), 0);
2708 2954 if (!atom)
2709 0 return JS_FALSE;
2710 2954 return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2711 }
2712
2713 JS_PUBLIC_API(JSBool)
2714 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
2715 jsval *vp)
2716 0 {
2717 JSAtom *atom;
2718 jsid id;
2719
2720 CHECK_REQUEST(cx);
2721 0 atom = js_Atomize(cx, name, strlen(name), 0);
2722 0 if (!atom)
2723 0 return JS_FALSE;
2724 0 id = ATOM_TO_JSID(atom);
2725
2726 #if JS_HAS_XML_SUPPORT
2727 0 if (OBJECT_IS_XML(cx, obj)) {
2728 JSXMLObjectOps *ops;
2729
2730 0 ops = (JSXMLObjectOps *) obj->map->ops;
2731 0 obj = ops->getMethod(cx, obj, id, vp);
2732 0 if (!obj)
2733 0 return JS_FALSE;
2734 } else
2735 #endif
2736 {
2737 0 if (!OBJ_GET_PROPERTY(cx, obj, id, vp))
2738 0 return JS_FALSE;
2739 }
2740
2741 0 *objp = obj;
2742 0 return JS_TRUE;
2743 }
2744
2745 JS_PUBLIC_API(JSBool)
2746 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2747 542 {
2748 JSAtom *atom;
2749
2750 CHECK_REQUEST(cx);
2751 542 atom = js_Atomize(cx, name, strlen(name), 0);
2752 542 if (!atom)
2753 0 return JS_FALSE;
2754 542 return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2755 }
2756
2757 JS_PUBLIC_API(JSBool)
2758 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
2759 0 {
2760 jsval junk;
2761
2762 CHECK_REQUEST(cx);
2763 0 return JS_DeleteProperty2(cx, obj, name, &junk);
2764 }
2765
2766 JS_PUBLIC_API(JSBool)
2767 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name,
2768 jsval *rval)
2769 0 {
2770 JSAtom *atom;
2771
2772 CHECK_REQUEST(cx);
2773 0 atom = js_Atomize(cx, name, strlen(name), 0);
2774 0 if (!atom)
2775 0 return JS_FALSE;
2776 0 return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
2777 }
2778
2779 JS_PUBLIC_API(JSBool)
2780 JS_DefineUCProperty(JSContext *cx, JSObject *obj,
2781 const jschar *name, size_t namelen, jsval value,
2782 JSPropertyOp getter, JSPropertyOp setter,
2783 uintN attrs)
2784 0 {
2785 CHECK_REQUEST(cx);
2786 0 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
2787 attrs, 0, 0);
2788 }
2789
2790 JS_PUBLIC_API(JSBool)
2791 JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj,
2792 const jschar *name, size_t namelen,
2793 uintN *attrsp, JSBool *foundp)
2794 0 {
2795 CHECK_REQUEST(cx);
2796 0 return GetPropertyAttributes(cx, obj,
2797 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2798 attrsp, foundp, NULL, NULL);
2799 }
2800
2801 JS_PUBLIC_API(JSBool)
2802 JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
2803 const jschar *name, size_t namelen,
2804 uintN *attrsp, JSBool *foundp,
2805 JSPropertyOp *getterp,
2806 JSPropertyOp *setterp)
2807 0 {
2808 CHECK_REQUEST(cx);
2809 0 return GetPropertyAttributes(cx, obj,
2810 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2811 attrsp, foundp, getterp, setterp);
2812 }
2813
2814 JS_PUBLIC_API(JSBool)
2815 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj,
2816 const jschar *name, size_t namelen,
2817 uintN attrs, JSBool *foundp)
2818 0 {
2819 CHECK_REQUEST(cx);
2820 0 return SetPropertyAttributes(cx, obj,
2821 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2822 attrs, foundp);
2823 }
2824
2825 JS_PUBLIC_API(JSBool)
2826 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
2827 const jschar *name, size_t namelen,
2828 int8 tinyid, jsval value,
2829 JSPropertyOp getter, JSPropertyOp setter,
2830 uintN attrs)
2831 0 {
2832 CHECK_REQUEST(cx);
2833 0 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
2834 attrs, SPROP_HAS_SHORTID, tinyid);
2835 }
2836
2837 JS_PUBLIC_API(JSBool)
2838 JS_HasUCProperty(JSContext *cx, JSObject *obj,
2839 const jschar *name, size_t namelen,
2840 JSBool *vp)
2841 0 {
2842 JSBool ok;
2843 JSObject *obj2;
2844 JSProperty *prop;
2845
2846 CHECK_REQUEST(cx);
2847 0 ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop);
2848 0 if (ok) {
2849 0 *vp = (prop != NULL);
2850 0 if (prop)
2851 0 OBJ_DROP_PROPERTY(cx, obj2, prop);
2852 }
2853 0 return ok;
2854 }
2855
2856 JS_PUBLIC_API(JSBool)
2857 JS_LookupUCProperty(JSContext *cx, JSObject *obj,
2858 const jschar *name, size_t namelen,
2859 jsval *vp)
2860 0 {
2861 JSBool ok;
2862 JSObject *obj2;
2863 JSProperty *prop;
2864
2865 CHECK_REQUEST(cx);
2866 0 ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop);
2867 0 if (ok)
2868 0 *vp = LookupResult(cx, obj, obj2, prop);
2869 0 return ok;
2870 }
2871
2872 JS_PUBLIC_API(JSBool)
2873 JS_GetUCProperty(JSContext *cx, JSObject *obj,
2874 const jschar *name, size_t namelen,
2875 jsval *vp)
2876 0 {
2877 JSAtom *atom;
2878
2879 CHECK_REQUEST(cx);
2880 0 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2881 0 if (!atom)
2882 0 return JS_FALSE;
2883 0 return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2884 }
2885
2886 JS_PUBLIC_API(JSBool)
2887 JS_SetUCProperty(JSContext *cx, JSObject *obj,
2888 const jschar *name, size_t namelen,
2889 jsval *vp)
2890 0 {
2891 JSAtom *atom;
2892
2893 CHECK_REQUEST(cx);
2894 0 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2895 0 if (!atom)
2896 0 return JS_FALSE;
2897 0 return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2898 }
2899
2900 JS_PUBLIC_API(JSBool)
2901 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
2902 const jschar *name, size_t namelen,
2903 jsval *rval)
2904 0 {
2905 JSAtom *atom;
2906
2907 CHECK_REQUEST(cx);
2908 0 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2909 0 if (!atom)
2910 0 return JS_FALSE;
2911 0 return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
2912 }
2913
2914 JS_PUBLIC_API(JSObject *)
2915 JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
2916 0 {
2917 CHECK_REQUEST(cx);
2918 /* NB: jsuint cast does ToUint32. */
2919 0 return js_NewArrayObject(cx, (jsuint)length, vector);
2920 }
2921
2922 JS_PUBLIC_API(JSBool)
2923 JS_IsArrayObject(JSContext *cx, JSObject *obj)
2924 0 {
2925 0 return OBJ_GET_CLASS(cx, obj) == &js_ArrayClass;
2926 }
2927
2928 JS_PUBLIC_API(JSBool)
2929 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
2930 0 {
2931 CHECK_REQUEST(cx);
2932 0 return js_GetLengthProperty(cx, obj, lengthp);
2933 }
2934
2935 JS_PUBLIC_API(JSBool)
2936 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
2937 0 {
2938 CHECK_REQUEST(cx);
2939 0 return js_SetLengthProperty(cx, obj, length);
2940 }
2941
2942 JS_PUBLIC_API(JSBool)
2943 JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
2944 0 {
2945 CHECK_REQUEST(cx);
2946 0 return js_HasLengthProperty(cx, obj, lengthp);
2947 }
2948
2949 JS_PUBLIC_API(JSBool)
2950 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
2951 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
2952 100942 {
2953 CHECK_REQUEST(cx);
2954 100942 return OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(index), value,
2955 getter, setter, attrs, NULL);
2956 }
2957
2958 JS_PUBLIC_API(JSBool)
2959 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
2960 0 {
2961 JSObject *obj2;
2962 JSProperty *prop;
2963 JSScopeProperty *sprop;
2964 JSBool ok;
2965
2966 CHECK_REQUEST(cx);
2967 0 if (!LookupProperty(cx, obj, name, &obj2, &prop))
2968 0 return JS_FALSE;
2969 0 if (!prop) {
2970 0 js_ReportIsNotDefined(cx, name);
2971 0 return JS_FALSE;
2972 }
2973 0 if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
2974 char numBuf[12];
2975 0 OBJ_DROP_PROPERTY(cx, obj2, prop);
2976 0 JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
2977 0 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
2978 numBuf, name, OBJ_GET_CLASS(cx, obj2)->name);
2979 0 return JS_FALSE;
2980 }
2981 0 sprop = (JSScopeProperty *)prop;
2982 0 ok = (js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
2983 sprop->getter, sprop->setter, sprop->slot,
2984 sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
2985 sprop->shortid)
2986 != NULL);
2987 0 OBJ_DROP_PROPERTY(cx, obj, prop);
2988 0 return ok;
2989 }
2990
2991 JS_PUBLIC_API(JSBool)
2992 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
2993 0 {
2994 JSBool ok;
2995 JSObject *obj2;
2996 JSProperty *prop;
2997
2998 CHECK_REQUEST(cx);
2999 0 ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSID(index), &obj2, &prop);
3000 0 if (ok) {
3001 0 *foundp = (prop != NULL);
3002 0 if (prop)
3003 0 OBJ_DROP_PROPERTY(cx, obj2, prop);
3004 }
3005 0 return ok;
3006 }
3007
3008 JS_PUBLIC_API(JSBool)
3009 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3010 0 {
3011 JSBool ok;
3012 JSObject *obj2;
3013 JSProperty *prop;
3014
3015 CHECK_REQUEST(cx);
3016 0 ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSID(index), &obj2, &prop);
3017 0 if (ok)
3018 0 *vp = LookupResult(cx, obj, obj2, prop);
3019 0 return ok;
3020 }
3021
3022 JS_PUBLIC_API(JSBool)
3023 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3024 0 {
3025 CHECK_REQUEST(cx);
3026 0 return OBJ_GET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
3027 }
3028
3029 JS_PUBLIC_API(JSBool)
3030 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3031 300 {
3032 CHECK_REQUEST(cx);
3033 300 return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
3034 }
3035
3036 JS_PUBLIC_API(JSBool)
3037 JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
3038 0 {
3039 jsval junk;
3040
3041 CHECK_REQUEST(cx);
3042 0 return JS_DeleteElement2(cx, obj, index, &junk);
3043 }
3044
3045 JS_PUBLIC_API(JSBool)
3046 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
3047 0 {
3048 CHECK_REQUEST(cx);
3049 0 return OBJ_DELETE_PROPERTY(cx, obj, INT_TO_JSID(index), rval);
3050 }
3051
3052 JS_PUBLIC_API(void)
3053 JS_ClearScope(JSContext *cx, JSObject *obj)
3054 0 {
3055 CHECK_REQUEST(cx);
3056
3057 0 if (obj->map->ops->clear)
3058 0 obj->map->ops->clear(cx, obj);
3059 0 }
3060
3061 JS_PUBLIC_API(JSIdArray *)
3062 JS_Enumerate(JSContext *cx, JSObject *obj)
3063 0 {
3064 jsint i, n;
3065 jsval iter_state, num_properties;
3066 jsid id;
3067 JSIdArray *ida;
3068 jsval *vector;
3069
3070 CHECK_REQUEST(cx);
3071
3072 0 ida = NULL;
3073 0 iter_state = JSVAL_NULL;
3074
3075 /* Get the number of properties to enumerate. */
3076 0 if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, &num_properties))
3077 0 goto error;
3078 0 if (!JSVAL_IS_INT(num_properties)) {
3079 JS_ASSERT(0);
3080 0 goto error;
3081 }
3082
3083 /* Grow as needed if we don't know the exact amount ahead of time. */
3084 0 n = JSVAL_TO_INT(num_properties);
3085 0 if (n <= 0)
3086 0 n = 8;
3087
3088 /* Create an array of jsids large enough to hold all the properties */
3089 0 ida = js_NewIdArray(cx, n);
3090 0 if (!ida)
3091 0 goto error;
3092
3093 0 i = 0;
3094 0 vector = &ida->vector[0];
3095 for (;;) {
3096 0 if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &id))
3097 0 goto error;
3098
3099 /* No more jsid's to enumerate ? */
3100 0 if (iter_state == JSVAL_NULL)
3101 0 break;
3102
3103 0 if (i == ida->length) {
3104 0 ida = js_SetIdArrayLength(cx, ida, ida->length * 2);
3105 0 if (!ida)
3106 0 goto error;
3107 0 vector = &ida->vector[0];
3108 }
3109 0 vector[i++] = id;
3110 0 }
3111 0 return js_SetIdArrayLength(cx, ida, i);
3112
3113 0 error:
3114 0 if (iter_state != JSVAL_NULL)
3115 0 OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0);
3116 0 if (ida)
3117 0 JS_DestroyIdArray(cx, ida);
3118 0 return NULL;
3119 }
3120
3121 /*
3122 * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
3123 * prop_iterator_class somehow...
3124 * + preserve the OBJ_ENUMERATE API while optimizing the native object case
3125 * + native case here uses a JSScopeProperty *, but that iterates in reverse!
3126 * + so we make non-native match, by reverse-iterating after JS_Enumerating
3127 */
3128 #define JSSLOT_ITER_INDEX (JSSLOT_PRIVATE + 1)
3129
3130 #if JSSLOT_ITER_INDEX >= JS_INITIAL_NSLOTS
3131 # error "JSSLOT_ITER_INDEX botch!"
3132 #endif
3133
3134 static void
3135 prop_iter_finalize(JSContext *cx, JSObject *obj)
3136 0 {
3137 jsval v;
3138 jsint i;
3139 JSIdArray *ida;
3140
3141 0 v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_ITER_INDEX);
3142 0 if (JSVAL_IS_VOID(v))
3143 0 return;
3144
3145 0 i = JSVAL_TO_INT(v);
3146 0 if (i >= 0) {
3147 /* Non-native case: destroy the ida enumerated when obj was created. */
3148 0 ida = (JSIdArray *) JS_GetPrivate(cx, obj);
3149 0 if (ida)
3150 0 JS_DestroyIdArray(cx, ida);
3151 }
3152 }
3153
3154 static uint32
3155 prop_iter_mark(JSContext *cx, JSObject *obj, void *arg)
3156 0 {
3157 jsval v;
3158 jsint i, n;
3159 JSScopeProperty *sprop;
3160 JSIdArray *ida;
3161 jsid id;
3162
3163 0 v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
3164 JS_ASSERT(!JSVAL_IS_VOID(v));
3165
3166 0 i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_INDEX));
3167 0 if (i < 0) {
3168 /* Native case: just mark the next property to visit. */
3169 0 sprop = (JSScopeProperty *) JSVAL_TO_PRIVATE(v);
3170 0 if (sprop)
3171 0 MARK_SCOPE_PROPERTY(sprop);
3172 } else {
3173 /* Non-native case: mark each id in the JSIdArray private. */
3174 0 ida = (JSIdArray *) JSVAL_TO_PRIVATE(v);
3175 0 for (i = 0, n = ida->length; i < n; i++) {
3176 0 id = ida->vector[i];
3177 0 if (JSID_IS_ATOM(id))
3178 0 GC_MARK_ATOM(cx, JSID_TO_ATOM(id), arg);
3179 0 else if (JSID_IS_OBJECT(id))
3180 0 GC_MARK(cx, JSID_TO_OBJECT(id), "id", arg);
3181 }
3182 }
3183 0 return 0;
3184 }
3185
3186 static JSClass prop_iter_class = {
3187 "PropertyIterator",
3188 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1),
3189 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
3190 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, prop_iter_finalize,
3191 NULL, NULL, NULL, NULL,
3192 NULL, NULL, prop_iter_mark, NULL
3193 };
3194
3195 JS_PUBLIC_API(JSObject *)
3196 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
3197 0 {
3198 JSObject *iterobj;
3199 JSScope *scope;
3200 void *pdata;
3201 jsint index;
3202 JSIdArray *ida;
3203
3204 CHECK_REQUEST(cx);
3205 0 iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj);
3206 0 if (!iterobj)
3207 0 return NULL;
3208
3209 0 if (OBJ_IS_NATIVE(obj)) {
3210 /* Native case: start with the last property in obj's own scope. */
3211 0 scope = OBJ_SCOPE(obj);
3212 0 pdata = (scope->object == obj) ? scope->lastProp : NULL;
3213 0 index = -1;
3214 } else {
3215 JSTempValueRooter tvr;
3216
3217 /*
3218 * Non-native case: enumerate a JSIdArray and keep it via private.
3219 *
3220 * Note: we have to make sure that we root obj around the call to
3221 * JS_Enumerate to protect against multiple allocations under it.
3222 */
3223 0 JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(iterobj), &tvr);
3224 0 ida = JS_Enumerate(cx, obj);
3225 0 JS_POP_TEMP_ROOT(cx, &tvr);
3226 0 if (!ida)
3227 0 goto bad;
3228 0 pdata = ida;
3229 0 index = ida->length;
3230 }
3231
3232 /* iterobj can not escape to other threads here. */
3233 0 iterobj->slots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(pdata);
3234 0 iterobj->slots[JSSLOT_ITER_INDEX] = INT_TO_JSVAL(index);
3235 0 return iterobj;
3236
3237 0 bad:
3238 0 cx->newborn[GCX_OBJECT] = NULL;
3239 0 return NULL;
3240 }
3241
3242 JS_PUBLIC_API(JSBool)
3243 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
3244 0 {
3245 jsint i;
3246 JSObject *obj;
3247 JSScope *scope;
3248 JSScopeProperty *sprop;
3249 JSIdArray *ida;
3250
3251 CHECK_REQUEST(cx);
3252 0 i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX));
3253 0 if (i < 0) {
3254 /* Native case: private data is a property tree node pointer. */
3255 0 obj = OBJ_GET_PARENT(cx, iterobj);
3256 JS_ASSERT(OBJ_IS_NATIVE(obj));
3257 0 scope = OBJ_SCOPE(obj);
3258 JS_ASSERT(scope->object == obj);
3259 0 sprop = (JSScopeProperty *) JS_GetPrivate(cx, iterobj);
3260
3261 /*
3262 * If the next property mapped by scope in the property tree ancestor
3263 * line is not enumerable, or it's an alias, or one or more properties
3264 * were deleted from the "middle" of the scope-mapped ancestor line
3265 * and the next property was among those deleted, skip it and keep on
3266 * trying to find an enumerable property that is still in scope.
3267 */
3268 0 while (sprop &&
3269 (!(sprop->attrs & JSPROP_ENUMERATE) ||
3270 (sprop->flags & SPROP_IS_ALIAS) ||
3271 (SCOPE_HAD_MIDDLE_DELETE(scope) &&
3272 !SCOPE_HAS_PROPERTY(scope, sprop)))) {
3273 0 sprop = sprop->parent;
3274 }
3275
3276 0 if (!sprop) {
3277 0 *idp = JSVAL_VOID;
3278 } else {
3279 0 if (!JS_SetPrivate(cx, iterobj, sprop->parent))
3280 0 return JS_FALSE;
3281 0 *idp = sprop->id;
3282 }
3283 } else {
3284 /* Non-native case: use the ida enumerated when iterobj was created. */
3285 0 ida = (JSIdArray *) JS_GetPrivate(cx, iterobj);
3286 JS_ASSERT(i <= ida->length);
3287 0 if (i == 0) {
3288 0 *idp = JSVAL_VOID;
3289 } else {
3290 0 *idp = ida->vector[--i];
3291 0 OBJ_SET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(i));
3292 }
3293 }
3294 0 return JS_TRUE;
3295 }
3296
3297 JS_PUBLIC_API(JSBool)
3298 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
3299 jsval *vp, uintN *attrsp)
3300 0 {
3301 CHECK_REQUEST(cx);
3302 0 return OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, attrsp);
3303 }
3304
3305 JS_PUBLIC_API(JSCheckAccessOp)
3306 JS_SetCheckObjectAccessCallback(JSRuntime *rt, JSCheckAccessOp acb)
3307 0 {
3308 JSCheckAccessOp oldacb;
3309
3310 0 oldacb = rt->checkObjectAccess;
3311 0 rt->checkObjectAccess = acb;
3312 0 return oldacb;
3313 }
3314
3315 static JSBool
3316 ReservedSlotIndexOK(JSContext *cx, JSObject *obj, JSClass *clasp,
3317 uint32 index, uint32 limit)
3318 0 {
3319 /* Check the computed, possibly per-instance, upper bound. */
3320 0 if (clasp->reserveSlots)
3321 0 JS_LOCK_OBJ_VOID(cx, obj, limit += clasp->reserveSlots(cx, obj));
3322 0 if (index >= limit) {
3323 0 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3324 JSMSG_RESERVED_SLOT_RANGE);
3325 0 return JS_FALSE;
3326 }
3327 0 return JS_TRUE;
3328 }
3329
3330 JS_PUBLIC_API(JSBool)
3331 JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
3332 0 {
3333 JSClass *clasp;
3334 uint32 limit, slot;
3335
3336 CHECK_REQUEST(cx);
3337 0 clasp = OBJ_GET_CLASS(cx, obj);
3338 0 limit = JSCLASS_RESERVED_SLOTS(clasp);
3339 0 if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
3340 0 return JS_FALSE;
3341 0 slot = JSSLOT_START(clasp) + index;
3342 0 *vp = OBJ_GET_REQUIRED_SLOT(cx, obj, slot);
3343 0 return JS_TRUE;
3344 }
3345
3346 JS_PUBLIC_API(JSBool)
3347 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
3348 37102 {
3349 JSClass *clasp;
3350 uint32 limit, slot;
3351
3352 CHECK_REQUEST(cx);
3353 37102 clasp = OBJ_GET_CLASS(cx, obj);
3354 37102 limit = JSCLASS_RESERVED_SLOTS(clasp);
3355 37102 if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
3356 0 return JS_FALSE;
3357 37102 slot = JSSLOT_START(clasp) + index;
3358 37102 return OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v);
3359 }
3360
3361 #ifdef JS_THREADSAFE
3362 JS_PUBLIC_API(jsrefcount)
3363 JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
3364 {
3365 return JS_ATOMIC_INCREMENT(&principals->refcount);
3366 }
3367
3368 JS_PUBLIC_API(jsrefcount)
3369 JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
3370 {
3371 jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
3372 if (rc == 0)
3373 principals->destroy(cx, principals);
3374 return rc;
3375 }
3376 #endif
3377
3378 JS_PUBLIC_API(JSPrincipalsTranscoder)
3379 JS_SetPrincipalsTranscoder(JSRuntime *rt, JSPrincipalsTranscoder px)
3380 0 {
3381 JSPrincipalsTranscoder oldpx;
3382
3383 0 oldpx = rt->principalsTranscoder;
3384 0 rt->principalsTranscoder = px;
3385 0 return oldpx;
3386 }
3387
3388 JS_PUBLIC_API(JSObjectPrincipalsFinder)
3389 JS_SetObjectPrincipalsFinder(JSRuntime *rt, JSObjectPrincipalsFinder fop)
3390 0 {
3391 JSObjectPrincipalsFinder oldfop;
3392
3393 0 oldfop = rt->findObjectPrincipals;
3394 0 rt->findObjectPrincipals = fop;
3395 0 return oldfop;
3396 }
3397
3398 JS_PUBLIC_API(JSFunction *)
3399 JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
3400 JSObject *parent, const char *name)
3401 0 {
3402 JSAtom *atom;
3403
3404 CHECK_REQUEST(cx);
3405
3406 0 if (!name) {
3407 0 atom = NULL;
3408 } else {
3409 0 atom = js_Atomize(cx, name, strlen(name), 0);
3410 0 if (!atom)
3411 0 return NULL;
3412 }
3413 0 return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom);
3414 }
3415
3416 JS_PUBLIC_API(JSObject *)
3417 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
3418 0 {
3419 CHECK_REQUEST(cx);
3420 0 if (OBJ_GET_CLASS(cx, funobj) != &js_FunctionClass) {
3421 /* Indicate we cannot clone this object. */
3422 0 return funobj;
3423 }
3424 0 return js_CloneFunctionObject(cx, funobj, parent);
3425 }
3426
3427 JS_PUBLIC_API(JSObject *)
3428 JS_GetFunctionObject(JSFunction *fun)
3429 0 {
3430 0 return fun->object;
3431 }
3432
3433 JS_PUBLIC_API(const char *)
3434 JS_GetFunctionName(JSFunction *fun)
3435 0 {
3436 0 return fun->atom
3437 ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
3438 : js_anonymous_str;
3439 }
3440
3441 JS_PUBLIC_API(JSString *)
3442 JS_GetFunctionId(JSFunction *fun)
3443 0 {
3444 0 return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
3445 }
3446
3447 JS_PUBLIC_API(uintN)
3448 JS_GetFunctionFlags(JSFunction *fun)
3449 0 {
3450 0 return fun->flags;
3451 }
3452
3453 JS_PUBLIC_API(uint16)
3454 JS_GetFunctionArity(JSFunction *fun)
3455 0 {
3456 0 return fun->nargs;
3457 }
3458
3459 JS_PUBLIC_API(JSBool)
3460 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
3461 0 {
3462 0 return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass;
3463 }
3464
3465 JS_STATIC_DLL_CALLBACK(JSBool)
3466 js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
3467 uintN argc, jsval *argv, jsval *rval)
3468 0 {
3469 jsval fsv;
3470 JSFunctionSpec *fs;
3471 JSObject *tmp;
3472
3473 0 if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &fsv))
3474 0 return JS_FALSE;
3475 0 fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv);
3476
3477 /*
3478 * We know that argv[0] is valid because JS_DefineFunctions, which is our
3479 * only (indirect) referrer, defined us as requiring at least one argument
3480 * (notice how it passes fs->nargs + 1 as the next-to-last argument to
3481 * JS_DefineFunction).
3482 */
3483 0 if (JSVAL_IS_PRIMITIVE(argv[0])) {
3484 /*
3485 * Make sure that this is an object or null, as required by the generic
3486 * functions.
3487 */
3488 0 if (!js_ValueToObject(cx, argv[0], &tmp))
3489 0 return JS_FALSE;
3490 0 argv[0] = OBJECT_TO_JSVAL(tmp);
3491 }
3492
3493 /*
3494 * Copy all actual (argc) and required but missing (fs->nargs + 1 - argc)
3495 * args down over our |this| parameter, argv[-1], which is almost always
3496 * the class constructor object, e.g. Array. Then call the corresponding
3497 * prototype native method with our first argument passed as |this|.
3498 */
3499 0 memmove(argv - 1, argv, JS_MAX(fs->nargs + 1U, argc) * sizeof(jsval));
3500
3501 /*
3502 * Follow Function.prototype.apply and .call by using the global object as
3503 * the 'this' param if no args.
3504 */
3505 JS_ASSERT(cx->fp->argv == argv);
3506 0 if (!js_ComputeThis(cx, JSVAL_TO_OBJECT(argv[-1]), cx->fp))
3507 0 return JS_FALSE;
3508
3509 /*
3510 * Protect against argc - 1 underflowing below. By calling js_ComputeThis,
3511 * we made it as if the static was called with one parameter.
3512 */
3513 0 if (argc == 0)
3514 0 argc = 1;
3515
3516 0 return fs->call(cx, JSVAL_TO_OBJECT(argv[-1]), argc - 1, argv, rval);
3517 }
3518
3519 JS_PUBLIC_API(JSBool)
3520 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
3521 680 {
3522 uintN flags;
3523 JSObject *ctor;
3524 JSFunction *fun;
3525
3526 CHECK_REQUEST(cx);
3527 680 ctor = NULL;
3528 7072 for (; fs->name; fs++) {
3529 6392 flags = fs->flags;
3530
3531 /*
3532 * Define a generic arity N+1 static method for the arity N prototype
3533 * method if flags contains JSFUN_GENERIC_NATIVE.
3534 */
3535 6392 if (flags & JSFUN_GENERIC_NATIVE) {
3536 1190 if (!ctor) {
3537 68 ctor = JS_GetConstructor(cx, obj);
3538 68 if (!ctor)
3539 0 return JS_FALSE;
3540 }
3541
3542 1190 flags &= ~JSFUN_GENERIC_NATIVE;
3543 1190 fun = JS_DefineFunction(cx, ctor, fs->name,
3544 js_generic_native_method_dispatcher,
3545 fs->nargs + 1, flags);
3546 1190 if (!fun)
3547 0 return JS_FALSE;
3548 1190 fun->extra = fs->extra;
3549
3550 /*
3551 * As jsapi.h notes, fs must point to storage that lives as long
3552 * as fun->object lives.
3553 */
3554 1190 if (!JS_SetReservedSlot(cx, fun->object, 0, PRIVATE_TO_JSVAL(fs)))
3555 0 return JS_FALSE;
3556 }
3557
3558 6392 fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
3559 6392 if (!fun)
3560 0 return JS_FALSE;
3561 6392 fun->extra = fs->extra;
3562 }
3563 680 return JS_TRUE;
3564 }
3565
3566 JS_PUBLIC_API(JSFunction *)
3567 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
3568 uintN nargs, uintN attrs)
3569 9044 {
3570 JSAtom *atom;
3571
3572 CHECK_REQUEST(cx);
3573 9044 atom = js_Atomize(cx, name, strlen(name), 0);
3574 9044 if (!atom)
3575 0 return NULL;
3576 9044 return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
3577 }
3578
3579 JS_PUBLIC_API(JSFunction *)
3580 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
3581 const jschar *name, size_t namelen, JSNative call,
3582 uintN nargs, uintN attrs)
3583 0 {
3584 JSAtom *atom;
3585
3586 0 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3587 0 if (!atom)
3588 0 return NULL;
3589 0 return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
3590 }
3591
3592 static JSScript *
3593 CompileTokenStream(JSContext *cx, JSObject *obj, JSTokenStream *ts,
3594 void *tempMark, JSBool *eofp)
3595 2201 {
3596 JSBool eof;
3597 JSArenaPool codePool, notePool;
3598 JSCodeGenerator cg;
3599 JSScript *script;
3600
3601 CHECK_REQUEST(cx);
3602 2201 eof = JS_FALSE;
3603 2201 JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode));
3604 2201 JS_InitArenaPool(&notePool, "note", 1024, sizeof(jssrcnote));
3605 2201 if (!js_InitCodeGenerator(cx, &cg, &codePool, &notePool,
3606 ts->filename, ts->lineno,
3607 ts->principals)) {
3608 0 script = NULL;
3609 2201 } else if (!js_CompileTokenStream(cx, obj, ts, &cg)) {
3610 0 script = NULL;
3611 0 eof = (ts->flags & TSF_EOF) != 0;
3612 } else {
3613 2201 script = js_NewScriptFromCG(cx, &cg, NULL);
3614 }
3615 2201 if (eofp)
3616 0 *eofp = eof;
3617 2201 if (!js_CloseTokenStream(cx, ts)) {
3618 0 if (script)
3619 0 js_DestroyScript(cx, script);
3620 0 script = NULL;
3621 }
3622 2201 cg.tempMark = tempMark;
3623 2201 js_FinishCodeGenerator(cx, &cg);
3624 2201 JS_FinishArenaPool(&codePool);
3625 2201 JS_FinishArenaPool(&notePool);
3626 2201 return script;
3627 }
3628
3629 JS_PUBLIC_API(JSScript *)
3630 JS_CompileScript(JSContext *cx, JSObject *obj,
3631 const char *bytes, size_t length,
3632 const char *filename, uintN lineno)
3633 0 {
3634 jschar *chars;
3635 JSScript *script;
3636
3637 CHECK_REQUEST(cx);
3638 0 chars = js_InflateString(cx, bytes, &length);
3639 0 if (!chars)
3640 0 return NULL;
3641 0 script = JS_CompileUCScript(cx, obj, chars, length, filename, lineno);
3642 0 JS_free(cx, chars);
3643 0 return script;
3644 }
3645
3646 JS_PUBLIC_API(JSScript *)
3647 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
3648 JSPrincipals *principals,
3649 const char *bytes, size_t length,
3650 const char *filename, uintN lineno)
3651 0 {
3652 jschar *chars;
3653 JSScript *script;
3654
3655 CHECK_REQUEST(cx);
3656 0 chars = js_InflateString(cx, bytes, &length);
3657 0 if (!chars)
3658 0 return NULL;
3659 0 script = JS_CompileUCScriptForPrincipals(cx, obj, principals,
3660 chars, length, filename, lineno);
3661 0 JS_free(cx, chars);
3662 0 return script;
3663 }
3664
3665 JS_PUBLIC_API(JSScript *)
3666 JS_CompileUCScript(JSContext *cx, JSObject *obj,
3667 const jschar *chars, size_t length,
3668 const char *filename, uintN lineno)
3669 0 {
3670 CHECK_REQUEST(cx);
3671 0 return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length,
3672 filename, lineno);
3673 }
3674
3675 #if JS_HAS_EXCEPTIONS
3676 # define LAST_FRAME_EXCEPTION_CHECK(cx,result) \
3677 JS_BEGIN_MACRO \
3678 if (!(result)) \
3679 js_ReportUncaughtException(cx); \
3680 JS_END_MACRO
3681 #else
3682 # define LAST_FRAME_EXCEPTION_CHECK(cx,result) /* nothing */
3683 #endif
3684
3685 #define LAST_FRAME_CHECKS(cx,result) \
3686 JS_BEGIN_MACRO \
3687 if (!(cx)->fp) { \
3688 (cx)->lastInternalResult = JSVAL_NULL; \
3689 LAST_FRAME_EXCEPTION_CHECK(cx, result); \
3690 } \
3691 JS_END_MACRO
3692
3693 JS_PUBLIC_API(JSScript *)
3694 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
3695 JSPrincipals *principals,
3696 const jschar *chars, size_t length,
3697 const char *filename, uintN lineno)
3698 2201 {
3699 void *mark;
3700 JSTokenStream *ts;
3701 JSScript *script;
3702
3703 CHECK_REQUEST(cx);
3704 2201 mark = JS_ARENA_MARK(&cx->tempPool);
3705 2201 ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
3706 2201 if (!ts)
3707 0 return NULL;
3708 2201 script = CompileTokenStream(cx, obj, ts, mark, NULL);
3709 2201 LAST_FRAME_CHECKS(cx, script);
3710 2201 return script;
3711 }
3712
3713 JS_PUBLIC_API(JSBool)
3714 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
3715 const char *bytes, size_t length)
3716 0 {
3717 jschar *chars;
3718 JSBool result;
3719 JSExceptionState *exnState;
3720 void *tempMark;
3721 JSTokenStream *ts;
3722 JSErrorReporter older;
3723
3724 CHECK_REQUEST(cx);
3725 0 chars = js_InflateString(cx, bytes, &length);
3726 0 if (!chars)
3727 0 return JS_TRUE;
3728
3729 /*
3730 * Return true on any out-of-memory error, so our caller doesn't try to
3731 * collect more buffered source.
3732 */
3733 0 result = JS_TRUE;
3734 0 exnState = JS_SaveExceptionState(cx);
3735 0 tempMark = JS_ARENA_MARK(&cx->tempPool);
3736 0 ts = js_NewTokenStream(cx, chars, length, NULL, 0, NULL);
3737 0 if (ts) {
3738 0 older = JS_SetErrorReporter(cx, NULL);
3739 0 if (!js_ParseTokenStream(cx, obj, ts) &&
3740 (ts->flags & TSF_UNEXPECTED_EOF)) {
3741 /*
3742 * We ran into an error. If it was because we ran out of source,
3743 * we return false, so our caller will know to try to collect more
3744 * buffered source.
3745 */
3746 0 result = JS_FALSE;
3747 }
3748
3749 0 JS_SetErrorReporter(cx, older);
3750 0 js_CloseTokenStream(cx, ts);
3751 0 JS_ARENA_RELEASE(&cx->tempPool, tempMark);
3752 }
3753
3754 0 JS_free(cx, chars);
3755 0 JS_RestoreExceptionState(cx, exnState);
3756 0 return result;
3757 }
3758
3759 JS_PUBLIC_API(JSScript *)
3760 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
3761 0 {
3762 void *mark;
3763 JSTokenStream *ts;
3764 JSScript *script;
3765
3766 CHECK_REQUEST(cx);
3767 0 mark = JS_ARENA_MARK(&cx->tempPool);
3768 0 ts = js_NewFileTokenStream(cx, filename, stdin);
3769 0 if (!ts)
3770 0 return NULL;
3771 0 script = CompileTokenStream(cx, obj, ts, mark, NULL);
3772 0 LAST_FRAME_CHECKS(cx, script);
3773 0 return script;
3774 }
3775
3776 JS_PUBLIC_API(JSScript *)
3777 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename,
3778 FILE *file)
3779 0 {
3780 0 return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
3781 }
3782
3783 JS_PUBLIC_API(JSScript *)
3784 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
3785 const char *filename, FILE *file,
3786 JSPrincipals *principals)
3787 0 {
3788 void *mark;
3789 JSTokenStream *ts;
3790 JSScript *script;
3791
3792 CHECK_REQUEST(cx);
3793 0 mark = JS_ARENA_MARK(&cx->tempPool);
3794 0 ts = js_NewFileTokenStream(cx, NULL, file);
3795 0 if (!ts)
3796 0 return NULL;
3797 0 ts->filename = filename;
3798 /* XXXshaver js_NewFileTokenStream should do this, because it drops */
3799 0 if (principals) {
3800 0 ts->principals = principals;
3801 0 JSPRINCIPALS_HOLD(cx, ts->principals);
3802 }
3803 0 script = CompileTokenStream(cx, obj, ts, mark, NULL);
3804 0 LAST_FRAME_CHECKS(cx, script);
3805 0 return script;
3806 }
3807
3808 JS_PUBLIC_API(JSObject *)
3809 JS_NewScriptObject(JSContext *cx, JSScript *script)
3810 0 {
3811 JSObject *obj;
3812
3813 0 obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
3814 0 if (!obj)
3815 0 return NULL;
3816
3817 0 if (script) {
3818 0 if (!JS_SetPrivate(cx, obj, script))
3819 0 return NULL;
3820 0 script->object = obj;
3821 }
3822 0 return obj;
3823 }
3824
3825 JS_PUBLIC_API(JSObject *)
3826 JS_GetScriptObject(JSScript *script)
3827 0 {
3828 0 return script->object;
3829 }
3830
3831 JS_PUBLIC_API(void)
3832 JS_DestroyScript(JSContext *cx, JSScript *script)
3833 2201 {
3834 CHECK_REQUEST(cx);
3835 2201 js_DestroyScript(cx, script);
3836 2201 }
3837
3838 JS_PUBLIC_API(JSFunction *)
3839 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
3840 uintN nargs, const char **argnames,
3841 const char *bytes, size_t length,
3842 const char *filename, uintN lineno)
3843 0 {
3844 jschar *chars;
3845 JSFunction *fun;
3846
3847 CHECK_REQUEST(cx);
3848 0 chars = js_InflateString(cx, bytes, &length);
3849 0 if (!chars)
3850 0 return NULL;
3851 0 fun = JS_CompileUCFunction(cx, obj, name, nargs, argnames, chars, length,
3852 filename, lineno);
3853 0 JS_free(cx, chars);
3854 0 return fun;
3855 }
3856
3857 JS_PUBLIC_API(JSFunction *)
3858 JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
3859 JSPrincipals *principals, const char *name,
3860 uintN nargs, const char **argnames,
3861 const char *bytes, size_t length,
3862 const char *filename, uintN lineno)
3863 0 {
3864 jschar *chars;
3865 JSFunction *fun;
3866
3867 CHECK_REQUEST(cx);
3868 0 chars = js_InflateString(cx, bytes, &length);
3869 0 if (!chars)
3870 0 return NULL;
3871 0 fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
3872 nargs, argnames, chars, length,
3873 filename, lineno);
3874 0 JS_free(cx, chars);
3875 0 return fun;
3876 }
3877
3878 JS_PUBLIC_API(JSFunction *)
3879 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
3880 uintN nargs, const char **argnames,
3881 const jschar *chars, size_t length,
3882 const char *filename, uintN lineno)
3883 0 {
3884 CHECK_REQUEST(cx);
3885 0 return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name,
3886 nargs, argnames,
3887 chars, length,
3888 filename, lineno);
3889 }
3890
3891 JS_PUBLIC_API(JSFunction *)
3892 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
3893 JSPrincipals *principals, const char *name,
3894 uintN nargs, const char **argnames,
3895 const jschar *chars, size_t length,
3896 const char *filename, uintN lineno)
3897 0 {
3898 void *mark;
3899 JSTokenStream *ts;
3900 JSFunction *fun;
3901 JSAtom *funAtom, *argAtom;
3902 uintN i;
3903
3904 CHECK_REQUEST(cx);
3905 0 mark = JS_ARENA_MARK(&cx->tempPool);
3906 0 ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
3907 0 if (!ts) {
3908 0 fun = NULL;
3909 0 goto out;
3910 }
3911 0 if (!name) {
3912 0 funAtom = NULL;
3913 } else {
3914 0 funAtom = js_Atomize(cx, name, strlen(name), 0);
3915 0 if (!funAtom) {
3916 0 fun = NULL;
3917 0 goto out;
3918 }
3919 }
3920 0 fun = js_NewFunction(cx, NULL, NULL, nargs, 0, obj, funAtom);
3921 0 if (!fun)
3922 0 goto out;
3923 0 if (nargs) {
3924 0 for (i = 0; i < nargs; i++) {
3925 0 argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
3926 0 if (!argAtom)
3927 0 break;
3928 0 if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom),
3929 js_GetArgument, js_SetArgument,
3930 SPROP_INVALID_SLOT,
3931 JSPROP_PERMANENT | JSPROP_SHARED,
3932 SPROP_HAS_SHORTID, i)) {
3933 0 break;
3934 }
3935 }
3936 0 if (i < nargs) {
3937 0 fun = NULL;
3938 0 goto out;
3939 }
3940 }
3941 0 if (!js_CompileFunctionBody(cx, ts, fun)) {
3942 0 fun = NULL;
3943 0 goto out;
3944 }
3945 0 if (obj && funAtom) {
3946 0 if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(funAtom),
3947 OBJECT_TO_JSVAL(fun->object),
3948 NULL, NULL, JSPROP_ENUMERATE, NULL)) {
3949 0 return NULL;
3950 }
3951 }
3952 0 out:
3953 0 if (ts)
3954 0 js_CloseTokenStream(cx, ts);
3955 0 JS_ARENA_RELEASE(&cx->tempPool, mark);
3956 0 LAST_FRAME_CHECKS(cx, fun);
3957 0 return fun;
3958 }
3959
3960 JS_PUBLIC_API(JSString *)
3961 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
3962 uintN indent)
3963 0 {
3964 JSPrinter *jp;
3965 JSString *str;
3966
3967 CHECK_REQUEST(cx);
3968 0 jp = js_NewPrinter(cx, name,
3969 indent & ~JS_DONT_PRETTY_PRINT,
3970 !(indent & JS_DONT_PRETTY_PRINT));
3971 0 if (!jp)
3972 0 return NULL;
3973 0 if (js_DecompileScript(jp, script))
3974 0 str = js_GetPrinterOutput(jp);
3975 else
3976 0 str = NULL;
3977 0 js_DestroyPrinter(jp);
3978 0 return str;
3979 }
3980
3981 JS_PUBLIC_API(JSString *)
3982 JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
3983 0 {
3984 JSPrinter *jp;
3985 JSString *str;
3986
3987 CHECK_REQUEST(cx);
3988 0 jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
3989 indent & ~JS_DONT_PRETTY_PRINT,
3990 !(indent & JS_DONT_PRETTY_PRINT));
3991 0 if (!jp)
3992 0 return NULL;
3993 0 if (js_DecompileFunction(jp, fun))
3994 0 str = js_GetPrinterOutput(jp);
3995 else
3996 0 str = NULL;
3997 0 js_DestroyPrinter(jp);
3998 0 return str;
3999 }
4000
4001 JS_PUBLIC_API(JSString *)
4002 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
4003 0 {
4004 JSPrinter *jp;
4005 JSString *str;
4006
4007 CHECK_REQUEST(cx);
4008 0 jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
4009 indent & ~JS_DONT_PRETTY_PRINT,
4010 !(indent & JS_DONT_PRETTY_PRINT));
4011 0 if (!jp)
4012 0 return NULL;
4013 0 if (js_DecompileFunctionBody(jp, fun))
4014 0 str = js_GetPrinterOutput(jp);
4015 else
4016 0 str = NULL;
4017 0 js_DestroyPrinter(jp);
4018 0 return str;
4019 }
4020
4021 JS_PUBLIC_API(JSBool)
4022 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
4023 0 {
4024 JSBool ok;
4025
4026 CHECK_REQUEST(cx);
4027 0 ok = js_Execute(cx, obj, script, NULL, 0, rval);
4028 0 LAST_FRAME_CHECKS(cx, ok);
4029 0 return ok;
4030 }
4031
4032 JS_PUBLIC_API(JSBool)
4033 JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script,
4034 JSExecPart part, jsval *rval)
4035 0 {
4036 JSScript tmp;
4037 JSRuntime *rt;
4038 JSBool ok;
4039
4040 /* Make a temporary copy of the JSScript structure and farble it a bit. */
4041 0 tmp = *script;
4042 0 if (part == JSEXEC_PROLOG) {
4043 0 tmp.length = PTRDIFF(tmp.main, tmp.code, jsbytecode);
4044 } else {
4045 0 tmp.length -= PTRDIFF(tmp.main, tmp.code, jsbytecode);
4046 0 tmp.code = tmp.main;
4047 }
4048
4049 /* Tell the debugger about our temporary copy of the script structure. */
4050 0 rt = cx->runtime;
4051 0 if (rt->newScriptHook) {
4052 0 rt->newScriptHook(cx, tmp.filename, tmp.lineno, &tmp, NULL,
4053 rt->newScriptHookData);
4054 }
4055
4056 /* Execute the farbled struct and tell the debugger to forget about it. */
4057 0 ok = JS_ExecuteScript(cx, obj, &tmp, rval);
4058 0 if (rt->destroyScriptHook)
4059 0 rt->destroyScriptHook(cx, &tmp, rt->destroyScriptHookData);
4060 0 return ok;
4061 }
4062
4063 JS_PUBLIC_API(JSBool)
4064 JS_EvaluateScript(JSContext *cx, JSObject *obj,
4065 const char *bytes, uintN nbytes,
4066 const char *filename, uintN lineno,
4067 jsval *rval)
4068 2201 {
4069 2201 size_t length = nbytes;
4070 jschar *chars;
4071 JSBool ok;
4072
4073 CHECK_REQUEST(cx);
4074 2201 chars = js_InflateString(cx, bytes, &length);
4075 2201 if (!chars)
4076 0 return JS_FALSE;
4077 2201 ok = JS_EvaluateUCScript(cx, obj, chars, length, filename, lineno, rval);
4078 2201 JS_free(cx, chars);
4079 2201 return ok;
4080 }
4081
4082 JS_PUBLIC_API(JSBool)
4083 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj,
4084 JSPrincipals *principals,
4085 const char *bytes, uintN nbytes,
4086 const char *filename, uintN lineno,
4087 jsval *rval)
4088 0 {
4089 0 size_t length = nbytes;
4090 jschar *chars;
4091 JSBool ok;
4092
4093 CHECK_REQUEST(cx);
4094 0 chars = js_InflateString(cx, bytes, &length);
4095 0 if (!chars)
4096 0 return JS_FALSE;
4097 0 ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
4098 filename, lineno, rval);
4099 0 JS_free(cx, chars);
4100 0 return ok;
4101 }
4102
4103 JS_PUBLIC_API(JSBool)
4104 JS_EvaluateUCScript(JSContext *cx, JSObject *obj,
4105 const jschar *chars, uintN length,
4106 const char *filename, uintN lineno,
4107 jsval *rval)
4108 2201 {
4109 CHECK_REQUEST(cx);
4110 2201 return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length,
4111 filename, lineno, rval);
4112 }
4113
4114 JS_PUBLIC_API(JSBool)
4115 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
4116 JSPrincipals *principals,
4117 const jschar *chars, uintN length,
4118 const char *filename, uintN lineno,
4119 jsval *rval)
4120 2201 {
4121 uint32 options;
4122 JSScript *script;
4123 JSBool ok;
4124
4125 CHECK_REQUEST(cx);
4126 2201 options = cx->options;
4127 2201 cx->options = options | JSOPTION_COMPILE_N_GO;
4128 2201 script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length,
4129 filename, lineno);
4130 2201 cx->options = options;
4131 2201 if (!script)
4132 0 return JS_FALSE;
4133 2201 ok = js_Execute(cx, obj, script, NULL, 0, rval);
4134 2201 LAST_FRAME_CHECKS(cx, ok);
4135 2201 JS_DestroyScript(cx, script);
4136 2201 return ok;
4137 }
4138
4139 JS_PUBLIC_API(JSBool)
4140 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc,
4141 jsval *argv, jsval *rval)
4142 0 {
4143 JSBool ok;
4144
4145 CHECK_REQUEST(cx);
4146 0 ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(fun->object), argc, argv,
4147 rval);
4148 0 LAST_FRAME_CHECKS(cx, ok);
4149 0 return ok;
4150 }
4151
4152 JS_PUBLIC_API(JSBool)
4153 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
4154 jsval *argv, jsval *rval)
4155 34 {
4156 JSBool ok;
4157 jsval fval;
4158
4159 CHECK_REQUEST(cx);
4160 #if JS_HAS_XML_SUPPORT
4161 34 if (OBJECT_IS_XML(cx, obj)) {
4162 JSXMLObjectOps *ops;
4163 JSAtom *atom;
4164
4165 0 ops = (JSXMLObjectOps *) obj->map->ops;
4166 0 atom = js_Atomize(cx, name, strlen(name), 0);
4167 0 if (!atom)
4168 0 return JS_FALSE;
4169 0 obj = ops->getMethod(cx, obj, ATOM_TO_JSID(atom), &fval);
4170 0 if (!obj)
4171 0 return JS_FALSE;
4172 } else
4173 #endif
4174 34 if (!JS_GetProperty(cx, obj, name, &fval))
4175 0 return JS_FALSE;
4176 34 ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
4177 34 LAST_FRAME_CHECKS(cx, ok);
4178 34 return ok;
4179 }
4180
4181 JS_PUBLIC_API(JSBool)
4182 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
4183 jsval *argv, jsval *rval)
4184 0 {
4185 JSBool ok;
4186
4187 CHECK_REQUEST(cx);
4188 0 ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
4189 0 LAST_FRAME_CHECKS(cx, ok);
4190 0 return ok;
4191 }
4192
4193 JS_PUBLIC_API(JSBranchCallback)
4194 JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb)
4195 0 {
4196 JSBranchCallback oldcb;
4197
4198 0 oldcb = cx->branchCallback;
4199 0 cx->branchCallback = cb;
4200 0 return oldcb;
4201 }
4202
4203 JS_PUBLIC_API(JSBool)
4204 JS_IsRunning(JSContext *cx)
4205 0 {
4206 0 return cx->fp != NULL;
4207 }
4208
4209 JS_PUBLIC_API(JSBool)
4210 JS_IsConstructing(JSContext *cx)
4211 0 {
4212 0 return cx->fp && (cx->fp->flags & JSFRAME_CONSTRUCTING);
4213 }
4214
4215 JS_FRIEND_API(JSBool)
4216 JS_IsAssigning(JSContext *cx)
4217 0 {
4218 JSStackFrame *fp;
4219 jsbytecode *pc;
4220
4221 0 for (fp = cx->fp; fp && !fp->script; fp = fp->down)
4222 continue;
4223 0 if (!fp || !(pc = fp->pc))
4224 0 return JS_FALSE;
4225 0 return (js_CodeSpec[*pc].format & JOF_ASSIGNING) != 0;
4226 }
4227
4228 JS_PUBLIC_API(void)
4229 JS_SetCallReturnValue2(JSContext *cx, jsval v)
4230 0 {
4231 #if JS_HAS_LVALUE_RETURN
4232 0 cx->rval2 = v;
4233 0 cx->rval2set = JS_TRUE;
4234 #endif
4235 0 }
4236
4237 /************************************************************************/
4238
4239 JS_PUBLIC_API(JSString *)
4240 JS_NewString(JSContext *cx, char *bytes, size_t length)
4241 0 {
4242 jschar *chars;
4243 JSString *str;
4244 0 size_t charsLength = length;
4245
4246 CHECK_REQUEST(cx);
4247 /* Make a Unicode vector from the 8-bit char codes in bytes. */
4248 0 chars = js_InflateString(cx, bytes, &charsLength);
4249 0 if (!chars)
4250 0 return NULL;
4251
4252 /* Free chars (but not bytes, which caller frees on error) if we fail. */
4253 0 str = js_NewString(cx, chars, charsLength, 0);
4254 0 if (!str) {
4255 0 JS_free(cx, chars);
4256 0 return NULL;
4257 }
4258
4259 /* Hand off bytes to the deflated string cache, if possible. */
4260 0 if (!js_SetStringBytes(str, bytes, length))
4261 0 JS_free(cx, bytes);
4262 0 return str;
4263 }
4264
4265 JS_PUBLIC_API(JSString *)
4266 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
4267 0 {
4268 jschar *js;
4269 JSString *str;
4270
4271 CHECK_REQUEST(cx);
4272 0 js = js_InflateString(cx, s, &n);
4273 0 if (!js)
4274 0 return NULL;
4275 0 str = js_NewString(cx, js, n, 0);
4276 0 if (!str)
4277 0 JS_free(cx, js);
4278 0 return str;
4279 }
4280
4281 JS_PUBLIC_API(JSString *)
4282 JS_NewStringCopyZ(JSContext *cx, const char *s)
4283 36059 {
4284 size_t n;
4285 jschar *js;
4286 JSString *str;
4287
4288 CHECK_REQUEST(cx);
4289 36059 if (!s)
4290 0 return cx->runtime->emptyString;
4291 36059 n = strlen(s);
4292 36059 js = js_InflateString(cx, s, &n);
4293 36059 if (!js)
4294 0 return NULL;
4295 36059 str = js_NewString(cx, js, n, 0);
4296 36059 if (!str)
4297 0 JS_free(cx, js);
4298 36059 return str;
4299 }
4300
4301 JS_PUBLIC_API(JSString *)
4302 JS_InternString(JSContext *cx, const char *s)
4303 438260 {
4304 JSAtom *atom;
4305
4306 CHECK_REQUEST(cx);
4307 438260 atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
4308 438260 if (!atom)
4309 0 return NULL;
4310 438260 return ATOM_TO_STRING(atom);
4311 }
4312
4313 JS_PUBLIC_API(JSString *)
4314 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
4315 0 {
4316 CHECK_REQUEST(cx);
4317 0 return js_NewString(cx, chars, length, 0);
4318 }
4319
4320 JS_PUBLIC_API(JSString *)
4321 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
4322 0 {
4323 CHECK_REQUEST(cx);
4324 0 return js_NewStringCopyN(cx, s, n, 0);
4325 }
4326
4327 JS_PUBLIC_API(JSString *)
4328 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
4329 0 {
4330 CHECK_REQUEST(cx);
4331 0 if (!s)
4332 0 return cx->runtime->emptyString;
4333 0 return js_NewStringCopyZ(cx, s, 0);
4334 }
4335
4336 JS_PUBLIC_API(JSString *)
4337 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
4338 0 {
4339 JSAtom *atom;
4340
4341 CHECK_REQUEST(cx);
4342 0 atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
4343 0 if (!atom)
4344 0 return NULL;
4345 0 return ATOM_TO_STRING(atom);
4346 }
4347
4348 JS_PUBLIC_API(JSString *)
4349 JS_InternUCString(JSContext *cx, const jschar *s)
4350 0 {
4351 0 return JS_InternUCStringN(cx, s, js_strlen(s));
4352 }
4353
4354 JS_PUBLIC_API(char *)
4355 JS_GetStringBytes(JSString *str)
4356 666834 {
4357 char *bytes;
4358
4359 666834 bytes = js_GetStringBytes(str);
4360 666834 return bytes ? bytes : "";
4361 }
4362
4363 JS_PUBLIC_API(jschar *)
4364 JS_GetStringChars(JSString *str)
4365 0 {
4366 /*
4367 * API botch (again, shades of JS_GetStringBytes): we have no cx to pass
4368 * to js_UndependString (called by js_GetStringChars) for out-of-memory
4369 * error reports, so js_UndependString passes NULL and suppresses errors.
4370 * If it fails to convert a dependent string into an independent one, our
4371 * caller will not be guaranteed a \u0000 terminator as a backstop. This
4372 * may break some clients who already misbehave on embedded NULs.
4373 *
4374 * The gain of dependent strings, which cure quadratic and cubic growth
4375 * rate bugs in string concatenation, is worth this slight loss in API
4376 * compatibility.
4377 */
4378 jschar *chars;
4379
4380 0 chars = js_GetStringChars(str);
4381 0 return chars ? chars : JSSTRING_CHARS(str);
4382 }
4383
4384 JS_PUBLIC_API(size_t)
4385 JS_GetStringLength(JSString *str)
4386 8106 {
4387 8106 return JSSTRING_LENGTH(str);
4388 }
4389
4390 JS_PUBLIC_API(intN)
4391 JS_CompareStrings(JSString *str1, JSString *str2)
4392 0 {
4393 0 return js_CompareStrings(str1, str2);
4394 }
4395
4396 JS_PUBLIC_API(JSString *)
4397 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
4398 0 {
4399 CHECK_REQUEST(cx);
4400 0 return js_NewString(cx, chars, length, GCF_MUTABLE);
4401 }
4402
4403 JS_PUBLIC_API(JSString *)
4404 JS_NewDependentString(JSContext *cx, JSString *str, size_t start,
4405 size_t length)
4406 0 {
4407 CHECK_REQUEST(cx);
4408 0 return js_NewDependentString(cx, str, start, length, 0);
4409 }
4410
4411 JS_PUBLIC_API(JSString *)
4412 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
4413 0 {
4414 CHECK_REQUEST(cx);
4415 0 return js_ConcatStrings(cx, left, right);
4416 }
4417
4418 JS_PUBLIC_API(const jschar *)
4419 JS_UndependString(JSContext *cx, JSString *str)
4420 0 {
4421 CHECK_REQUEST(cx);
4422 0 return js_UndependString(cx, str);
4423 }
4424
4425 JS_PUBLIC_API(JSBool)
4426 JS_MakeStringImmutable(JSContext *cx, JSString *str)
4427 16454 {
4428 CHECK_REQUEST(cx);
4429 16454 if (!js_UndependString(cx, str))
4430 0 return JS_FALSE;
4431
4432 16454 *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
4433 16454 return JS_TRUE;
4434 }
4435
4436 JS_PUBLIC_API(JSBool)
4437 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst,
4438 size_t *dstlenp)
4439 0 {
4440 0 return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
4441 }
4442
4443 JS_PUBLIC_API(JSBool)
4444 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst,
4445 size_t *dstlenp)
4446 0 {
4447 0 return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
4448 }
4449
4450 JS_PUBLIC_API(JSBool)
4451 JS_StringsAreUTF8 ()
4452 0 {
4453 #ifdef JS_C_STRINGS_ARE_UTF8
4454 return JS_TRUE;
4455 #else
4456 0 return JS_FALSE;
4457 #endif
4458 }
4459
4460 /************************************************************************/
4461
4462 JS_PUBLIC_API(void)
4463 JS_ReportError(JSContext *cx, const char *format, ...)
4464 0 {
4465 va_list ap;
4466
4467 0 va_start(ap, format);
4468 0 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
4469 0 va_end(ap);
4470 0 }
4471
4472 JS_PUBLIC_API(void)
4473 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
4474 void *userRef, const uintN errorNumber, ...)
4475 0 {
4476 va_list ap;
4477
4478 0 va_start(ap, errorNumber);
4479 0 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
4480 errorNumber, JS_TRUE, ap);
4481 0 va_end(ap);
4482 0 }
4483
4484 JS_PUBLIC_API(void)
4485 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
4486 void *userRef, const uintN errorNumber, ...)
4487 0 {
4488 va_list ap;
4489
4490 0 va_start(ap, errorNumber);
4491 0 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
4492 errorNumber, JS_FALSE, ap);
4493 0 va_end(ap);
4494 0 }
4495
4496 JS_PUBLIC_API(JSBool)
4497 JS_ReportWarning(JSContext *cx, const char *format, ...)
4498 0 {
4499 va_list ap;
4500 JSBool ok;
4501
4502 0 va_start(ap, format);
4503 0 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
4504 0 va_end(ap);
4505 0 return ok;
4506 }
4507
4508 JS_PUBLIC_API(JSBool)
4509 JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
4510 JSErrorCallback errorCallback, void *userRef,
4511 const uintN errorNumber, ...)
4512 0 {
4513 va_list ap;
4514 JSBool ok;
4515
4516 0 va_start(ap, errorNumber);
4517 0 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
4518 errorNumber, JS_TRUE, ap);
4519 0 va_end(ap);
4520 0 return ok;
4521 }
4522
4523 JS_PUBLIC_API(JSBool)
4524 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
4525 JSErrorCallback errorCallback, void *userRef,
4526 const uintN errorNumber, ...)
4527 0 {
4528 va_list ap;
4529 JSBool ok;
4530
4531 0 va_start(ap, errorNumber);
4532 0 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
4533 errorNumber, JS_FALSE, ap);
4534 0 va_end(ap);
4535 0 return ok;
4536 }
4537
4538 JS_PUBLIC_API(void)
4539 JS_ReportOutOfMemory(JSContext *cx)
4540 0 {
4541 0 js_ReportOutOfMemory(cx, js_GetErrorMessage);
4542 0 }
4543
4544 JS_PUBLIC_API(JSErrorReporter)
4545 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
4546 184264 {
4547 JSErrorReporter older;
4548
4549 184264 older = cx->errorReporter;
4550 184264 cx->errorReporter = er;
4551 184264 return older;
4552 }
4553
4554 /************************************************************************/
4555
4556 /*
4557 * Regular Expressions.
4558 */
4559 JS_PUBLIC_API(JSObject *)
4560 JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags)
4561 0 {
4562 #if JS_HAS_REGEXPS
4563 jschar *chars;
4564 JSObject *obj;
4565
4566 CHECK_REQUEST(cx);
4567 0 chars = js_InflateString(cx, bytes, &length);
4568 0 if (!chars)
4569 0 return NULL;
4570 0 obj = js_NewRegExpObject(cx, NULL, chars, length, flags);
4571 0 JS_free(cx, chars);
4572 0 return obj;
4573 #else
4574 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_REG_EXPS);
4575 return NULL;
4576 #endif
4577 }
4578
4579 JS_PUBLIC_API(JSObject *)
4580 JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags)
4581 0 {
4582 CHECK_REQUEST(cx);
4583 #if JS_HAS_REGEXPS
4584 0 return js_NewRegExpObject(cx, NULL, chars, length, flags);
4585 #else
4586 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_REG_EXPS);
4587 return NULL;
4588 #endif
4589 }
4590
4591 JS_PUBLIC_API(void)
4592 JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline)
4593 0 {
4594 JSRegExpStatics *res;
4595
4596 CHECK_REQUEST(cx);
4597 /* No locking required, cx is thread-private and input must be live. */
4598 0 res = &cx->regExpStatics;
4599 0 res->input = input;
4600 0 res->multiline = multiline;
4601 0 cx->runtime->gcPoke = JS_TRUE;
4602 0 }
4603
4604 JS_PUBLIC_API(void)
4605 JS_ClearRegExpStatics(JSContext *cx)
4606 34 {
4607 JSRegExpStatics *res;
4608
4609 /* No locking required, cx is thread-private and input must be live. */
4610 34 res = &cx->regExpStatics;
4611 34 res->input = NULL;
4612 34 res->multiline = JS_FALSE;
4613 34 res->parenCount = 0;
4614 34 res->lastMatch = res->lastParen = js_EmptySubString;
4615 34 res->leftContext = res->rightContext = js_EmptySubString;
4616 34 cx->runtime->gcPoke = JS_TRUE;
4617 34 }
4618
4619 JS_PUBLIC_API(void)
4620 JS_ClearRegExpRoots(JSContext *cx)
4621 0 {
4622 JSRegExpStatics *res;
4623
4624 /* No locking required, cx is thread-private and input must be live. */
4625 0 res = &cx->regExpStatics;
4626 0 res->input = NULL;
4627 0 cx->runtime->gcPoke = JS_TRUE;
4628 0 }
4629
4630 /* TODO: compile, execute, get/set other statics... */
4631
4632 /************************************************************************/
4633
4634 JS_PUBLIC_API(void)
4635 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
4636 0 {
4637 0 cx->localeCallbacks = callbacks;
4638 0 }
4639
4640 JS_PUBLIC_API(JSLocaleCallbacks *)
4641 JS_GetLocaleCallbacks(JSContext *cx)
4642 0 {
4643 0 return cx->localeCallbacks;
4644 }
4645
4646 /************************************************************************/
4647
4648 JS_PUBLIC_API(JSBool)
4649 JS_IsExceptionPending(JSContext *cx)
4650 0 {
4651 #if JS_HAS_EXCEPTIONS
4652 0 return (JSBool) cx->throwing;
4653 #else
4654 return JS_FALSE;
4655 #endif
4656 }
4657
4658 JS_PUBLIC_API(JSBool)
4659 JS_GetPendingException(JSContext *cx, jsval *vp)
4660 0 {
4661 #if JS_HAS_EXCEPTIONS
4662 CHECK_REQUEST(cx);
4663 0 if (!cx->throwing)
4664 0 return JS_FALSE;
4665 0 *vp = cx->exception;
4666 0 return JS_TRUE;
4667 #else
4668 return JS_FALSE;
4669 #endif
4670 }
4671
4672 JS_PUBLIC_API(void)
4673 JS_SetPendingException(JSContext *cx, jsval v)
4674 0 {
4675 CHECK_REQUEST(cx);
4676 #if JS_HAS_EXCEPTIONS
4677 0 cx->throwing = JS_TRUE;
4678 0 cx->exception = v;
4679 #endif
4680 0 }
4681
4682 JS_PUBLIC_API(void)
4683 JS_ClearPendingException(JSContext *cx)
4684 0 {
4685 #if JS_HAS_EXCEPTIONS
4686 0 cx->throwing = JS_FALSE;
4687 0 cx->exception = JSVAL_VOID;
4688 #endif
4689 0 }
4690
4691 JS_PUBLIC_API(JSBool)
4692 JS_ReportPendingException(JSContext *cx)
4693 0 {
4694 #if JS_HAS_EXCEPTIONS
4695 JSBool save, ok;
4696
4697 CHECK_REQUEST(cx);
4698
4699 /*
4700 * Set cx->creatingException to suppress the standard error-to-exception
4701 * conversion done by all {js,JS}_Report* functions except for OOM. The
4702 * cx->creatingException flag was added to suppress recursive divergence
4703 * under js_ErrorToException, but it serves for our purposes here too.
4704 */
4705 0 save = cx->creatingException;
4706 0 cx->creatingException = JS_TRUE;
4707 0 ok = js_ReportUncaughtException(cx);
4708 0 cx->creatingException = save;
4709 0 return ok;
4710 #else
4711 return JS_TRUE;
4712 #endif
4713 }
4714
4715 #if JS_HAS_EXCEPTIONS
4716 struct JSExceptionState {
4717 JSBool throwing;
4718 jsval exception;
4719 };
4720 #endif
4721
4722 JS_PUBLIC_API(JSExceptionState *)
4723 JS_SaveExceptionState(JSContext *cx)
4724 0 {
4725 #if JS_HAS_EXCEPTIONS
4726 JSExceptionState *state;
4727
4728 CHECK_REQUEST(cx);
4729 0 state = (JSExceptionState *) JS_malloc(cx, sizeof(JSExceptionState));
4730 0 if (state) {
4731 0 state->throwing = JS_GetPendingException(cx, &state->exception);
4732 0 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
4733 0 js_AddRoot(cx, &state->exception, "JSExceptionState.exception");
4734 }
4735 0 return state;
4736 #else
4737 return NULL;
4738 #endif
4739 }
4740
4741 JS_PUBLIC_API(void)
4742 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
4743 0 {
4744 #if JS_HAS_EXCEPTIONS
4745 CHECK_REQUEST(cx);
4746 0 if (state) {
4747 0 if (state->throwing)
4748 0 JS_SetPendingException(cx, state->exception);
4749 else
4750 0 JS_ClearPendingException(cx);
4751 0 JS_DropExceptionState(cx, state);
4752 }
4753 #endif
4754 0 }
4755
4756 JS_PUBLIC_API(void)
4757 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
4758 0 {
4759 #if JS_HAS_EXCEPTIONS
4760 CHECK_REQUEST(cx);
4761 0 if (state) {
4762 0 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
4763 0 JS_RemoveRoot(cx, &state->exception);
4764 0 JS_free(cx, state);
4765 }
4766 #endif
4767 0 }
4768
4769 JS_PUBLIC_API(JSErrorReport *)
4770 JS_ErrorFromException(JSContext *cx, jsval v)
4771 0 {
4772 #if JS_HAS_ERROR_EXCEPTIONS
4773 CHECK_REQUEST(cx);
4774 0 return js_ErrorFromException(cx, v);
4775 #else
4776 return NULL;
4777 #endif
4778 }
4779
4780 JS_PUBLIC_API(JSBool)
4781 JS_ThrowReportedError(JSContext *cx, const char *message,
4782 JSErrorReport *reportp)
4783 0 {
4784 0 return js_ErrorToException(cx, message, reportp);
4785 }
4786
4787 #ifdef JS_THREADSAFE
4788 JS_PUBLIC_API(jsword)
4789 JS_GetContextThread(JSContext *cx)
4790 {
4791 return cx->thread;
4792 }
4793
4794 JS_PUBLIC_API(jsword)
4795 JS_SetContextThread(JSContext *cx)
4796 {
4797 jsword old = cx->thread;
4798 cx->thread = js_CurrentThreadId();
4799 return old;
4800 }
4801
4802 JS_PUBLIC_API(jsword)
4803 JS_ClearContextThread(JSContext *cx)
4804 {
4805 jsword old = cx->thread;
4806 cx->thread = 0;
4807 return old;
4808 }
4809 #endif
4810
4811 /************************************************************************/
4812
4813 #if defined(XP_WIN)
4814 #include <windows.h>
4815 /*
4816 * Initialization routine for the JS DLL...
4817 */
4818
4819 /*
4820 * Global Instance handle...
4821 * In Win32 this is the module handle of the DLL.
4822 *
4823 * In Win16 this is the instance handle of the application
4824 * which loaded the DLL.
4825 */
4826
4827 #ifdef _WIN32
4828 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
4829 {
4830 return TRUE;
4831 }
4832
4833 #else /* !_WIN32 */
4834
4835 int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg,
4836 WORD cbHeapSize, LPSTR lpszCmdLine )
4837 {
4838 return TRUE;
4839 }
4840
4841 BOOL CALLBACK __loadds WEP(BOOL fSystemExit)
4842 {
4843 return TRUE;
4844 }
4845
4846 #endif /* !_WIN32 */