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 ***** */
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"
81 #if JS_HAS_FILE_OBJECT
82 #include "jsfile.h"
83 #endif
85 #if JS_HAS_XML_SUPPORT
86 #include "jsxml.h"
87 #endif
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
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
101 JS_PUBLIC_API(int64)
102 JS_Now()
103 {
104 return PRMJ_Now();
105 }
107 JS_PUBLIC_API(jsval)
108 JS_GetNaNValue(JSContext *cx)
109 {
110 return DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
111 }
113 JS_PUBLIC_API(jsval)
114 JS_GetNegativeInfinityValue(JSContext *cx)
115 {
116 return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
117 }
119 JS_PUBLIC_API(jsval)
120 JS_GetPositiveInfinityValue(JSContext *cx)
121 {
122 return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
123 }
125 JS_PUBLIC_API(jsval)
126 JS_GetEmptyStringValue(JSContext *cx)
127 {
128 return STRING_TO_JSVAL(cx->runtime->emptyString);
129 }
131 static JSBool
132 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS,
133 jsval **vpp, va_list *app)
134 {
135 const char *format;
136 JSArgumentFormatMap *map;
138 format = *formatp;
139 for (map = cx->argumentFormatMap; map; map = map->next) {
140 if (!strncmp(format, map->format, map->length)) {
141 *formatp = format + map->length;
142 return map->formatter(cx, format, fromJS, vpp, app);
143 }
144 }
145 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
146 return JS_FALSE;
147 }
149 JS_PUBLIC_API(JSBool)
150 JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
151 ...)
152 {
153 va_list ap;
154 JSBool ok;
156 va_start(ap, format);
157 ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
158 va_end(ap);
159 return ok;
160 }
162 JS_PUBLIC_API(JSBool)
163 JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
164 const char *format, va_list ap)
165 {
166 jsval *sp;
167 JSBool required;
168 char c;
169 JSFunction *fun;
170 jsdouble d;
171 JSString *str;
172 JSObject *obj;
174 CHECK_REQUEST(cx);
175 sp = argv;
176 required = JS_TRUE;
177 while ((c = *format++) != '\0') {
178 if (isspace(c))
179 continue;
180 if (c == '/') {
181 required = JS_FALSE;
182 continue;
183 }
184 if (sp == argv + argc) {
185 if (required) {
186 fun = js_ValueToFunction(cx, &argv[-2], 0);
187 if (fun) {
188 char numBuf[12];
189 JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
190 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
191 JSMSG_MORE_ARGS_NEEDED,
192 JS_GetFunctionName(fun), numBuf,
193 (argc == 1) ? "" : "s");
194 }
195 return JS_FALSE;
196 }
197 break;
198 }
199 switch (c) {
200 case 'b':
201 if (!js_ValueToBoolean(cx, *sp, va_arg(ap, JSBool *)))
202 return JS_FALSE;
203 break;
204 case 'c':
205 if (!js_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
206 return JS_FALSE;
207 break;
208 case 'i':
209 if (!js_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
210 return JS_FALSE;
211 break;
212 case 'u':
213 if (!js_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
214 return JS_FALSE;
215 break;
216 case 'j':
217 if (!js_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
218 return JS_FALSE;
219 break;
220 case 'd':
221 if (!js_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
222 return JS_FALSE;
223 break;
224 case 'I':
225 if (!js_ValueToNumber(cx, *sp, &d))
226 return JS_FALSE;
227 *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
228 break;
229 case 's':
230 case 'S':
231 case 'W':
232 str = js_ValueToString(cx, *sp);
233 if (!str)
234 return JS_FALSE;
235 *sp = STRING_TO_JSVAL(str);
236 if (c == 's')
237 *va_arg(ap, char **) = JS_GetStringBytes(str);
238 else if (c == 'W')
239 *va_arg(ap, jschar **) = JS_GetStringChars(str);
240 else
241 *va_arg(ap, JSString **) = str;
242 break;
243 case 'o':
244 if (!js_ValueToObject(cx, *sp, &obj))
245 return JS_FALSE;
246 *sp = OBJECT_TO_JSVAL(obj);
247 *va_arg(ap, JSObject **) = obj;
248 break;
249 case 'f':
250 obj = js_ValueToFunctionObject(cx, sp, 0);
251 if (!obj)
252 return JS_FALSE;
253 *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj);
254 break;
255 case 'v':
256 *va_arg(ap, jsval *) = *sp;
257 break;
258 case '*':
259 break;
260 default:
261 format--;
262 if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
263 JS_ADDRESSOF_VA_LIST(ap))) {
264 return JS_FALSE;
265 }
266 /* NB: the formatter already updated sp, so we continue here. */
267 continue;
268 }
269 sp++;
270 }
271 return JS_TRUE;
272 }
274 JS_PUBLIC_API(jsval *)
275 JS_PushArguments(JSContext *cx, void **markp, const char *format, ...)
276 {
277 va_list ap;
278 jsval *argv;
280 va_start(ap, format);
281 argv = JS_PushArgumentsVA(cx, markp, format, ap);
282 va_end(ap);
283 return argv;
284 }
286 JS_PUBLIC_API(jsval *)
287 JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap)
288 {
289 uintN argc;
290 jsval *argv, *sp;
291 char c;
292 const char *cp;
293 JSString *str;
294 JSFunction *fun;
295 JSStackHeader *sh;
297 CHECK_REQUEST(cx);
298 *markp = NULL;
299 argc = 0;
300 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 if (isspace(c) || c == '*')
306 continue;
307 argc++;
308 }
309 sp = js_AllocStack(cx, argc, markp);
310 if (!sp)
311 return NULL;
312 argv = sp;
313 while ((c = *format++) != '\0') {
314 if (isspace(c) || c == '*')
315 continue;
316 switch (c) {
317 case 'b':
318 *sp = BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int));
319 break;
320 case 'c':
321 *sp = INT_TO_JSVAL((uint16) va_arg(ap, unsigned int));
322 break;
323 case 'i':
324 case 'j':
325 if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp))
326 goto bad;
327 break;
328 case 'u':
329 if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp))
330 goto bad;
331 break;
332 case 'd':
333 case 'I':
334 if (!js_NewDoubleValue(cx, va_arg(ap, jsdouble), sp))
335 goto bad;
336 break;
337 case 's':
338 str = JS_NewStringCopyZ(cx, va_arg(ap, char *));
339 if (!str)
340 goto bad;
341 *sp = STRING_TO_JSVAL(str);
342 break;
343 case 'W':
344 str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *));
345 if (!str)
346 goto bad;
347 *sp = STRING_TO_JSVAL(str);
348 break;
349 case 'S':
350 str = va_arg(ap, JSString *);
351 *sp = STRING_TO_JSVAL(str);
352 break;
353 case 'o':
354 *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *));
355 break;
356 case 'f':
357 fun = va_arg(ap, JSFunction *);
358 *sp = fun ? OBJECT_TO_JSVAL(fun->object) : JSVAL_NULL;
359 break;
360 case 'v':
361 *sp = va_arg(ap, jsval);
362 break;
363 default:
364 format--;
365 if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp,
366 JS_ADDRESSOF_VA_LIST(ap))) {
367 goto bad;
368 }
369 /* NB: the formatter already updated sp, so we continue here. */
370 continue;
371 }
372 sp++;
373 }
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 if (sp < argv + argc) {
381 /* Return slots not pushed to the current stack arena. */
382 cx->stackPool.current->avail = (jsuword)sp;
384 /* Reduce the count of slots the GC will scan in this stack segment. */
385 sh = cx->stackHeaders;
386 JS_ASSERT(JS_STACK_SEGMENT(sh) + sh->nslots == argv + argc);
387 sh->nslots -= argc - (sp - argv);
388 }
389 return argv;
391 bad:
392 js_FreeStack(cx, *markp);
393 return NULL;
394 }
396 JS_PUBLIC_API(void)
397 JS_PopArguments(JSContext *cx, void *mark)
398 {
399 CHECK_REQUEST(cx);
400 js_FreeStack(cx, mark);
401 }
403 JS_PUBLIC_API(JSBool)
404 JS_AddArgumentFormatter(JSContext *cx, const char *format,
405 JSArgumentFormatter formatter)
406 {
407 size_t length;
408 JSArgumentFormatMap **mpp, *map;
410 length = strlen(format);
411 mpp = &cx->argumentFormatMap;
412 while ((map = *mpp) != NULL) {
413 /* Insert before any shorter string to match before prefixes. */
414 if (map->length < length)
415 break;
416 if (map->length == length && !strcmp(map->format, format))
417 goto out;
418 mpp = &map->next;
419 }
420 map = (JSArgumentFormatMap *) JS_malloc(cx, sizeof *map);
421 if (!map)
422 return JS_FALSE;
423 map->format = format;
424 map->length = length;
425 map->next = *mpp;
426 *mpp = map;
427 out:
428 map->formatter = formatter;
429 return JS_TRUE;
430 }
432 JS_PUBLIC_API(void)
433 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
434 {
435 size_t length;
436 JSArgumentFormatMap **mpp, *map;
438 length = strlen(format);
439 mpp = &cx->argumentFormatMap;
440 while ((map = *mpp) != NULL) {
441 if (map->length == length && !strcmp(map->format, format)) {
442 *mpp = map->next;
443 JS_free(cx, map);
444 return;
445 }
446 mpp = &map->next;
447 }
448 }
450 JS_PUBLIC_API(JSBool)
451 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
452 {
453 JSBool ok, b;
454 JSObject *obj;
455 JSString *str;
456 jsdouble d, *dp;
458 CHECK_REQUEST(cx);
459 switch (type) {
460 case JSTYPE_VOID:
461 *vp = JSVAL_VOID;
462 ok = JS_TRUE;
463 break;
464 case JSTYPE_OBJECT:
465 ok = js_ValueToObject(cx, v, &obj);
466 if (ok)
467 *vp = OBJECT_TO_JSVAL(obj);
468 break;
469 case JSTYPE_FUNCTION:
470 *vp = v;
471 obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK);
472 ok = (obj != NULL);
473 break;
474 case JSTYPE_STRING:
475 str = js_ValueToString(cx, v);
476 ok = (str != NULL);
477 if (ok)
478 *vp = STRING_TO_JSVAL(str);
479 break;
480 case JSTYPE_NUMBER:
481 ok = js_ValueToNumber(cx, v, &d);
482 if (ok) {
483 dp = js_NewDouble(cx, d, 0);
484 ok = (dp != NULL);
485 if (ok)
486 *vp = DOUBLE_TO_JSVAL(dp);
487 }
488 break;
489 case JSTYPE_BOOLEAN:
490 ok = js_ValueToBoolean(cx, v, &b);
491 if (ok)
492 *vp = BOOLEAN_TO_JSVAL(b);
493 break;
494 default: {
495 char numBuf[12];
496 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
497 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
498 numBuf);
499 ok = JS_FALSE;
500 break;
501 }
502 }
503 return ok;
504 }
506 JS_PUBLIC_API(JSBool)
507 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
508 {
509 CHECK_REQUEST(cx);
510 return js_ValueToObject(cx, v, objp);
511 }
513 JS_PUBLIC_API(JSFunction *)
514 JS_ValueToFunction(JSContext *cx, jsval v)
515 {
516 CHECK_REQUEST(cx);
517 return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
518 }
520 JS_PUBLIC_API(JSFunction *)
521 JS_ValueToConstructor(JSContext *cx, jsval v)
522 {
523 CHECK_REQUEST(cx);
524 return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
525 }
527 JS_PUBLIC_API(JSString *)
528 JS_ValueToString(JSContext *cx, jsval v)
529 {
530 CHECK_REQUEST(cx);
531 return js_ValueToString(cx, v);
532 }
534 JS_PUBLIC_API(JSBool)
535 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
536 {
537 CHECK_REQUEST(cx);
538 return js_ValueToNumber(cx, v, dp);
539 }
541 JS_PUBLIC_API(JSBool)
542 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
543 {
544 CHECK_REQUEST(cx);
545 return js_ValueToECMAInt32(cx, v, ip);
546 }
548 JS_PUBLIC_API(JSBool)
549 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
550 {
551 CHECK_REQUEST(cx);
552 return js_ValueToECMAUint32(cx, v, ip);
553 }
555 JS_PUBLIC_API(JSBool)
556 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
557 {
558 CHECK_REQUEST(cx);
559 return js_ValueToInt32(cx, v, ip);
560 }
562 JS_PUBLIC_API(JSBool)
563 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
564 {
565 CHECK_REQUEST(cx);
566 return js_ValueToUint16(cx, v, ip);
567 }
569 JS_PUBLIC_API(JSBool)
570 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
571 {
572 CHECK_REQUEST(cx);
573 return js_ValueToBoolean(cx, v, bp);
574 }
576 JS_PUBLIC_API(JSType)
577 JS_TypeOfValue(JSContext *cx, jsval v)
578 {
579 JSType type;
580 JSObject *obj;
581 JSObjectOps *ops;
582 JSClass *clasp;
584 CHECK_REQUEST(cx);
585 if (JSVAL_IS_OBJECT(v)) {
586 type = JSTYPE_OBJECT; /* XXXbe JSTYPE_NULL for JS2 */
587 obj = JSVAL_TO_OBJECT(v);
588 if (obj) {
589 ops = obj->map->ops;
590 #if JS_HAS_XML_SUPPORT
591 if (ops == &js_XMLObjectOps.base) {
592 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 clasp = OBJ_GET_CLASS(cx, obj);
603 if ((ops == &js_ObjectOps)
604 ? (clasp->call
605 ? (clasp == &js_RegExpClass || clasp == &js_ScriptClass)
606 : clasp == &js_FunctionClass)
607 : ops->call != NULL) {
608 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 } else if (JSVAL_IS_NUMBER(v)) {
624 type = JSTYPE_NUMBER;
625 } else if (JSVAL_IS_STRING(v)) {
626 type = JSTYPE_STRING;
627 } else if (JSVAL_IS_BOOLEAN(v)) {
628 type = JSTYPE_BOOLEAN;
629 } else {
630 type = JSTYPE_VOID;
631 }
632 return type;
633 }
635 JS_PUBLIC_API(const char *)
636 JS_GetTypeName(JSContext *cx, JSType type)
637 {
638 if ((uintN)type >= (uintN)JSTYPE_LIMIT)
639 return NULL;
640 return js_type_str[type];
641 }
643 /************************************************************************/
645 JS_PUBLIC_API(JSRuntime *)
646 JS_NewRuntime(uint32 maxbytes)
647 {
648 JSRuntime *rt;
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 */
666 if (!js_InitStringGlobals())
667 return NULL;
668 rt = (JSRuntime *) malloc(sizeof(JSRuntime));
669 if (!rt)
670 return NULL;
672 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
673 memset(rt, 0, sizeof(JSRuntime));
674 JS_INIT_CLIST(&rt->contextList);
675 JS_INIT_CLIST(&rt->trapList);
676 JS_INIT_CLIST(&rt->watchPointList);
678 if (!js_InitGC(rt, maxbytes))
679 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 rt->propertyCache.empty = JS_TRUE;
711 if (!js_InitPropertyTree(rt))
712 goto bad;
713 return rt;
715 bad:
716 JS_DestroyRuntime(rt);
717 return NULL;
718 }
720 JS_PUBLIC_API(void)
721 JS_DestroyRuntime(JSRuntime *rt)
722 {
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
736 js_FreeRuntimeScriptState(rt);
737 js_FinishAtomState(&rt->atomState);
738 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 js_FinishPropertyTree(rt);
758 free(rt);
759 }
761 JS_PUBLIC_API(void)
762 JS_ShutDown(void)
763 {
764 JS_ArenaShutDown();
765 js_FinishDtoa();
766 js_FreeStringGlobals();
767 #ifdef JS_THREADSAFE
768 js_CleanupLocks();
769 #endif
770 }
772 JS_PUBLIC_API(void *)
773 JS_GetRuntimePrivate(JSRuntime *rt)
774 {
775 return rt->data;
776 }
778 JS_PUBLIC_API(void)
779 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
780 {
781 rt->data = data;
782 }
784 #ifdef JS_THREADSAFE
786 JS_PUBLIC_API(void)
787 JS_BeginRequest(JSContext *cx)
788 {
789 JSRuntime *rt;
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);
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 }
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 }
812 JS_PUBLIC_API(void)
813 JS_EndRequest(JSContext *cx)
814 {
815 JSRuntime *rt;
816 JSScope *scope, **todop;
817 uintN nshares;
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;
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 */
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);
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);
861 JS_UNLOCK_GC(rt);
862 return;
863 }
865 cx->requestDepth--;
866 }
868 /* Yield to pending GC operations, regardless of request depth */
869 JS_PUBLIC_API(void)
870 JS_YieldRequest(JSContext *cx)
871 {
872 JSRuntime *rt;
874 JS_ASSERT(cx->thread);
875 CHECK_REQUEST(cx);
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 }
891 JS_PUBLIC_API(jsrefcount)
892 JS_SuspendRequest(JSContext *cx)
893 {
894 jsrefcount saveDepth = cx->requestDepth;
896 while (cx->requestDepth)
897 JS_EndRequest(cx);
898 return saveDepth;
899 }
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 }
909 #endif /* JS_THREADSAFE */
911 JS_PUBLIC_API(void)
912 JS_Lock(JSRuntime *rt)
913 {
914 JS_LOCK_RUNTIME(rt);
915 }
917 JS_PUBLIC_API(void)
918 JS_Unlock(JSRuntime *rt)
919 {
920 JS_UNLOCK_RUNTIME(rt);
921 }
923 JS_PUBLIC_API(JSContext *)
924 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
925 {
926 return js_NewContext(rt, stackChunkSize);
927 }
929 JS_PUBLIC_API(void)
930 JS_DestroyContext(JSContext *cx)
931 {
932 js_DestroyContext(cx, JS_FORCE_GC);
933 }
935 JS_PUBLIC_API(void)
936 JS_DestroyContextNoGC(JSContext *cx)
937 {
938 js_DestroyContext(cx, JS_NO_GC);
939 }
941 JS_PUBLIC_API(void)
942 JS_DestroyContextMaybeGC(JSContext *cx)
943 {
944 js_DestroyContext(cx, JS_MAYBE_GC);
945 }
947 JS_PUBLIC_API(void *)
948 JS_GetContextPrivate(JSContext *cx)
949 {
950 return cx->data;
951 }
953 JS_PUBLIC_API(void)
954 JS_SetContextPrivate(JSContext *cx, void *data)
955 {
956 cx->data = data;
957 }
959 JS_PUBLIC_API(JSRuntime *)
960 JS_GetRuntime(JSContext *cx)
961 {
962 return cx->runtime;
963 }
965 JS_PUBLIC_API(JSContext *)
966 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
967 {
968 return js_ContextIterator(rt, JS_TRUE, iterp);
969 }
971 JS_PUBLIC_API(JSVersion)
972 JS_GetVersion(JSContext *cx)
973 {
974 return cx->version & JSVERSION_MASK;
975 }
977 JS_PUBLIC_API(JSVersion)
978 JS_SetVersion(JSContext *cx, JSVersion version)
979 {
980 JSVersion oldVersion;
982 JS_ASSERT(version != JSVERSION_UNKNOWN);
983 JS_ASSERT((version & ~JSVERSION_MASK) == 0);
985 oldVersion = cx->version & JSVERSION_MASK;
986 if (version == oldVersion)
987 return oldVersion;
989 cx->version = (cx->version & ~JSVERSION_MASK) | version;
990 js_OnVersionChange(cx);
991 return oldVersion;
992 }
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 };
1010 JS_PUBLIC_API(const char *)
1011 JS_VersionToString(JSVersion version)
1012 {
1013 int i;
1015 for (i = 0; v2smap[i].string; i++)
1016 if (v2smap[i].version == version)
1017 return v2smap[i].string;
1018 return "unknown";
1019 }
1021 JS_PUBLIC_API(JSVersion)
1022 JS_StringToVersion(const char *string)
1023 {
1024 int i;
1026 for (i = 0; v2smap[i].string; i++)
1027 if (strcmp(v2smap[i].string, string) == 0)
1028 return v2smap[i].version;
1029 return JSVERSION_UNKNOWN;
1030 }
1032 JS_PUBLIC_API(uint32)
1033 JS_GetOptions(JSContext *cx)
1034 {
1035 return cx->options;
1036 }
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
1046 JS_PUBLIC_API(uint32)
1047 JS_SetOptions(JSContext *cx, uint32 options)
1048 {
1049 uint32 oldopts = cx->options;
1050 cx->options = options;
1051 SYNC_OPTIONS_TO_VERSION(cx);
1052 return oldopts;
1053 }
1055 JS_PUBLIC_API(uint32)
1056 JS_ToggleOptions(JSContext *cx, uint32 options)
1057 {
1058 uint32 oldopts = cx->options;
1059 cx->options ^= options;
1060 SYNC_OPTIONS_TO_VERSION(cx);
1061 return oldopts;
1062 }
1064 JS_PUBLIC_API(const char *)
1065 JS_GetImplementationVersion(void)
1066 {
1067 return "JavaScript-C 1.6 2006-11-19";
1068 }
1071 JS_PUBLIC_API(JSObject *)
1072 JS_GetGlobalObject(JSContext *cx)
1073 {
1074 return cx->globalObject;
1075 }
1077 JS_PUBLIC_API(void)
1078 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1079 {
1080 cx->globalObject = obj;
1081 #if JS_HAS_XML_SUPPORT
1082 cx->xmlSettingFlags = 0;
1083 #endif
1084 }
1086 static JSObject *
1087 InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1088 {
1089 JSDHashTable *table;
1090 JSBool resolving;
1091 JSRuntime *rt;
1092 JSResolvingKey key;
1093 JSResolvingEntry *entry;
1094 JSObject *fun_proto, *obj_proto;
1096 /* If cx has no global object, use obj so prototypes can be found. */
1097 if (!cx->globalObject)
1098 JS_SetGlobalObject(cx, obj);
1100 /* Record Function and Object in cx->resolvingTable, if we are resolving. */
1101 table = cx->resolvingTable;
1102 resolving = (table && table->entryCount);
1103 if (resolving) {
1104 rt = cx->runtime;
1105 key.obj = obj;
1106 key.id = ATOM_TO_JSID(rt->atomState.FunctionAtom);
1107 entry = (JSResolvingEntry *)
1108 JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1109 if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) {
1110 /* Already resolving Function, record Object too. */
1111 JS_ASSERT(entry->key.obj == obj);
1112 key.id = ATOM_TO_JSID(rt->atomState.ObjectAtom);
1113 entry = (JSResolvingEntry *)
1114 JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1115 }
1116 if (!entry) {
1117 JS_ReportOutOfMemory(cx);
1118 return NULL;
1119 }
1120 JS_ASSERT(!entry->key.obj && entry->flags == 0);
1121 entry->key = key;
1122 entry->flags = JSRESFLAG_LOOKUP;
1123 }
1125 /* Initialize the function class first so constructors can be made. */
1126 fun_proto = js_InitFunctionClass(cx, obj);
1127 if (!fun_proto)
1128 goto out;
1130 /* Initialize the object class next so Object.prototype works. */
1131 obj_proto = js_InitObjectClass(cx, obj);
1132 if (!obj_proto) {
1133 fun_proto = NULL;
1134 goto out;
1135 }
1137 /* Function.prototype and the global object delegate to Object.prototype. */
1138 OBJ_SET_PROTO(cx, fun_proto, obj_proto);
1139 if (!OBJ_GET_PROTO(cx, obj))
1140 OBJ_SET_PROTO(cx, obj, obj_proto);
1142 out:
1143 /* If resolving, remove the other entry (Object or Function) from table. */
1144 if (resolving)
1145 JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1146 return fun_proto;
1147 }
1149 JS_PUBLIC_API(JSBool)
1150 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1151 {
1152 CHECK_REQUEST(cx);
1154 #if JS_HAS_UNDEFINED
1155 {
1156 /* Define a top-level property 'undefined' with the undefined value. */
1157 JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1158 if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1159 NULL, NULL, JSPROP_PERMANENT, NULL)) {
1160 return JS_FALSE;
1161 }
1162 }
1163 #endif
1165 /* Function and Object require cooperative bootstrapping magic. */
1166 if (!InitFunctionAndObjectClasses(cx, obj))
1167 return JS_FALSE;
1169 /* Initialize the rest of the standard objects and functions. */
1170 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 }
1196 #define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom)
1197 #define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
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 };
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;
1249 static JSAtom *
1250 StdNameToAtom(JSContext *cx, JSStdName *stdn)
1251 {
1252 size_t offset;
1253 JSAtom *atom;
1254 const char *name;
1256 offset = stdn->atomOffset;
1257 atom = OFFSET_TO_ATOM(cx->runtime, offset);
1258 if (!atom) {
1259 name = stdn->name;
1260 if (name) {
1261 atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1262 OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1263 }
1264 }
1265 return atom;
1266 }
1268 #define EAGERLY_PINNED_ATOM(name) ATOM_OFFSET(name), NULL
1269 #define LAZILY_PINNED_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
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)},
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)},
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
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
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
1313 {NULL, 0, NULL}
1314 };
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
1343 {NULL, 0, NULL}
1344 };
1346 #undef EAGERLY_PINNED_ATOM
1347 #undef LAZILY_PINNED_ATOM
1349 JS_PUBLIC_API(JSBool)
1350 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
1351 JSBool *resolved)
1352 {
1353 JSString *idstr;
1354 JSRuntime *rt;
1355 JSAtom *atom;
1356 JSObjectOp init;
1357 uintN i;
1359 CHECK_REQUEST(cx);
1360 *resolved = JS_FALSE;
1362 if (!JSVAL_IS_STRING(id))
1363 return JS_TRUE;
1364 idstr = JSVAL_TO_STRING(id);
1365 rt = cx->runtime;
1367 #if JS_HAS_UNDEFINED
1368 /* Check whether we're resolving 'undefined', and define it if so. */
1369 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1370 if (idstr == ATOM_TO_STRING(atom)) {
1371 *resolved = JS_TRUE;
1372 return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1373 NULL, NULL, JSPROP_PERMANENT, NULL);
1374 }
1375 #endif
1377 /* Try for class constructors/prototypes named by well-known atoms. */
1378 init = NULL;
1379 for (i = 0; standard_class_atoms[i].init; i++) {
1380 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1381 if (idstr == ATOM_TO_STRING(atom)) {
1382 init = standard_class_atoms[i].init;
1383 break;
1384 }
1385 }
1387 if (!init) {
1388 /* Try less frequently used top-level functions and constants. */
1389 for (i = 0; standard_class_names[i].init; i++) {
1390 atom = StdNameToAtom(cx, &standard_class_names[i]);
1391 if (!atom)
1392 return JS_FALSE;
1393 if (idstr == ATOM_TO_STRING(atom)) {
1394 init = standard_class_names[i].init;
1395 break;
1396 }
1397 }
1399 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 for (i = 0; object_prototype_names[i].init; i++) {
1406 atom = StdNameToAtom(cx, &object_prototype_names[i]);
1407 if (!atom)
1408 return JS_FALSE;
1409 if (idstr == ATOM_TO_STRING(atom)) {
1410 init = standard_class_names[i].init;
1411 break;
1412 }
1413 }
1414 }
1415 }
1417 if (init) {
1418 if (!init(cx, obj))
1419 return JS_FALSE;
1420 *resolved = JS_TRUE;
1421 }
1422 return JS_TRUE;
1423 }
1425 static JSBool
1426 AlreadyHasOwnProperty(JSObject *obj, JSAtom *atom)
1427 {
1428 JS_ASSERT(OBJ_IS_NATIVE(obj));
1429 return SCOPE_GET_PROPERTY(OBJ_SCOPE(obj), ATOM_TO_JSID(atom)) != NULL;
1430 }
1432 JS_PUBLIC_API(JSBool)
1433 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1434 {
1435 JSRuntime *rt;
1436 JSAtom *atom;
1437 uintN i;
1439 CHECK_REQUEST(cx);
1440 rt = cx->runtime;
1442 #if JS_HAS_UNDEFINED
1443 /* Check whether we need to bind 'undefined' and define it if so. */
1444 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1445 if (!AlreadyHasOwnProperty(obj, atom) &&
1446 !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1447 NULL, NULL, JSPROP_PERMANENT, NULL)) {
1448 return JS_FALSE;
1449 }
1450 #endif
1452 /* Initialize any classes that have not been resolved yet. */
1453 for (i = 0; standard_class_atoms[i].init; i++) {
1454 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1455 if (!AlreadyHasOwnProperty(obj, atom) &&
1456 !standard_class_atoms[i].init(cx, obj)) {
1457 return JS_FALSE;
1458 }
1459 }
1461 return JS_TRUE;
1462 }
1464 static JSIdArray *
1465 AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1466 {
1467 jsint i, length;
1469 i = *ip;
1470 length = ida->length;
1471 if (i >= length) {
1472 ida = js_SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
1473 if (!ida)
1474 return NULL;
1475 JS_ASSERT(i < ida->length);
1476 }
1477 ida->vector[i] = ATOM_TO_JSID(atom);
1478 *ip = i + 1;
1479 return ida;
1480 }
1482 static JSIdArray *
1483 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
1484 jsint *ip, JSBool *foundp)
1485 {
1486 *foundp = AlreadyHasOwnProperty(obj, atom);
1487 if (*foundp)
1488 ida = AddAtomToArray(cx, atom, ida, ip);
1489 return ida;
1490 }
1492 JS_PUBLIC_API(JSIdArray *)
1493 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
1494 JSIdArray *ida)
1495 {
1496 JSRuntime *rt;
1497 jsint i, j, k;
1498 JSAtom *atom;
1499 JSBool found;
1500 JSObjectOp init;
1502 CHECK_REQUEST(cx);
1503 rt = cx->runtime;
1504 if (ida) {
1505 i = ida->length;
1506 } else {
1507 ida = js_NewIdArray(cx, 8);
1508 if (!ida)
1509 return NULL;
1510 i = 0;
1511 }
1513 #if JS_HAS_UNDEFINED
1514 /* Check whether 'undefined' has been resolved and enumerate it if so. */
1515 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1516 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1517 if (!ida)
1518 return NULL;
1519 #endif
1521 /* Enumerate only classes that *have* been resolved. */
1522 for (j = 0; standard_class_atoms[j].init; j++) {
1523 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
1524 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1525 if (!ida)
1526 return NULL;
1528 if (found) {
1529 init = standard_class_atoms[j].init;
1531 for (k = 0; standard_class_names[k].init; k++) {
1532 if (standard_class_names[k].init == init) {
1533 atom = StdNameToAtom(cx, &standard_class_names[k]);
1534 ida = AddAtomToArray(cx, atom, ida, &i);
1535 if (!ida)
1536 return NULL;
1537 }
1538 }
1540 if (init == js_InitObjectClass) {
1541 for (k = 0; object_prototype_names[k].init; k++) {
1542 atom = StdNameToAtom(cx, &object_prototype_names[k]);
1543 ida = AddAtomToArray(cx, atom, ida, &i);
1544 if (!ida)
1545 return NULL;
1546 }
1547 }
1548 }
1549 }
1551 /* Trim to exact length via js_SetIdArrayLength. */
1552 return js_SetIdArrayLength(cx, ida, i);
1553 }
1555 #undef ATOM_OFFSET
1556 #undef OFFSET_TO_ATOM
1558 JS_PUBLIC_API(JSObject *)
1559 JS_GetScopeChain(JSContext *cx)
1560 {
1561 return cx->fp ? cx->fp->scopeChain : NULL;
1562 }
1564 JS_PUBLIC_API(void *)
1565 JS_malloc(JSContext *cx, size_t nbytes)
1566 {
1567 void *p;
1569 JS_ASSERT(nbytes != 0);
1570 if (nbytes == 0)
1571 nbytes = 1;
1572 cx->runtime->gcMallocBytes += nbytes;
1573 p = malloc(nbytes);
1574 if (!p)
1575 JS_ReportOutOfMemory(cx);
1576 return p;
1577 }
1579 JS_PUBLIC_API(void *)
1580 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1581 {
1582 p = realloc(p, nbytes);
1583 if (!p)
1584 JS_ReportOutOfMemory(cx);
1585 return p;
1586 }
1588 JS_PUBLIC_API(void)
1589 JS_free(JSContext *cx, void *p)
1590 {
1591 if (p)
1592 free(p);
1593 }
1595 JS_PUBLIC_API(char *)
1596 JS_strdup(JSContext *cx, const char *s)
1597 {
1598 size_t n;
1599 void *p;
1601 n = strlen(s) + 1;
1602 p = JS_malloc(cx, n);
1603 if (!p)
1604 return NULL;
1605 return (char *)memcpy(p, s, n);
1606 }
1608 JS_PUBLIC_API(jsdouble *)
1609 JS_NewDouble(JSContext *cx, jsdouble d)
1610 {
1611 CHECK_REQUEST(cx);
1612 return js_NewDouble(cx, d, 0);
1613 }
1615 JS_PUBLIC_API(JSBool)
1616 JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
1617 {
1618 CHECK_REQUEST(cx);
1619 return js_NewDoubleValue(cx, d, rval);
1620 }
1622 JS_PUBLIC_API(JSBool)
1623 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
1624 {
1625 CHECK_REQUEST(cx);
1626 return js_NewNumberValue(cx, d, rval);
1627 }
1629 #undef JS_AddRoot
1630 JS_PUBLIC_API(JSBool)
1631 JS_AddRoot(JSContext *cx, void *rp)
1632 {
1633 CHECK_REQUEST(cx);
1634 return js_AddRoot(cx, rp, NULL);
1635 }
1637 JS_PUBLIC_API(JSBool)
1638 JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name)
1639 {
1640 return js_AddRootRT(rt, rp, name);
1641 }
1643 JS_PUBLIC_API(JSBool)
1644 JS_RemoveRoot(JSContext *cx, void *rp)
1645 {
1646 CHECK_REQUEST(cx);
1647 return js_RemoveRoot(cx->runtime, rp);
1648 }
1650 JS_PUBLIC_API(JSBool)
1651 JS_RemoveRootRT(JSRuntime *rt, void *rp)
1652 {
1653 return js_RemoveRoot(rt, rp);
1654 }
1656 JS_PUBLIC_API(JSBool)
1657 JS_AddNamedRoot(JSContext *cx, void *rp, const char *name)
1658 {
1659 CHECK_REQUEST(cx);
1660 return js_AddRoot(cx, rp, name);
1661 }
1663 JS_PUBLIC_API(void)
1664 JS_ClearNewbornRoots(JSContext *cx)
1665 {
1666 uintN i;
1668 for (i = 0; i < GCX_NTYPES; i++)
1669 cx->newborn[i] = NULL;
1670 cx->lastAtom = NULL;
1671 cx->lastInternalResult = JSVAL_NULL;
1672 }
1674 JS_PUBLIC_API(JSBool)
1675 JS_EnterLocalRootScope(JSContext *cx)
1676 {
1677 CHECK_REQUEST(cx);
1678 return js_EnterLocalRootScope(cx);
1679 }
1681 JS_PUBLIC_API(void)
1682 JS_LeaveLocalRootScope(JSContext *cx)
1683 {
1684 CHECK_REQUEST(cx);
1685 js_LeaveLocalRootScope(cx);
1686 }
1688 JS_PUBLIC_API(void)
1689 JS_ForgetLocalRoot(JSContext *cx, void *thing)
1690 {
1691 CHECK_REQUEST(cx);
1692 js_ForgetLocalRoot(cx, (jsval) thing);
1693 }
1695 #include "jshash.h" /* Added by JSIFY */
1697 #ifdef DEBUG
1699 typedef struct NamedRootDumpArgs {
1700 void (*dump)(const char *name, void *rp, void *data);
1701 void *data;
1702 } NamedRootDumpArgs;
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;
1711 if (rhe->name)
1712 args->dump(rhe->name, rhe->root, args->data);
1713 return JS_DHASH_NEXT;
1714 }
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;
1723 args.dump = dump;
1724 args.data = data;
1725 JS_DHashTableEnumerate(&rt->gcRootsHash, js_named_root_dumper, &args);
1726 }
1728 #endif /* DEBUG */
1730 typedef struct GCRootMapArgs {
1731 JSGCRootMapFun map;
1732 void *data;
1733 } GCRootMapArgs;
1735 JS_STATIC_DLL_CALLBACK(JSDHashOperator)
1736 js_gcroot_mapper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
1737 void *arg)
1738 {
1739 GCRootMapArgs *args = (GCRootMapArgs *) arg;
1740 JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
1741 intN mapflags;
1742 JSDHashOperator op;
1744 mapflags = args->map(rhe->root, rhe->name, args->data);
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 op = JS_DHASH_NEXT;
1752 if (mapflags & JS_MAP_GCROOT_STOP)
1753 op |= JS_DHASH_STOP;
1754 if (mapflags & JS_MAP_GCROOT_REMOVE)
1755 op |= JS_DHASH_REMOVE;
1756 #endif
1758 return op;
1759 }
1761 JS_PUBLIC_API(uint32)
1762 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
1763 {
1764 GCRootMapArgs args;
1765 uint32 rv;
1767 args.map = map;
1768 args.data = data;
1769 JS_LOCK_GC(rt);
1770 rv = JS_DHashTableEnumerate(&rt->gcRootsHash, js_gcroot_mapper, &args);
1771 JS_UNLOCK_GC(rt);
1772 return rv;
1773 }
1775 JS_PUBLIC_API(JSBool)
1776 JS_LockGCThing(JSContext *cx, void *thing)
1777 {
1778 JSBool ok;
1780 CHECK_REQUEST(cx);
1781 ok = js_LockGCThing(cx, thing);
1782 if (!ok)
1783 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_LOCK);
1784 return ok;
1785 }
1787 JS_PUBLIC_API(JSBool)
1788 JS_LockGCThingRT(JSRuntime *rt, void *thing)
1789 {
1790 return js_LockGCThingRT(rt, thing);
1791 }
1793 JS_PUBLIC_API(JSBool)
1794 JS_UnlockGCThing(JSContext *cx, void *thing)
1795 {
1796 JSBool ok;
1798 CHECK_REQUEST(cx);
1799 ok = js_UnlockGCThingRT(cx->runtime, thing);
1800 if (!ok)
1801 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_UNLOCK);
1802 return ok;
1803 }
1805 JS_PUBLIC_API(JSBool)
1806 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
1807 {
1808 return js_UnlockGCThingRT(rt, thing);
1809 }
1811 JS_PUBLIC_API(void)
1812 JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg)
1813 {
1814 JS_ASSERT(cx->runtime->gcLevel > 0);
1815 #ifdef JS_THREADSAFE
1816 JS_ASSERT(cx->runtime->gcThread == js_CurrentThreadId());
1817 #endif
1819 GC_MARK(cx, thing, name, arg);
1820 }
1822 JS_PUBLIC_API(void)
1823 JS_GC(JSContext *cx)
1824 {
1825 /* Don't nuke active arenas if executing or compiling. */
1826 if (cx->stackPool.current == &cx->stackPool.first)
1827 JS_FinishArenaPool(&cx->stackPool);
1828 if (cx->tempPool.current == &cx->tempPool.first)
1829 JS_FinishArenaPool(&cx->tempPool);
1830 js_ForceGC(cx, 0);
1831 }
1833 JS_PUBLIC_API(void)
1834 JS_MaybeGC(JSContext *cx)
1835 {
1836 #ifdef WAY_TOO_MUCH_GC
1837 JS_GC(cx);
1838 #else
1839 JSRuntime *rt;
1840 uint32 bytes, lastBytes;
1842 rt = cx->runtime;
1843 bytes = rt->gcBytes;
1844 lastBytes = rt->gcLastBytes;
1845 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 JS_GC(cx);
1853 }
1854 #endif
1855 }
1857 JS_PUBLIC_API(JSGCCallback)
1858 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
1859 {
1860 return JS_SetGCCallbackRT(cx->runtime, cb);
1861 }
1863 JS_PUBLIC_API(JSGCCallback)
1864 JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
1865 {
1866 JSGCCallback oldcb;
1868 oldcb = rt->gcCallback;
1869 rt->gcCallback = cb;
1870 return oldcb;
1871 }
1873 JS_PUBLIC_API(JSBool)
1874 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
1875 {
1876 JS_ASSERT(thing);
1877 return js_IsAboutToBeFinalized(cx, thing);
1878 }
1880 JS_PUBLIC_API(void)
1881 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
1882 {
1883 switch (key) {
1884 case JSGC_MAX_BYTES:
1885 rt->gcMaxBytes = value;
1886 break;
1887 case JSGC_MAX_MALLOC_BYTES:
1888 rt->gcMaxMallocBytes = value;
1889 break;
1890 }
1891 }
1893 JS_PUBLIC_API(intN)
1894 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
1895 {
1896 return js_ChangeExternalStringFinalizer(NULL, finalizer);
1897 }
1899 JS_PUBLIC_API(intN)
1900 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
1901 {
1902 return js_ChangeExternalStringFinalizer(finalizer, NULL);
1903 }
1905 JS_PUBLIC_API(JSString *)
1906 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
1907 {
1908 JSString *str;
1910 CHECK_REQUEST(cx);
1911 JS_ASSERT(GCX_EXTERNAL_STRING <= type && type < (intN) GCX_NTYPES);
1913 str = (JSString *) js_NewGCThing(cx, (uintN) type, sizeof(JSString));
1914 if (!str)
1915 return NULL;
1916 str->length = length;
1917 str->chars = chars;
1918 return str;
1919 }
1921 JS_PUBLIC_API(intN)
1922 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
1923 {
1924 uint8 type = (uint8) (*js_GetGCThingFlags(str) & GCF_TYPEMASK);
1926 if (type >= GCX_EXTERNAL_STRING)
1927 return (intN)type;
1928 JS_ASSERT(type == GCX_STRING || type == GCX_MUTABLE_STRING);
1929 return -1;
1930 }
1932 JS_PUBLIC_API(void)
1933 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
1934 {
1935 #if JS_STACK_GROWTH_DIRECTION > 0
1936 if (limitAddr == 0)
1937 limitAddr = (jsuword)-1;
1938 #endif
1939 cx->stackLimit = limitAddr;
1940 }
1942 /************************************************************************/
1944 JS_PUBLIC_API(void)
1945 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
1946 {
1947 JS_free(cx, ida);
1948 }
1950 JS_PUBLIC_API(JSBool)
1951 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
1952 {
1953 JSAtom *atom;
1955 CHECK_REQUEST(cx);
1956 if (JSVAL_IS_INT(v)) {
1957 *idp = v;
1958 } else {
1959 atom = js_ValueToStringAtom(cx, v);
1960 if (!atom)
1961 return JS_FALSE;
1962 *idp = ATOM_TO_JSID(atom);
1963 }
1964 return JS_TRUE;
1965 }
1967 JS_PUBLIC_API(JSBool)
1968 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
1969 {
1970 CHECK_REQUEST(cx);
1971 *vp = ID_TO_VALUE(id);
1972 return JS_TRUE;
1973 }
1975 JS_PUBLIC_API(JSBool)
1976 JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
1977 {
1978 return JS_TRUE;
1979 }
1981 JS_PUBLIC_API(JSBool)
1982 JS_EnumerateStub(JSContext *cx, JSObject *obj)
1983 {
1984 return JS_TRUE;
1985 }
1987 JS_PUBLIC_API(JSBool)
1988 JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id)
1989 {
1990 return JS_TRUE;
1991 }
1993 JS_PUBLIC_API(JSBool)
1994 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
1995 {
1996 #if JS_BUG_EAGER_TOSTRING
1997 if (type == JSTYPE_STRING)
1998 return JS_TRUE;
1999 #endif
2000 js_TryValueOf(cx, obj, type, vp);
2001 return JS_TRUE;
2002 }
2004 JS_PUBLIC_API(void)
2005 JS_FinalizeStub(JSContext *cx, JSObject *obj)
2006 {
2007 }
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 {
2015 JSAtom *atom;
2016 JSObject *proto, *ctor;
2017 JSTempValueRooter tvr;
2018 jsval cval, rval;
2019 JSBool named;
2020 JSFunction *fun;
2022 CHECK_REQUEST(cx);
2023 atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
2024 if (!atom)
2025 return NULL;
2027 /* Create a prototype object for this class. */
2028 proto = js_NewObject(cx, clasp, parent_proto, obj);
2029 if (!proto)
2030 return NULL;
2032 /* After this point, control must exit via label bad or out. */
2033 JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(proto), &tvr);
2035 if (!constructor) {
2036 /* Lacking a constructor, name the prototype (e.g., Math). */
2037 named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
2038 OBJECT_TO_JSVAL(proto),
2039 NULL, NULL, 0, NULL);
2040 if (!named)
2041 goto bad;
2042 ctor = proto;
2043 } else {
2044 /* Define the constructor function in obj's scope. */
2045 fun = js_DefineFunction(cx, obj, atom, constructor, nargs, 0);
2046 named = (fun != NULL);
2047 if (!fun)
2048 goto bad;
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 fun->clasp = clasp;
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 ctor = fun->object;
2064 if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) {
2065 cval = OBJECT_TO_JSVAL(ctor);
2066 if (!js_InternalConstruct(cx, proto, cval, 0, NULL, &rval))
2067 goto bad;
2068 if (!JSVAL_IS_PRIMITIVE(rval) && JSVAL_TO_OBJECT(rval) != proto)
2069 proto = JSVAL_TO_OBJECT(rval);
2070 }
2072 /* Connect constructor and prototype by named properties. */
2073 if (!js_SetClassPrototype(cx, ctor, proto,
2074 JSPROP_READONLY | JSPROP_PERMANENT)) {
2075 goto bad;
2076 }
2078 /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
2079 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 OBJ_SET_PROTO(cx, ctor, proto);
2085 }
2086 }
2088 /* Add properties and methods to the prototype and the constructor. */
2089 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 }
2096 out:
2097 JS_POP_TEMP_ROOT(cx, &tvr);
2098 return proto;
2100 bad:
2101 if (named)
2102 (void) OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &rval);
2103 proto = NULL;
2104 goto out;
2105 }
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 {
2118 return LOCKED_OBJ_GET_CLASS(obj);
2119 }
2120 #endif
2122 JS_PUBLIC_API(JSBool)
2123 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2124 {
2125 JSFunction *fun;
2127 CHECK_REQUEST(cx);
2128 if (OBJ_GET_CLASS(cx, obj) == clasp)
2129 return JS_TRUE;
2130 if (argv) {
2131 fun = js_ValueToFunction(cx, &argv[-2], 0);
2132 if (fun) {
2133 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 return JS_FALSE;
2140 }
2142 JS_PUBLIC_API(JSBool)
2143 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
2144 {
2145 return js_HasInstance(cx, obj, v, bp);
2146 }
2148 JS_PUBLIC_API(void *)
2149 JS_GetPrivate(JSContext *cx, JSObject *obj)
2150 {
2151 jsval v;
2153 JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2154 v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
2155 if (!JSVAL_IS_INT(v))
2156 return NULL;
2157 return JSVAL_TO_PRIVATE(v);
2158 }
2160 JS_PUBLIC_API(JSBool)
2161 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2162 {
2163 JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2164 OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(data));
2165 return JS_TRUE;
2166 }
2168 JS_PUBLIC_API(void *)
2169 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp,
2170 jsval *argv)
2171 {
2172 if (!JS_InstanceOf(cx, obj, clasp, argv))
2173 return NULL;
2174 return JS_GetPrivate(cx, obj);
2175 }
2177 JS_PUBLIC_API(JSObject *)
2178 JS_GetPrototype(JSContext *cx, JSObject *obj)
2179 {
2180 JSObject *proto;
2182 CHECK_REQUEST(cx);
2183 proto = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PROTO));
2185 /* Beware ref to dead object (we may be called from obj's finalizer). */
2186 return proto && proto->map ? proto : NULL;
2187 }
2189 JS_PUBLIC_API(JSBool)
2190 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
2191 {
2192 CHECK_REQUEST(cx);
2193 if (obj->map->ops->setProto)
2194 return obj->map->ops->setProto(cx, obj, JSSLOT_PROTO, proto);
2195 OBJ_SET_SLOT(cx, obj, JSSLOT_PROTO, OBJECT_TO_JSVAL(proto));
2196 return JS_TRUE;
2197 }
2199 JS_PUBLIC_API(JSObject *)
2200 JS_GetParent(JSContext *cx, JSObject *obj)
2201 {
2202 JSObject *parent;
2204 parent = JSVAL_TO_OBJECT(GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PARENT));
2206 /* Beware ref to dead object (we may be called from obj's finalizer). */
2207 return parent && parent->map ? parent : NULL;
2208 }
2210 JS_PUBLIC_API(JSBool)
2211 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
2212 {
2213 CHECK_REQUEST(cx);
2214 if (obj->map->ops->setParent)
2215 return obj->map->ops->setParent(cx, obj, JSSLOT_PARENT, parent);
2216 OBJ_SET_SLOT(cx, obj, JSSLOT_PARENT, OBJECT_TO_JSVAL(parent));
2217 return JS_TRUE;
2218 }
2220 JS_PUBLIC_API(JSObject *)
2221 JS_GetConstructor(JSContext *cx, JSObject *proto)
2222 {
2223 jsval cval;
2225 CHECK_REQUEST(cx);
2226 if (!OBJ_GET_PROPERTY(cx, proto,
2227 ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
2228 &cval)) {
2229 return NULL;
2230 }
2231 if (!JSVAL_IS_FUNCTION(cx, cval)) {
2232 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
2233 OBJ_GET_CLASS(cx, proto)->name);
2234 return NULL;
2235 }
2236 return JSVAL_TO_OBJECT(cval);
2237 }
2239 JS_PUBLIC_API(JSBool)
2240 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
2241 {
2242 JS_ASSERT(((jsid)obj & JSID_TAGMASK) == 0);
2243 *idp = OBJECT_TO_JSID(obj);
2244 return JS_TRUE;
2245 }
2247 JS_PUBLIC_API(JSObject *)
2248 JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
2249 {
2250 CHECK_REQUEST(cx);
2251 if (!clasp)
2252 clasp = &js_ObjectClass; /* default class is Object */
2253 return js_NewObject(cx, clasp, proto, parent);
2254 }
2256 JS_PUBLIC_API(JSBool)
2257 JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
2258 {
2259 JSScope *scope;
2260 JSIdArray *ida;
2261 uint32 nslots;
2262 jsval v, *vp, *end;
2264 if (!OBJ_IS_NATIVE(obj)) {
2265 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2266 JSMSG_CANT_SEAL_OBJECT,
2267 OBJ_GET_CLASS(cx, obj)->name);
2268 return JS_FALSE;
2269 }
2271 scope = OBJ_SCOPE(obj);
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
2283 /* Nothing to do if obj's scope is already sealed. */
2284 if (SCOPE_IS_SEALED(scope))
2285 return JS_TRUE;
2287 /* XXX Enumerate lazy properties now, as they can't be added later. */
2288 ida = JS_Enumerate(cx, obj);
2289 if (!ida)
2290 return JS_FALSE;
2291 JS_DestroyIdArray(cx, ida);
2293 /* Ensure that obj has its own, mutable scope, and seal that scope. */
2294 JS_LOCK_OBJ(cx, obj);
2295 scope = js_GetMutableScope(cx, obj);
2296 if (scope)
2297 SCOPE_SET_SEALED(scope);
2298 JS_UNLOCK_SCOPE(cx, scope);
2299 if (!scope)
2300 return JS_FALSE;
2302 /* If we are not sealing an entire object graph, we're done. */
2303 if (!deep)
2304 return JS_TRUE;
2306 /* Walk obj->slots and if any value is a non-null object, seal it. */
2307 nslots = JS_MIN(scope->map.freeslot, scope->map.nslots);
2308 for (vp = obj->slots, end = vp + nslots; vp < end; vp++) {
2309 v = *vp;
2310 if (JSVAL_IS_PRIMITIVE(v))
2311 continue;
2312 if (!JS_SealObject(cx, JSVAL_TO_OBJECT(v), deep))
2313 return JS_FALSE;
2314 }
2315 return JS_TRUE;
2316 }
2318 JS_PUBLIC_API(JSObject *)
2319 JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
2320 JSObject *parent)
2321 {
2322 CHECK_REQUEST(cx);
2323 if (!clasp)
2324 clasp = &js_ObjectClass; /* default class is Object */
2325 return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
2326 }
2328 JS_PUBLIC_API(JSObject *)
2329 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto,
2330 JSObject *parent, uintN argc, jsval *argv)
2331 {
2332 CHECK_REQUEST(cx);
2333 if (!clasp)
2334 clasp = &js_ObjectClass; /* default class is Object */
2335 return js_ConstructObject(cx, clasp, proto, parent, argc, argv);
2336 }
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 {
2343 jsid id;
2344 JSAtom *atom;
2346 if (attrs & JSPROP_INDEX) {
2347 id = INT_TO_JSID(JS_PTR_TO_INT32(name));
2348 atom = NULL;
2349 attrs &= ~JSPROP_INDEX;
2350 } else {
2351 atom = js_Atomize(cx, name, strlen(name), 0);
2352 if (!atom)
2353 return JS_FALSE;
2354 id = ATOM_TO_JSID(atom);
2355 }
2356 if (flags != 0 && OBJ_IS_NATIVE(obj)) {
2357 return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
2358 attrs, flags, tinyid, NULL);
2359 }
2360 return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs,
2361 NULL);
2362 }
2364 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
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 {
2372 JSAtom *atom;
2374 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2375 if (!atom)
2376 return JS_FALSE;
2377 if (flags != 0 && OBJ_IS_NATIVE(obj)) {
2378 return js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
2379 getter, setter, attrs, flags, tinyid,
2380 NULL);
2381 }
2382 return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), value,
2383 getter, setter, attrs, NULL);
2384 }
2386 JS_PUBLIC_API(JSObject *)
2387 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
2388 JSObject *proto, uintN attrs)
2389 {
2390 JSObject *nobj;
2392 CHECK_REQUEST(cx);
2393 if (!clasp)
2394 clasp = &js_ObjectClass; /* default class is Object */
2395 nobj = js_NewObject(cx, clasp, proto, obj);
2396 if (!nobj)
2397 return NULL;
2398 if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs,
2399 0, 0)) {
2400 cx->newborn[GCX_OBJECT] = NULL;
2401 return NULL;
2402 }
2403 return nobj;
2404 }
2406 JS_PUBLIC_API(JSBool)
2407 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
2408 {
2409 JSBool ok;
2410 jsval value;
2411 uintN flags;
2413 CHECK_REQUEST(cx);
2414 for (ok = JS_TRUE; cds->name; cds++) {
2415 ok = js_NewNumberValue(cx, cds->dval, &value);
2416 if (!ok)
2417 break;
2418 flags = cds->flags;
2419 if (!flags)
2420 flags = JSPROP_READONLY | JSPROP_PERMANENT;
2421 ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, flags, 0, 0);
2422 if (!ok)
2423 break;
2424 }
2425 return ok;
2426 }
2428 JS_PUBLIC_API(JSBool)
2429 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
2430 {
2431 JSBool ok;
2433 CHECK_REQUEST(cx);
2434 for (ok = JS_TRUE; ps->name; ps++) {
2435 ok = DefineProperty(cx, obj, ps->name, JSVAL_VOID,
2436 ps->getter, ps->setter, ps->flags,
2437 SPROP_HAS_SHORTID, ps->tinyid);
2438 if (!ok)
2439 break;
2440 }
2441 return ok;
2442 }
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 {
2448 CHECK_REQUEST(cx);
2449 return DefineProperty(cx, obj, name, value, getter, setter, attrs, 0, 0);
2450 }
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 {
2458 CHECK_REQUEST(cx);
2459 return DefineProperty(cx, obj, name, value, getter, setter, attrs,
2460 SPROP_HAS_SHORTID, tinyid);
2461 }
2463 static JSBool
2464 LookupProperty(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
2465 JSProperty **propp)
2466 {
2467 JSAtom *atom;
2469 atom = js_Atomize(cx, name, strlen(name), 0);
2470 if (!atom)
2471 return JS_FALSE;
2472 return OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), objp, propp);
2473 }
2475 static JSBool
2476 LookupUCProperty(JSContext *cx, JSObject *obj,
2477 const jschar *name, size_t namelen,
2478 JSObject **objp, JSProperty **propp)
2479 {
2480 JSAtom *atom;
2482 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2483 if (!atom)
2484 return JS_FALSE;
2485 return OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), objp, propp);
2486 }
2488 JS_PUBLIC_API(JSBool)
2489 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
2490 const char *alias)
2491 {
2492 JSObject *obj2;
2493 JSProperty *prop;
2494 JSAtom *atom;
2495 JSBool ok;
2496 JSScopeProperty *sprop;
2498 CHECK_REQUEST(cx);
2499 if (!LookupProperty(cx, obj, name, &obj2, &prop))
2500 return JS_FALSE;
2501 if (!prop) {
2502 js_ReportIsNotDefined(cx, name);
2503 return JS_FALSE;
2504 }
2505 if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
2506 OBJ_DROP_PROPERTY(cx, obj2, prop);
2507 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
2508 alias, name, OBJ_GET_CLASS(cx, obj2)->name);
2509 return JS_FALSE;
2510 }
2511 atom = js_Atomize(cx, alias, strlen(alias), 0);
2512 if (!atom) {
2513 ok = JS_FALSE;
2514 } else {
2515 sprop = (JSScopeProperty *)prop;
2516 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 OBJ_DROP_PROPERTY(cx, obj, prop);
2523 return ok;
2524 }
2526 static jsval
2527 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop)
2528 {
2529 JSScopeProperty *sprop;
2530 jsval rval;
2532 if (!prop) {
2533 /* XXX bad API: no way to tell "not defined" from "void value" */
2534 return JSVAL_VOID;
2535 }
2536 if (OBJ_IS_NATIVE(obj2)) {
2537 /* Peek at the native property's slot value, without doing a Get. */
2538 sprop = (JSScopeProperty *)prop;
2539 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 rval = JSVAL_TRUE;
2545 }
2546 OBJ_DROP_PROPERTY(cx, obj2, prop);
2547 return rval;
2548 }
2550 static JSBool
2551 GetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
2552 uintN *attrsp, JSBool *foundp,
2553 JSPropertyOp *getterp, JSPropertyOp *setterp)
2554 {
2555 JSObject *obj2;
2556 JSProperty *prop;
2557 JSBool ok;
2559 if (!atom)
2560 return JS_FALSE;
2561 if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop))
2562 return JS_FALSE;
2564 if (!prop || obj != obj2) {
2565 *attrsp = 0;
2566 *foundp = JS_FALSE;
2567 if (getterp)
2568 *getterp = NULL;
2569 if (setterp)
2570 *setterp = NULL;
2571 if (prop)
2572 OBJ_DROP_PROPERTY(cx, obj2, prop);
2573 return JS_TRUE;
2574 }
2576 *foundp = JS_TRUE;
2577 ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, attrsp);
2578 if (ok && OBJ_IS_NATIVE(obj)) {
2579 JSScopeProperty *sprop = (JSScopeProperty *) prop;
2581 if (getterp)
2582 *getterp = sprop->getter;
2583 if (setterp)
2584 *setterp = sprop->setter;
2585 }
2586 OBJ_DROP_PROPERTY(cx, obj, prop);
2587 return ok;
2588 }
2590 static JSBool
2591 SetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
2592 uintN attrs, JSBool *foundp)
2593 {
2594 JSObject *obj2;
2595 JSProperty *prop;
2596 JSBool ok;
2598 if (!atom)
2599 return JS_FALSE;
2600 if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop))
2601 return JS_FALSE;
2602 if (!prop || obj != obj2) {
2603 *foundp = JS_FALSE;
2604 if (prop)
2605 OBJ_DROP_PROPERTY(cx, obj2, prop);
2606 return JS_TRUE;
2607 }
2609 *foundp = JS_TRUE;
2610 ok = OBJ_SET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs);
2611 OBJ_DROP_PROPERTY(cx, obj, prop);
2612 return ok;
2613 }
2615 JS_PUBLIC_API(JSBool)
2616 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
2617 uintN *attrsp, JSBool *foundp)
2618 {
2619 CHECK_REQUEST(cx);
2620 return GetPropertyAttributes(cx, obj,
2621 js_Atomize(cx, name, strlen(name), 0),
2622 attrsp, foundp, NULL, NULL);
2623 }
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 {
2632 CHECK_REQUEST(cx);
2633 return GetPropertyAttributes(cx, obj,
2634 js_Atomize(cx, name, strlen(name), 0),
2635 attrsp, foundp, getterp, setterp);
2636 }
2638 JS_PUBLIC_API(JSBool)
2639 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
2640 uintN attrs, JSBool *foundp)
2641 {
2642 CHECK_REQUEST(cx);
2643 return SetPropertyAttributes(cx, obj,
2644 js_Atomize(cx, name, strlen(name), 0),
2645 attrs, foundp);
2646 }
2648 JS_PUBLIC_API(JSBool)
2649 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
2650 {
2651 JSBool ok;
2652 JSObject *obj2;
2653 JSProperty *prop;
2655 CHECK_REQUEST(cx);
2656 ok = LookupProperty(cx, obj, name, &obj2, &prop);
2657 if (ok) {
2658 *foundp = (prop != NULL);
2659 if (prop)
2660 OBJ_DROP_PROPERTY(cx, obj2, prop);
2661 }
2662 return ok;
2663 }
2665 JS_PUBLIC_API(JSBool)
2666 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2667 {
2668 JSBool ok;
2669 JSObject *obj2;
2670 JSProperty *prop;
2672 CHECK_REQUEST(cx);
2673 ok = LookupProperty(cx, obj, name, &obj2, &prop);
2674 if (ok)
2675 *vp = LookupResult(cx, obj, obj2, prop);
2676 return ok;
2677 }
2679 JS_PUBLIC_API(JSBool)
2680 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name,
2681 uintN flags, jsval *vp)
2682 {
2683 JSAtom *atom;
2684 JSBool ok;
2685 JSObject *obj2;
2686 JSProperty *prop;
2688 CHECK_REQUEST(cx);
2689 atom = js_Atomize(cx, name, strlen(name), 0);
2690 if (!atom)
2691 return JS_FALSE;
2692 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 if (ok)
2697 *vp = LookupResult(cx, obj, obj2, prop);
2698 return ok;
2699 }
2701 JS_PUBLIC_API(JSBool)
2702 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2703 {
2704 JSAtom *atom;
2706 CHECK_REQUEST(cx);
2707 atom = js_Atomize(cx, name, strlen(name), 0);
2708 if (!atom)
2709 return JS_FALSE;
2710 return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2711 }
2713 JS_PUBLIC_API(JSBool)
2714 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
2715 jsval *vp)
2716 {
2717 JSAtom *atom;
2718 jsid id;
2720 CHECK_REQUEST(cx);
2721 atom = js_Atomize(cx, name, strlen(name), 0);
2722 if (!atom)
2723 return JS_FALSE;
2724 id = ATOM_TO_JSID(atom);
2726 #if JS_HAS_XML_SUPPORT
2727 if (OBJECT_IS_XML(cx, obj)) {
2728 JSXMLObjectOps *ops;
2730 ops = (JSXMLObjectOps *) obj->map->ops;
2731 obj = ops->getMethod(cx, obj, id, vp);
2732 if (!obj)
2733 return JS_FALSE;
2734 } else
2735 #endif
2736 {
2737 if (!OBJ_GET_PROPERTY(cx, obj, id, vp))
2738 return JS_FALSE;
2739 }
2741 *objp = obj;
2742 return JS_TRUE;
2743 }
2745 JS_PUBLIC_API(JSBool)
2746 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
2747 {
2748 JSAtom *atom;
2750 CHECK_REQUEST(cx);
2751 atom = js_Atomize(cx, name, strlen(name), 0);
2752 if (!atom)
2753 return JS_FALSE;
2754 return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2755 }
2757 JS_PUBLIC_API(JSBool)
2758 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
2759 {
2760 jsval junk;
2762 CHECK_REQUEST(cx);
2763 return JS_DeleteProperty2(cx, obj, name, &junk);
2764 }
2766 JS_PUBLIC_API(JSBool)
2767 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name,
2768 jsval *rval)
2769 {
2770 JSAtom *atom;
2772 CHECK_REQUEST(cx);
2773 atom = js_Atomize(cx, name, strlen(name), 0);
2774 if (!atom)
2775 return JS_FALSE;
2776 return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
2777 }
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 {
2785 CHECK_REQUEST(cx);
2786 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
2787 attrs, 0, 0);
2788 }
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 {
2795 CHECK_REQUEST(cx);
2796 return GetPropertyAttributes(cx, obj,
2797 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2798 attrsp, foundp, NULL, NULL);
2799 }
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 {
2808 CHECK_REQUEST(cx);
2809 return GetPropertyAttributes(cx, obj,
2810 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2811 attrsp, foundp, getterp, setterp);
2812 }
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 {
2819 CHECK_REQUEST(cx);
2820 return SetPropertyAttributes(cx, obj,
2821 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
2822 attrs, foundp);
2823 }
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 {
2832 CHECK_REQUEST(cx);
2833 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
2834 attrs, SPROP_HAS_SHORTID, tinyid);
2835 }
2837 JS_PUBLIC_API(JSBool)
2838 JS_HasUCProperty(JSContext *cx, JSObject *obj,
2839 const jschar *name, size_t namelen,
2840 JSBool *vp)
2841 {
2842 JSBool ok;
2843 JSObject *obj2;
2844 JSProperty *prop;
2846 CHECK_REQUEST(cx);
2847 ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop);
2848 if (ok) {
2849 *vp = (prop != NULL);
2850 if (prop)
2851 OBJ_DROP_PROPERTY(cx, obj2, prop);
2852 }
2853 return ok;
2854 }
2856 JS_PUBLIC_API(JSBool)
2857 JS_LookupUCProperty(JSContext *cx, JSObject *obj,
2858 const jschar *name, size_t namelen,
2859 jsval *vp)
2860 {
2861 JSBool ok;
2862 JSObject *obj2;
2863 JSProperty *prop;
2865 CHECK_REQUEST(cx);
2866 ok = LookupUCProperty(cx, obj, name, namelen, &obj2, &prop);
2867 if (ok)
2868 *vp = LookupResult(cx, obj, obj2, prop);
2869 return ok;
2870 }
2872 JS_PUBLIC_API(JSBool)
2873 JS_GetUCProperty(JSContext *cx, JSObject *obj,
2874 const jschar *name, size_t namelen,
2875 jsval *vp)
2876 {
2877 JSAtom *atom;
2879 CHECK_REQUEST(cx);
2880 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2881 if (!atom)
2882 return JS_FALSE;
2883 return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2884 }
2886 JS_PUBLIC_API(JSBool)
2887 JS_SetUCProperty(JSContext *cx, JSObject *obj,
2888 const jschar *name, size_t namelen,
2889 jsval *vp)
2890 {
2891 JSAtom *atom;
2893 CHECK_REQUEST(cx);
2894 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2895 if (!atom)
2896 return JS_FALSE;
2897 return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
2898 }
2900 JS_PUBLIC_API(JSBool)
2901 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
2902 const jschar *name, size_t namelen,
2903 jsval *rval)
2904 {
2905 JSAtom *atom;
2907 CHECK_REQUEST(cx);
2908 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
2909 if (!atom)
2910 return JS_FALSE;
2911 return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
2912 }
2914 JS_PUBLIC_API(JSObject *)
2915 JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
2916 {
2917 CHECK_REQUEST(cx);
2918 /* NB: jsuint cast does ToUint32. */
2919 return js_NewArrayObject(cx, (jsuint)length, vector);
2920 }
2922 JS_PUBLIC_API(JSBool)
2923 JS_IsArrayObject(JSContext *cx, JSObject *obj)
2924 {
2925 return OBJ_GET_CLASS(cx, obj) == &js_ArrayClass;
2926 }
2928 JS_PUBLIC_API(JSBool)
2929 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
2930 {
2931 CHECK_REQUEST(cx);
2932 return js_GetLengthProperty(cx, obj, lengthp);
2933 }
2935 JS_PUBLIC_API(JSBool)
2936 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
2937 {
2938 CHECK_REQUEST(cx);
2939 return js_SetLengthProperty(cx, obj, length);
2940 }
2942 JS_PUBLIC_API(JSBool)
2943 JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
2944 {
2945 CHECK_REQUEST(cx);
2946 return js_HasLengthProperty(cx, obj, lengthp);
2947 }
2949 JS_PUBLIC_API(JSBool)
2950 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
2951 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
2952 {
2953 CHECK_REQUEST(cx);
2954 return OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(index), value,
2955 getter, setter, attrs, NULL);
2956 }
2958 JS_PUBLIC_API(JSBool)
2959 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
2960 {
2961 JSObject *obj2;
2962 JSProperty *prop;
2963 JSScopeProperty *sprop;
2964 JSBool ok;
2966 CHECK_REQUEST(cx);
2967 if (!LookupProperty(cx, obj, name, &obj2, &prop))
2968 return JS_FALSE;
2969 if (!prop) {
2970 js_ReportIsNotDefined(cx, name);
2971 return JS_FALSE;
2972 }
2973 if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
2974 char numBuf[12];
2975 OBJ_DROP_PROPERTY(cx, obj2, prop);
2976 JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
2977 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
2978 numBuf, name, OBJ_GET_CLASS(cx, obj2)->name);
2979 return JS_FALSE;
2980 }
2981 sprop = (JSScopeProperty *)prop;
2982 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 OBJ_DROP_PROPERTY(cx, obj, prop);
2988 return ok;
2989 }
2991 JS_PUBLIC_API(JSBool)
2992 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
2993 {
2994 JSBool ok;
2995 JSObject *obj2;
2996 JSProperty *prop;
2998 CHECK_REQUEST(cx);
2999 ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSID(index), &obj2, &prop);
3000 if (ok) {
3001 *foundp = (prop != NULL);
3002 if (prop)
3003 OBJ_DROP_PROPERTY(cx, obj2, prop);
3004 }
3005 return ok;
3006 }
3008 JS_PUBLIC_API(JSBool)
3009 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3010 {
3011 JSBool ok;
3012 JSObject *obj2;
3013 JSProperty *prop;
3015 CHECK_REQUEST(cx);
3016 ok = OBJ_LOOKUP_PROPERTY(cx, obj, INT_TO_JSID(index), &obj2, &prop);
3017 if (ok)
3018 *vp = LookupResult(cx, obj, obj2, prop);
3019 return ok;
3020 }
3022 JS_PUBLIC_API(JSBool)
3023 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3024 {
3025 CHECK_REQUEST(cx);
3026 return OBJ_GET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
3027 }
3029 JS_PUBLIC_API(JSBool)
3030 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3031 {
3032 CHECK_REQUEST(cx);
3033 return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
3034 }
3036 JS_PUBLIC_API(JSBool)
3037 JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
3038 {
3039 jsval junk;
3041 CHECK_REQUEST(cx);
3042 return JS_DeleteElement2(cx, obj, index, &junk);
3043 }
3045 JS_PUBLIC_API(JSBool)
3046 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
3047 {
3048 CHECK_REQUEST(cx);
3049 return OBJ_DELETE_PROPERTY(cx, obj, INT_TO_JSID(index), rval);
3050 }
3052 JS_PUBLIC_API(void)
3053 JS_ClearScope(JSContext *cx, JSObject *obj)
3054 {
3055 CHECK_REQUEST(cx);
3057 if (obj->map->ops->clear)
3058 obj->map->ops->clear(cx, obj);
3059 }
3061 JS_PUBLIC_API(JSIdArray *)
3062 JS_Enumerate(JSContext *cx, JSObject *obj)
3063 {
3064 jsint i, n;
3065 jsval iter_state, num_properties;
3066 jsid id;
3067 JSIdArray *ida;
3068 jsval *vector;
3070 CHECK_REQUEST(cx);
3072 ida = NULL;
3073 iter_state = JSVAL_NULL;
3075 /* Get the number of properties to enumerate. */
3076 if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, &num_properties))
3077 goto error;
3078 if (!JSVAL_IS_INT(num_properties)) {
3079 JS_ASSERT(0);
3080 goto error;
3081 }
3083 /* Grow as needed if we don't know the exact amount ahead of time. */
3084 n = JSVAL_TO_INT(num_properties);
3085 if (n <= 0)
3086 n = 8;
3088 /* Create an array of jsids large enough to hold all the properties */
3089 ida = js_NewIdArray(cx, n);
3090 if (!ida)
3091 goto error;
3093 i = 0;
3094 vector = &ida->vector[0];
3095 for (;;) {
3096 if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &id))
3097 goto error;
3099 /* No more jsid's to enumerate ? */
3100 if (iter_state == JSVAL_NULL)
3101 break;
3103 if (i == ida->length) {
3104 ida = js_SetIdArrayLength(cx, ida, ida->length * 2);
3105 if (!ida)
3106 goto error;
3107 vector = &ida->vector[0];
3108 }
3109 vector[i++] = id;
3110 }
3111 return js_SetIdArrayLength(cx, ida, i);
3113 error:
3114 if (iter_state != JSVAL_NULL)
3115 OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0);
3116 if (ida)
3117 JS_DestroyIdArray(cx, ida);
3118 return NULL;
3119 }
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)
3130 #if JSSLOT_ITER_INDEX >= JS_INITIAL_NSLOTS
3131 # error "JSSLOT_ITER_INDEX botch!"
3132 #endif
3134 static void
3135 prop_iter_finalize(JSContext *cx, JSObject *obj)
3136 {
3137 jsval v;
3138 jsint i;
3139 JSIdArray *ida;
3141 v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_ITER_INDEX);
3142 if (JSVAL_IS_VOID(v))
3143 return;
3145 i = JSVAL_TO_INT(v);
3146 if (i >= 0) {
3147 /* Non-native case: destroy the ida enumerated when obj was created. */
3148 ida = (JSIdArray *) JS_GetPrivate(cx, obj);
3149 if (ida)
3150 JS_DestroyIdArray(cx, ida);
3151 }
3152 }
3154 static uint32
3155 prop_iter_mark(JSContext *cx, JSObject *obj, void *arg)
3156 {
3157 jsval v;
3158 jsint i, n;
3159 JSScopeProperty *sprop;
3160 JSIdArray *ida;
3161 jsid id;
3163 v = GC_AWARE_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
3164 JS_ASSERT(!JSVAL_IS_VOID(v));
3166 i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, obj, JSSLOT_ITER_INDEX));
3167 if (i < 0) {
3168 /* Native case: just mark the next property to visit. */
3169 sprop = (JSScopeProperty *) JSVAL_TO_PRIVATE(v);
3170 if (sprop)
3171 MARK_SCOPE_PROPERTY(sprop);
3172 } else {
3173 /* Non-native case: mark each id in the JSIdArray private. */
3174 ida = (JSIdArray *) JSVAL_TO_PRIVATE(v);
3175 for (i = 0, n = ida->length; i < n; i++) {
3176 id = ida->vector[i];
3177 if (JSID_IS_ATOM(id))
3178 GC_MARK_ATOM(cx, JSID_TO_ATOM(id), arg);
3179 else if (JSID_IS_OBJECT(id))
3180 GC_MARK(cx, JSID_TO_OBJECT(id), "id", arg);
3181 }
3182 }
3183 return 0;
3184 }
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 };
3195 JS_PUBLIC_API(JSObject *)
3196 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
3197 {
3198 JSObject *iterobj;
3199 JSScope *scope;
3200 void *pdata;
3201 jsint index;
3202 JSIdArray *ida;
3204 CHECK_REQUEST(cx);
3205 iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj);
3206 if (!iterobj)
3207 return NULL;
3209 if (OBJ_IS_NATIVE(obj)) {
3210 /* Native case: start with the last property in obj's own scope. */
3211 scope = OBJ_SCOPE(obj);
3212 pdata = (scope->object == obj) ? scope->lastProp : NULL;
3213 index = -1;
3214 } else {
3215 JSTempValueRooter tvr;
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 JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(iterobj), &tvr);
3224 ida = JS_Enumerate(cx, obj);
3225 JS_POP_TEMP_ROOT(cx, &tvr);
3226 if (!ida)
3227 goto bad;
3228 pdata = ida;
3229 index = ida->length;
3230 }
3232 /* iterobj can not escape to other threads here. */
3233 iterobj->slots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(pdata);
3234 iterobj->slots[JSSLOT_ITER_INDEX] = INT_TO_JSVAL(index);
3235 return iterobj;
3237 bad:
3238 cx->newborn[GCX_OBJECT] = NULL;
3239 return NULL;
3240 }
3242 JS_PUBLIC_API(JSBool)
3243 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
3244 {
3245 jsint i;
3246 JSObject *obj;
3247 JSScope *scope;
3248 JSScopeProperty *sprop;
3249 JSIdArray *ida;
3251 CHECK_REQUEST(cx);
3252 i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX));
3253 if (i < 0) {
3254 /* Native case: private data is a property tree node pointer. */
3255 obj = OBJ_GET_PARENT(cx, iterobj);
3256 JS_ASSERT(OBJ_IS_NATIVE(obj));
3257 scope = OBJ_SCOPE(obj);
3258 JS_ASSERT(scope->object == obj);
3259 sprop = (JSScopeProperty *) JS_GetPrivate(cx, iterobj);
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 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 sprop = sprop->parent;
3274 }
3276 if (!sprop) {
3277 *idp = JSVAL_VOID;
3278 } else {
3279 if (!JS_SetPrivate(cx, iterobj, sprop->parent))
3280 return JS_FALSE;
3281 *idp = sprop->id;
3282 }
3283 } else {
3284 /* Non-native case: use the ida enumerated when iterobj was created. */
3285 ida = (JSIdArray *) JS_GetPrivate(cx, iterobj);
3286 JS_ASSERT(i <= ida->length);
3287 if (i == 0) {
3288 *idp = JSVAL_VOID;
3289 } else {
3290 *idp = ida->vector[--i];
3291 OBJ_SET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(i));
3292 }
3293 }
3294 return JS_TRUE;
3295 }
3297 JS_PUBLIC_API(JSBool)
3298 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
3299 jsval *vp, uintN *attrsp)
3300 {
3301 CHECK_REQUEST(cx);
3302 return OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, attrsp);
3303 }
3305 JS_PUBLIC_API(JSCheckAccessOp)
3306 JS_SetCheckObjectAccessCallback(JSRuntime *rt, JSCheckAccessOp acb)
3307 {
3308 JSCheckAccessOp oldacb;
3310 oldacb = rt->checkObjectAccess;
3311 rt->checkObjectAccess = acb;
3312 return oldacb;
3313 }
3315 static JSBool
3316 ReservedSlotIndexOK(JSContext *cx, JSObject *obj, JSClass *clasp,
3317 uint32 index, uint32 limit)
3318 {
3319 /* Check the computed, possibly per-instance, upper bound. */
3320 if (clasp->reserveSlots)
3321 JS_LOCK_OBJ_VOID(cx, obj, limit += clasp->reserveSlots(cx, obj));
3322 if (index >= limit) {
3323 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3324 JSMSG_RESERVED_SLOT_RANGE);
3325 return JS_FALSE;
3326 }
3327 return JS_TRUE;
3328 }
3330 JS_PUBLIC_API(JSBool)
3331 JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
3332 {
3333 JSClass *clasp;
3334 uint32 limit, slot;
3336 CHECK_REQUEST(cx);
3337 clasp = OBJ_GET_CLASS(cx, obj);
3338 limit = JSCLASS_RESERVED_SLOTS(clasp);
3339 if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
3340 return JS_FALSE;
3341 slot = JSSLOT_START(clasp) + index;
3342 *vp = OBJ_GET_REQUIRED_SLOT(cx, obj, slot);
3343 return JS_TRUE;
3344 }
3346 JS_PUBLIC_API(JSBool)
3347 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
3348 {
3349 JSClass *clasp;
3350 uint32 limit, slot;
3352 CHECK_REQUEST(cx);
3353 clasp = OBJ_GET_CLASS(cx, obj);
3354 limit = JSCLASS_RESERVED_SLOTS(clasp);
3355 if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
3356 return JS_FALSE;
3357 slot = JSSLOT_START(clasp) + index;
3358 return OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v);
3359 }
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 }
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
3378 JS_PUBLIC_API(JSPrincipalsTranscoder)
3379 JS_SetPrincipalsTranscoder(JSRuntime *rt, JSPrincipalsTranscoder px)
3380 {
3381 JSPrincipalsTranscoder oldpx;
3383 oldpx = rt->principalsTranscoder;
3384 rt->principalsTranscoder = px;
3385 return oldpx;
3386 }
3388 JS_PUBLIC_API(JSObjectPrincipalsFinder)
3389 JS_SetObjectPrincipalsFinder(JSRuntime *rt, JSObjectPrincipalsFinder fop)
3390 {
3391 JSObjectPrincipalsFinder oldfop;
3393 oldfop = rt->findObjectPrincipals;
3394 rt->findObjectPrincipals = fop;
3395 return oldfop;
3396 }
3398 JS_PUBLIC_API(JSFunction *)
3399 JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
3400 JSObject *parent, const char *name)
3401 {
3402 JSAtom *atom;
3404 CHECK_REQUEST(cx);
3406 if (!name) {
3407 atom = NULL;
3408 } else {
3409 atom = js_Atomize(cx, name, strlen(name), 0);
3410 if (!atom)
3411 return NULL;
3412 }
3413 return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom);
3414 }
3416 JS_PUBLIC_API(JSObject *)
3417 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
3418 {
3419 CHECK_REQUEST(cx);
3420 if (OBJ_GET_CLASS(cx, funobj) != &js_FunctionClass) {
3421 /* Indicate we cannot clone this object. */
3422 return funobj;
3423 }
3424 return js_CloneFunctionObject(cx, funobj, parent);
3425 }
3427 JS_PUBLIC_API(JSObject *)
3428 JS_GetFunctionObject(JSFunction *fun)
3429 {
3430 return fun->object;
3431 }
3433 JS_PUBLIC_API(const char *)
3434 JS_GetFunctionName(JSFunction *fun)
3435 {
3436 return fun->atom
3437 ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
3438 : js_anonymous_str;
3439 }
3441 JS_PUBLIC_API(JSString *)
3442 JS_GetFunctionId(JSFunction *fun)
3443 {
3444 return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
3445 }
3447 JS_PUBLIC_API(uintN)
3448 JS_GetFunctionFlags(JSFunction *fun)
3449 {
3450 return fun->flags;
3451 }
3453 JS_PUBLIC_API(uint16)
3454 JS_GetFunctionArity(JSFunction *fun)
3455 {
3456 return fun->nargs;
3457 }
3459 JS_PUBLIC_API(JSBool)
3460 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
3461 {
3462 return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass;
3463 }
3465 JS_STATIC_DLL_CALLBACK(JSBool)
3466 js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
3467 uintN argc, jsval *argv, jsval *rval)
3468 {
3469 jsval fsv;
3470 JSFunctionSpec *fs;
3471 JSObject *tmp;
3473 if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &fsv))
3474 return JS_FALSE;
3475 fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv);
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 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 if (!js_ValueToObject(cx, argv[0], &tmp))
3489 return JS_FALSE;
3490 argv[0] = OBJECT_TO_JSVAL(tmp);
3491 }
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 memmove(argv - 1, argv, JS_MAX(fs->nargs + 1U, argc) * sizeof(jsval));
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 if (!js_ComputeThis(cx, JSVAL_TO_OBJECT(argv[-1]), cx->fp))
3507 return JS_FALSE;
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 if (argc == 0)
3514 argc = 1;
3516 return fs->call(cx, JSVAL_TO_OBJECT(argv[-1]), argc - 1, argv, rval);
3517 }
3519 JS_PUBLIC_API(JSBool)
3520 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
3521 {
3522 uintN flags;
3523 JSObject *ctor;
3524 JSFunction *fun;
3526 CHECK_REQUEST(cx);
3527 ctor = NULL;
3528 for (; fs->name; fs++) {
3529 flags = fs->flags;
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 if (flags & JSFUN_GENERIC_NATIVE) {
3536 if (!ctor) {
3537 ctor = JS_GetConstructor(cx, obj);
3538 if (!ctor)
3539 return JS_FALSE;
3540 }
3542 flags &= ~JSFUN_GENERIC_NATIVE;
3543 fun = JS_DefineFunction(cx, ctor, fs->name,
3544 js_generic_native_method_dispatcher,
3545 fs->nargs + 1, flags);
3546 if (!fun)
3547 return JS_FALSE;
3548 fun->extra = fs->extra;
3550 /*
3551 * As jsapi.h notes, fs must point to storage that lives as long
3552 * as fun->object lives.
3553 */
3554 if (!JS_SetReservedSlot(cx, fun->object, 0, PRIVATE_TO_JSVAL(fs)))
3555 return JS_FALSE;
3556 }
3558 fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
3559 if (!fun)
3560 return JS_FALSE;
3561 fun->extra = fs->extra;
3562 }
3563 return JS_TRUE;
3564 }
3566 JS_PUBLIC_API(JSFunction *)
3567 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
3568 uintN nargs, uintN attrs)
3569 {
3570 JSAtom *atom;
3572 CHECK_REQUEST(cx);
3573 atom = js_Atomize(cx, name, strlen(name), 0);
3574 if (!atom)
3575 return NULL;
3576 return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
3577 }
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 {
3584 JSAtom *atom;
3586 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3587 if (!atom)
3588 return NULL;
3589 return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
3590 }
3592 static JSScript *
3593 CompileTokenStream(JSContext *cx, JSObject *obj, JSTokenStream *ts,
3594 void *tempMark, JSBool *eofp)
3595 {
3596 JSBool eof;
3597 JSArenaPool codePool, notePool;
3598 JSCodeGenerator cg;
3599 JSScript *script;
3601 CHECK_REQUEST(cx);
3602 eof = JS_FALSE;
3603 JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode));
3604 JS_InitArenaPool(¬ePool, "note", 1024, sizeof(jssrcnote));
3605 if (!js_InitCodeGenerator(cx, &cg, &codePool, ¬ePool,
3606 ts->filename, ts->lineno,
3607 ts->principals)) {
3608 script = NULL;
3609 } else if (!js_CompileTokenStream(cx, obj, ts, &cg)) {
3610 script = NULL;
3611 eof = (ts->flags & TSF_EOF) != 0;
3612 } else {
3613 script = js_NewScriptFromCG(cx, &cg, NULL);
3614 }
3615 if (eofp)
3616 *eofp = eof;
3617 if (!js_CloseTokenStream(cx, ts)) {
3618 if (script)
3619 js_DestroyScript(cx, script);
3620 script = NULL;
3621 }
3622 cg.tempMark = tempMark;
3623 js_FinishCodeGenerator(cx, &cg);
3624 JS_FinishArenaPool(&codePool);
3625 JS_FinishArenaPool(¬ePool);
3626 return script;
3627 }
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 {
3634 jschar *chars;
3635 JSScript *script;
3637 CHECK_REQUEST(cx);
3638 chars = js_InflateString(cx, bytes, &length);
3639 if (!chars)
3640 return NULL;
3641 script = JS_CompileUCScript(cx, obj, chars, length, filename, lineno);
3642 JS_free(cx, chars);
3643 return script;
3644 }
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 {
3652 jschar *chars;
3653 JSScript *script;
3655 CHECK_REQUEST(cx);
3656 chars = js_InflateString(cx, bytes, &length);
3657 if (!chars)
3658 return NULL;
3659 script = JS_CompileUCScriptForPrincipals(cx, obj, principals,
3660 chars, length, filename, lineno);
3661 JS_free(cx, chars);
3662 return script;
3663 }
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 {
3670 CHECK_REQUEST(cx);
3671 return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length,
3672 filename, lineno);
3673 }
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
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
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 {
3699 void *mark;
3700 JSTokenStream *ts;
3701 JSScript *script;
3703 CHECK_REQUEST(cx);
3704 mark = JS_ARENA_MARK(&cx->tempPool);
3705 ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
3706 if (!ts)
3707 return NULL;
3708 script = CompileTokenStream(cx, obj, ts, mark, NULL);
3709 LAST_FRAME_CHECKS(cx, script);
3710 return script;
3711 }
3713 JS_PUBLIC_API(JSBool)
3714 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
3715 const char *bytes, size_t length)
3716 {
3717 jschar *chars;
3718 JSBool result;
3719 JSExceptionState *exnState;
3720 void *tempMark;
3721 JSTokenStream *ts;
3722 JSErrorReporter older;
3724 CHECK_REQUEST(cx);
3725 chars = js_InflateString(cx, bytes, &length);
3726 if (!chars)
3727 return JS_TRUE;
3729 /*
3730 * Return true on any out-of-memory error, so our caller doesn't try to
3731 * collect more buffered source.
3732 */
3733 result = JS_TRUE;
3734 exnState = JS_SaveExceptionState(cx);
3735 tempMark = JS_ARENA_MARK(&cx->tempPool);
3736 ts = js_NewTokenStream(cx, chars, length, NULL, 0, NULL);
3737 if (ts) {
3738 older = JS_SetErrorReporter(cx, NULL);
3739 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 result = JS_FALSE;
3747 }
3749 JS_SetErrorReporter(cx, older);
3750 js_CloseTokenStream(cx, ts);
3751 JS_ARENA_RELEASE(&cx->tempPool, tempMark);
3752 }
3754 JS_free(cx, chars);
3755 JS_RestoreExceptionState(cx, exnState);
3756 return result;
3757 }
3759 JS_PUBLIC_API(JSScript *)
3760 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
3761 {
3762 void *mark;
3763 JSTokenStream *ts;
3764 JSScript *script;
3766 CHECK_REQUEST(cx);
3767 mark = JS_ARENA_MARK(&cx->tempPool);
3768 ts = js_NewFileTokenStream(cx, filename, stdin);
3769 if (!ts)
3770 return NULL;
3771 script = CompileTokenStream(cx, obj, ts, mark, NULL);
3772 LAST_FRAME_CHECKS(cx, script);
3773 return script;
3774 }
3776 JS_PUBLIC_API(JSScript *)
3777 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename,
3778 FILE *file)
3779 {
3780 return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
3781 }
3783 JS_PUBLIC_API(JSScript *)
3784 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
3785 const char *filename, FILE *file,
3786 JSPrincipals *principals)
3787 {
3788 void *mark;
3789 JSTokenStream *ts;
3790 JSScript *script;
3792 CHECK_REQUEST(cx);
3793 mark = JS_ARENA_MARK(&cx->tempPool);
3794 ts = js_NewFileTokenStream(cx, NULL, file);
3795 if (!ts)
3796 return NULL;
3797 ts->filename = filename;
3798 /* XXXshaver js_NewFileTokenStream should do this, because it drops */
3799 if (principals) {
3800 ts->principals = principals;
3801 JSPRINCIPALS_HOLD(cx, ts->principals);
3802 }
3803 script = CompileTokenStream(cx, obj, ts, mark, NULL);
3804 LAST_FRAME_CHECKS(cx, script);
3805 return script;
3806 }
3808 JS_PUBLIC_API(JSObject *)
3809 JS_NewScriptObject(JSContext *cx, JSScript *script)
3810 {
3811 JSObject *obj;
3813 obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
3814 if (!obj)
3815 return NULL;
3817 if (script) {
3818 if (!JS_SetPrivate(cx, obj, script))
3819 return NULL;
3820 script->object = obj;
3821 }
3822 return obj;
3823 }
3825 JS_PUBLIC_API(JSObject *)
3826 JS_GetScriptObject(JSScript *script)
3827 {
3828 return script->object;
3829 }
3831 JS_PUBLIC_API(void)
3832 JS_DestroyScript(JSContext *cx, JSScript *script)
3833 {
3834 CHECK_REQUEST(cx);
3835 js_DestroyScript(cx, script);
3836 }
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 {
3844 jschar *chars;
3845 JSFunction *fun;
3847 CHECK_REQUEST(cx);
3848 chars = js_InflateString(cx, bytes, &length);
3849 if (!chars)
3850 return NULL;
3851 fun = JS_CompileUCFunction(cx, obj, name, nargs, argnames, chars, length,
3852 filename, lineno);
3853 JS_free(cx, chars);
3854 return fun;
3855 }
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 {
3864 jschar *chars;
3865 JSFunction *fun;
3867 CHECK_REQUEST(cx);
3868 chars = js_InflateString(cx, bytes, &length);
3869 if (!chars)
3870 return NULL;
3871 fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
3872 nargs, argnames, chars, length,
3873 filename, lineno);
3874 JS_free(cx, chars);
3875 return fun;
3876 }
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 {
3884 CHECK_REQUEST(cx);
3885 return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name,
3886 nargs, argnames,
3887 chars, length,
3888 filename, lineno);
3889 }
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 {
3898 void *mark;
3899 JSTokenStream *ts;
3900 JSFunction *fun;
3901 JSAtom *funAtom, *argAtom;
3902 uintN i;
3904 CHECK_REQUEST(cx);
3905 mark = JS_ARENA_MARK(&cx->tempPool);
3906 ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals);
3907 if (!ts) {
3908 fun = NULL;
3909 goto out;
3910 }
3911 if (!name) {
3912 funAtom = NULL;
3913 } else {
3914 funAtom = js_Atomize(cx, name, strlen(name), 0);
3915 if (!funAtom) {
3916 fun = NULL;
3917 goto out;
3918 }
3919 }
3920 fun = js_NewFunction(cx, NULL, NULL, nargs, 0, obj, funAtom);
3921 if (!fun)
3922 goto out;
3923 if (nargs) {
3924 for (i = 0; i < nargs; i++) {
3925 argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
3926 if (!argAtom)
3927 break;
3928 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 break;
3934 }
3935 }
3936 if (i < nargs) {
3937 fun = NULL;
3938 goto out;
3939 }
3940 }
3941 if (!js_CompileFunctionBody(cx, ts, fun)) {
3942 fun = NULL;
3943 goto out;
3944 }
3945 if (obj && funAtom) {
3946 if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(funAtom),
3947 OBJECT_TO_JSVAL(fun->object),
3948 NULL, NULL, JSPROP_ENUMERATE, NULL)) {
3949 return NULL;
3950 }
3951 }
3952 out:
3953 if (ts)
3954 js_CloseTokenStream(cx, ts);
3955 JS_ARENA_RELEASE(&cx->tempPool, mark);
3956 LAST_FRAME_CHECKS(cx, fun);
3957 return fun;
3958 }
3960 JS_PUBLIC_API(JSString *)
3961 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
3962 uintN indent)
3963 {
3964 JSPrinter *jp;
3965 JSString *str;
3967 CHECK_REQUEST(cx);
3968 jp = js_NewPrinter(cx, name,
3969 indent & ~JS_DONT_PRETTY_PRINT,
3970 !(indent & JS_DONT_PRETTY_PRINT));
3971 if (!jp)
3972 return NULL;
3973 if (js_DecompileScript(jp, script))
3974 str = js_GetPrinterOutput(jp);
3975 else
3976 str = NULL;
3977 js_DestroyPrinter(jp);
3978 return str;
3979 }
3981 JS_PUBLIC_API(JSString *)
3982 JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
3983 {
3984 JSPrinter *jp;
3985 JSString *str;
3987 CHECK_REQUEST(cx);
3988 jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
3989 indent & ~JS_DONT_PRETTY_PRINT,
3990 !(indent & JS_DONT_PRETTY_PRINT));
3991 if (!jp)
3992 return NULL;
3993 if (js_DecompileFunction(jp, fun))
3994 str = js_GetPrinterOutput(jp);
3995 else
3996 str = NULL;
3997 js_DestroyPrinter(jp);
3998 return str;
3999 }
4001 JS_PUBLIC_API(JSString *)
4002 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
4003 {
4004 JSPrinter *jp;
4005 JSString *str;
4007 CHECK_REQUEST(cx);
4008 jp = js_NewPrinter(cx, JS_GetFunctionName(fun),
4009 indent & ~JS_DONT_PRETTY_PRINT,
4010 !(indent & JS_DONT_PRETTY_PRINT));
4011 if (!jp)
4012 return NULL;
4013 if (js_DecompileFunctionBody(jp, fun))
4014 str = js_GetPrinterOutput(jp);
4015 else
4016 str = NULL;
4017 js_DestroyPrinter(jp);
4018 return str;
4019 }
4021 JS_PUBLIC_API(JSBool)
4022 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
4023 {
4024 JSBool ok;
4026 CHECK_REQUEST(cx);
4027 ok = js_Execute(cx, obj, script, NULL, 0, rval);
4028 LAST_FRAME_CHECKS(cx, ok);
4029 return ok;
4030 }
4032 JS_PUBLIC_API(JSBool)
4033 JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script,
4034 JSExecPart part, jsval *rval)
4035 {
4036 JSScript tmp;
4037 JSRuntime *rt;
4038 JSBool ok;
4040 /* Make a temporary copy of the JSScript structure and farble it a bit. */
4041 tmp = *script;
4042 if (part == JSEXEC_PROLOG) {
4043 tmp.length = PTRDIFF(tmp.main, tmp.code, jsbytecode);
4044 } else {
4045 tmp.length -= PTRDIFF(tmp.main, tmp.code, jsbytecode);
4046 tmp.code = tmp.main;
4047 }
4049 /* Tell the debugger about our temporary copy of the script structure. */
4050 rt = cx->runtime;
4051 if (rt->newScriptHook) {
4052 rt->newScriptHook(cx, tmp.filename, tmp.lineno, &tmp, NULL,
4053 rt->newScriptHookData);
4054 }
4056 /* Execute the farbled struct and tell the debugger to forget about it. */
4057 ok = JS_ExecuteScript(cx, obj, &tmp, rval);
4058 if (rt->destroyScriptHook)
4059 rt->destroyScriptHook(cx, &tmp, rt->destroyScriptHookData);
4060 return ok;
4061 }
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 {
4069 size_t length = nbytes;
4070 jschar *chars;
4071 JSBool ok;
4073 CHECK_REQUEST(cx);
4074 chars = js_InflateString(cx, bytes, &length);
4075 if (!chars)
4076 return JS_FALSE;
4077 ok = JS_EvaluateUCScript(cx, obj, chars, length, filename, lineno, rval);
4078 JS_free(cx, chars);
4079 return ok;
4080 }
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 {
4089 size_t length = nbytes;
4090 jschar *chars;
4091 JSBool ok;
4093 CHECK_REQUEST(cx);
4094 chars = js_InflateString(cx, bytes, &length);
4095 if (!chars)
4096 return JS_FALSE;
4097 ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
4098 filename, lineno, rval);
4099 JS_free(cx, chars);
4100 return ok;
4101 }
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 {
4109 CHECK_REQUEST(cx);
4110 return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length,
4111 filename, lineno, rval);
4112 }
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 {
4121 uint32 options;
4122 JSScript *script;
4123 JSBool ok;
4125 CHECK_REQUEST(cx);
4126 options = cx->options;
4127 cx->options = options | JSOPTION_COMPILE_N_GO;
4128 script = JS_CompileUCScriptForPrincipals(cx, obj, principals, chars, length,
4129 filename, lineno);
4130 cx->options = options;
4131 if (!script)
4132 return JS_FALSE;
4133 ok = js_Execute(cx, obj, script, NULL, 0, rval);
4134 LAST_FRAME_CHECKS(cx, ok);
4135 JS_DestroyScript(cx, script);
4136 return ok;
4137 }
4139 JS_PUBLIC_API(JSBool)
4140 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc,
4141 jsval *argv, jsval *rval)
4142 {
4143 JSBool ok;
4145 CHECK_REQUEST(cx);
4146 ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(fun->object), argc, argv,
4147 rval);
4148 LAST_FRAME_CHECKS(cx, ok);
4149 return ok;
4150 }
4152 JS_PUBLIC_API(JSBool)
4153 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
4154 jsval *argv, jsval *rval)
4155 {
4156 JSBool ok;
4157 jsval fval;
4159 CHECK_REQUEST(cx);
4160 #if JS_HAS_XML_SUPPORT
4161 if (OBJECT_IS_XML(cx, obj)) {
4162 JSXMLObjectOps *ops;
4163 JSAtom *atom;
4165 ops = (JSXMLObjectOps *) obj->map->ops;
4166 atom = js_Atomize(cx, name, strlen(name), 0);
4167 if (!atom)
4168 return JS_FALSE;
4169 obj = ops->getMethod(cx, obj, ATOM_TO_JSID(atom), &fval);
4170 if (!obj)
4171 return JS_FALSE;
4172 } else
4173 #endif
4174 if (!JS_GetProperty(cx, obj, name, &fval))
4175 return JS_FALSE;
4176 ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
4177 LAST_FRAME_CHECKS(cx, ok);
4178 return ok;
4179 }
4181 JS_PUBLIC_API(JSBool)
4182 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
4183 jsval *argv, jsval *rval)
4184 {
4185 JSBool ok;
4187 CHECK_REQUEST(cx);
4188 ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
4189 LAST_FRAME_CHECKS(cx, ok);
4190 return ok;
4191 }
4193 JS_PUBLIC_API(JSBranchCallback)
4194 JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb)
4195 {
4196 JSBranchCallback oldcb;
4198 oldcb = cx->branchCallback;
4199 cx->branchCallback = cb;
4200 return oldcb;
4201 }
4203 JS_PUBLIC_API(JSBool)
4204 JS_IsRunning(JSContext *cx)
4205 {
4206 return cx->fp != NULL;
4207 }
4209 JS_PUBLIC_API(JSBool)
4210 JS_IsConstructing(JSContext *cx)
4211 {
4212 return cx->fp && (cx->fp->flags & JSFRAME_CONSTRUCTING);
4213 }
4215 JS_FRIEND_API(JSBool)
4216 JS_IsAssigning(JSContext *cx)
4217 {
4218 JSStackFrame *fp;
4219 jsbytecode *pc;
4221 for (fp = cx->fp; fp && !fp->script; fp = fp->down)
4222 continue;
4223 if (!fp || !(pc = fp->pc))
4224 return JS_FALSE;
4225 return (js_CodeSpec[*pc].format & JOF_ASSIGNING) != 0;
4226 }
4228 JS_PUBLIC_API(void)
4229 JS_SetCallReturnValue2(JSContext *cx, jsval v)
4230 {
4231 #if JS_HAS_LVALUE_RETURN
4232 cx->rval2 = v;
4233 cx->rval2set = JS_TRUE;
4234 #endif
4235 }
4237 /************************************************************************/
4239 JS_PUBLIC_API(JSString *)
4240 JS_NewString(JSContext *cx, char *bytes, size_t length)
4241 {
4242 jschar *chars;
4243 JSString *str;
4244 size_t charsLength = length;
4246 CHECK_REQUEST(cx);
4247 /* Make a Unicode vector from the 8-bit char codes in bytes. */
4248 chars = js_InflateString(cx, bytes, &charsLength);
4249 if (!chars)
4250 return NULL;
4252 /* Free chars (but not bytes, which caller frees on error) if we fail. */
4253 str = js_NewString(cx, chars, charsLength, 0);
4254 if (!str) {
4255 JS_free(cx, chars);
4256 return NULL;
4257 }
4259 /* Hand off bytes to the deflated string cache, if possible. */
4260 if (!js_SetStringBytes(str, bytes, length))
4261 JS_free(cx, bytes);
4262 return str;
4263 }
4265 JS_PUBLIC_API(JSString *)
4266 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
4267 {
4268 jschar *js;
4269 JSString *str;
4271 CHECK_REQUEST(cx);
4272 js = js_InflateString(cx, s, &n);
4273 if (!js)
4274 return NULL;
4275 str = js_NewString(cx, js, n, 0);
4276 if (!str)
4277 JS_free(cx, js);
4278 return str;
4279 }
4281 JS_PUBLIC_API(JSString *)
4282 JS_NewStringCopyZ(JSContext *cx, const char *s)
4283 {
4284 size_t n;
4285 jschar *js;
4286 JSString *str;
4288 CHECK_REQUEST(cx);
4289 if (!s)
4290 return cx->runtime->emptyString;
4291 n = strlen(s);
4292 js = js_InflateString(cx, s, &n);
4293 if (!js)
4294 return NULL;
4295 str = js_NewString(cx, js, n, 0);
4296 if (!str)
4297 JS_free(cx, js);
4298 return str;
4299 }
4301 JS_PUBLIC_API(JSString *)
4302 JS_InternString(JSContext *cx, const char *s)
4303 {
4304 JSAtom *atom;
4306 CHECK_REQUEST(cx);
4307 atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
4308 if (!atom)
4309 return NULL;
4310 return ATOM_TO_STRING(atom);
4311 }
4313 JS_PUBLIC_API(JSString *)
4314 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
4315 {
4316 CHECK_REQUEST(cx);
4317 return js_NewString(cx, chars, length, 0);
4318 }
4320 JS_PUBLIC_API(JSString *)
4321 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
4322 {
4323 CHECK_REQUEST(cx);
4324 return js_NewStringCopyN(cx, s, n, 0);
4325 }
4327 JS_PUBLIC_API(JSString *)
4328 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
4329 {
4330 CHECK_REQUEST(cx);
4331 if (!s)
4332 return cx->runtime->emptyString;
4333 return js_NewStringCopyZ(cx, s, 0);
4334 }
4336 JS_PUBLIC_API(JSString *)
4337 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
4338 {
4339 JSAtom *atom;
4341 CHECK_REQUEST(cx);
4342 atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
4343 if (!atom)
4344 return NULL;
4345 return ATOM_TO_STRING(atom);
4346 }
4348 JS_PUBLIC_API(JSString *)
4349 JS_InternUCString(JSContext *cx, const jschar *s)
4350 {
4351 return JS_InternUCStringN(cx, s, js_strlen(s));
4352 }
4354 JS_PUBLIC_API(char *)
4355 JS_GetStringBytes(JSString *str)
4356 {
4357 char *bytes;
4359 bytes = js_GetStringBytes(str);
4360 return bytes ? bytes : "";
4361 }
4363 JS_PUBLIC_API(jschar *)
4364 JS_GetStringChars(JSString *str)
4365 {
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;
4380 chars = js_GetStringChars(str);
4381 return chars ? chars : JSSTRING_CHARS(str);
4382 }
4384 JS_PUBLIC_API(size_t)
4385 JS_GetStringLength(JSString *str)
4386 {
4387 return JSSTRING_LENGTH(str);
4388 }
4390 JS_PUBLIC_API(intN)
4391 JS_CompareStrings(JSString *str1, JSString *str2)
4392 {
4393 return js_CompareStrings(str1, str2);
4394 }
4396 JS_PUBLIC_API(JSString *)
4397 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
4398 {
4399 CHECK_REQUEST(cx);
4400 return js_NewString(cx, chars, length, GCF_MUTABLE);
4401 }
4403 JS_PUBLIC_API(JSString *)
4404 JS_NewDependentString(JSContext *cx, JSString *str, size_t start,
4405 size_t length)
4406 {
4407 CHECK_REQUEST(cx);
4408 return js_NewDependentString(cx, str, start, length, 0);
4409 }
4411 JS_PUBLIC_API(JSString *)
4412 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
4413 {
4414 CHECK_REQUEST(cx);
4415 return js_ConcatStrings(cx, left, right);
4416 }
4418 JS_PUBLIC_API(const jschar *)
4419 JS_UndependString(JSContext *cx, JSString *str)
4420 {
4421 CHECK_REQUEST(cx);
4422 return js_UndependString(cx, str);
4423 }
4425 JS_PUBLIC_API(JSBool)
4426 JS_MakeStringImmutable(JSContext *cx, JSString *str)
4427 {
4428 CHECK_REQUEST(cx);
4429 if (!js_UndependString(cx, str))
4430 return JS_FALSE;
4432 *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
4433 return JS_TRUE;
4434 }
4436 JS_PUBLIC_API(JSBool)
4437 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst,
4438 size_t *dstlenp)
4439 {
4440 return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
4441 }
4443 JS_PUBLIC_API(JSBool)
4444 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst,
4445 size_t *dstlenp)
4446 {
4447 return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
4448 }
4450 JS_PUBLIC_API(JSBool)
4451 JS_StringsAreUTF8 ()
4452 {
4453 #ifdef JS_C_STRINGS_ARE_UTF8
4454 return JS_TRUE;
4455 #else
4456 return JS_FALSE;
4457 #endif
4458 }
4460 /************************************************************************/
4462 JS_PUBLIC_API(void)
4463 JS_ReportError(JSContext *cx, const char *format, ...)
4464 {
4465 va_list ap;
4467 va_start(ap, format);
4468 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
4469 va_end(ap);
4470 }
4472 JS_PUBLIC_API(void)
4473 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
4474 void *userRef, const uintN errorNumber, ...)
4475 {
4476 va_list ap;
4478 va_start(ap, errorNumber);
4479 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
4480 errorNumber, JS_TRUE, ap);
4481 va_end(ap);
4482 }
4484 JS_PUBLIC_API(void)
4485 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
4486 void *userRef, const uintN errorNumber, ...)
4487 {
4488 va_list ap;
4490 va_start(ap, errorNumber);
4491 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
4492 errorNumber, JS_FALSE, ap);
4493 va_end(ap);
4494 }
4496 JS_PUBLIC_API(JSBool)
4497 JS_ReportWarning(JSContext *cx, const char *format, ...)
4498 {
4499 va_list ap;
4500 JSBool ok;
4502 va_start(ap, format);
4503 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
4504 va_end(ap);
4505 return ok;
4506 }
4508 JS_PUBLIC_API(JSBool)
4509 JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
4510 JSErrorCallback errorCallback, void *userRef,
4511 const uintN errorNumber, ...)
4512 {
4513 va_list ap;
4514 JSBool ok;
4516 va_start(ap, errorNumber);
4517 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
4518 errorNumber, JS_TRUE, ap);
4519 va_end(ap);
4520 return ok;
4521 }
4523 JS_PUBLIC_API(JSBool)
4524 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
4525 JSErrorCallback errorCallback, void *userRef,
4526 const uintN errorNumber, ...)
4527 {
4528 va_list ap;
4529 JSBool ok;
4531 va_start(ap, errorNumber);
4532 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
4533 errorNumber, JS_FALSE, ap);
4534 va_end(ap);
4535 return ok;
4536 }
4538 JS_PUBLIC_API(void)
4539 JS_ReportOutOfMemory(JSContext *cx)
4540 {
4541 js_ReportOutOfMemory(cx, js_GetErrorMessage);
4542 }
4544 JS_PUBLIC_API(JSErrorReporter)
4545 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
4546 {
4547 JSErrorReporter older;
4549 older = cx->errorReporter;
4550 cx->errorReporter = er;
4551 return older;
4552 }
4554 /************************************************************************/
4556 /*
4557 * Regular Expressions.
4558 */
4559 JS_PUBLIC_API(JSObject *)
4560 JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags)
4561 {
4562 #if JS_HAS_REGEXPS
4563 jschar *chars;
4564 JSObject *obj;
4566 CHECK_REQUEST(cx);
4567 chars = js_InflateString(cx, bytes, &length);
4568 if (!chars)
4569 return NULL;
4570 obj = js_NewRegExpObject(cx, NULL, chars, length, flags);
4571 JS_free(cx, chars);
4572 return obj;
4573 #else
4574 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_REG_EXPS);
4575 return NULL;
4576 #endif
4577 }
4579 JS_PUBLIC_API(JSObject *)
4580 JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags)
4581 {
4582 CHECK_REQUEST(cx);
4583 #if JS_HAS_REGEXPS
4584 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 }
4591 JS_PUBLIC_API(void)
4592 JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline)
4593 {
4594 JSRegExpStatics *res;
4596 CHECK_REQUEST(cx);
4597 /* No locking required, cx is thread-private and input must be live. */
4598 res = &cx->regExpStatics;
4599 res->input = input;
4600 res->multiline = multiline;
4601 cx->runtime->gcPoke = JS_TRUE;
4602 }
4604 JS_PUBLIC_API(void)
4605 JS_ClearRegExpStatics(JSContext *cx)
4606 {
4607 JSRegExpStatics *res;
4609 /* No locking required, cx is thread-private and input must be live. */
4610 res = &cx->regExpStatics;
4611 res->input = NULL;
4612 res->multiline = JS_FALSE;
4613 res->parenCount = 0;
4614 res->lastMatch = res->lastParen = js_EmptySubString;
4615 res->leftContext = res->rightContext = js_EmptySubString;
4616 cx->runtime->gcPoke = JS_TRUE;
4617 }
4619 JS_PUBLIC_API(void)
4620 JS_ClearRegExpRoots(JSContext *cx)
4621 {
4622 JSRegExpStatics *res;
4624 /* No locking required, cx is thread-private and input must be live. */
4625 res = &cx->regExpStatics;
4626 res->input = NULL;
4627 cx->runtime->gcPoke = JS_TRUE;
4628 }
4630 /* TODO: compile, execute, get/set other statics... */
4632 /************************************************************************/
4634 JS_PUBLIC_API(void)
4635 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
4636 {
4637 cx->localeCallbacks = callbacks;
4638 }
4640 JS_PUBLIC_API(JSLocaleCallbacks *)
4641 JS_GetLocaleCallbacks(JSContext *cx)
4642 {
4643 return cx->localeCallbacks;
4644 }
4646 /************************************************************************/
4648 JS_PUBLIC_API(JSBool)
4649 JS_IsExceptionPending(JSContext *cx)
4650 {
4651 #if JS_HAS_EXCEPTIONS
4652 return (JSBool) cx->throwing;
4653 #else
4654 return JS_FALSE;
4655 #endif
4656 }
4658 JS_PUBLIC_API(JSBool)
4659 JS_GetPendingException(JSContext *cx, jsval *vp)
4660 {
4661 #if JS_HAS_EXCEPTIONS
4662 CHECK_REQUEST(cx);
4663 if (!cx->throwing)
4664 return JS_FALSE;
4665 *vp = cx->exception;
4666 return JS_TRUE;
4667 #else
4668 return JS_FALSE;
4669 #endif
4670 }
4672 JS_PUBLIC_API(void)
4673 JS_SetPendingException(JSContext *cx, jsval v)
4674 {
4675 CHECK_REQUEST(cx);
4676 #if JS_HAS_EXCEPTIONS
4677 cx->throwing = JS_TRUE;
4678 cx->exception = v;
4679 #endif
4680 }
4682 JS_PUBLIC_API(void)
4683 JS_ClearPendingException(JSContext *cx)
4684 {
4685 #if JS_HAS_EXCEPTIONS
4686 cx->throwing = JS_FALSE;
4687 cx->exception = JSVAL_VOID;
4688 #endif
4689 }
4691 JS_PUBLIC_API(JSBool)
4692 JS_ReportPendingException(JSContext *cx)
4693 {
4694 #if JS_HAS_EXCEPTIONS
4695 JSBool save, ok;
4697 CHECK_REQUEST(cx);
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 save = cx->creatingException;
4706 cx->creatingException = JS_TRUE;
4707 ok = js_ReportUncaughtException(cx);
4708 cx->creatingException = save;
4709 return ok;
4710 #else
4711 return JS_TRUE;
4712 #endif
4713 }
4715 #if JS_HAS_EXCEPTIONS
4716 struct JSExceptionState {
4717 JSBool throwing;
4718 jsval exception;
4719 };
4720 #endif
4722 JS_PUBLIC_API(JSExceptionState *)
4723 JS_SaveExceptionState(JSContext *cx)
4724 {
4725 #if JS_HAS_EXCEPTIONS
4726 JSExceptionState *state;
4728 CHECK_REQUEST(cx);
4729 state = (JSExceptionState *) JS_malloc(cx, sizeof(JSExceptionState));
4730 if (state) {
4731 state->throwing = JS_GetPendingException(cx, &state->exception);
4732 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
4733 js_AddRoot(cx, &state->exception, "JSExceptionState.exception");
4734 }
4735 return state;
4736 #else
4737 return NULL;
4738 #endif
4739 }
4741 JS_PUBLIC_API(void)
4742 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
4743 {
4744 #if JS_HAS_EXCEPTIONS
4745 CHECK_REQUEST(cx);
4746 if (state) {
4747 if (state->throwing)
4748 JS_SetPendingException(cx, state->exception);
4749 else
4750 JS_ClearPendingException(cx);
4751 JS_DropExceptionState(cx, state);
4752 }
4753 #endif
4754 }
4756 JS_PUBLIC_API(void)
4757 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
4758 {
4759 #if JS_HAS_EXCEPTIONS
4760 CHECK_REQUEST(cx);
4761 if (state) {
4762 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
4763 JS_RemoveRoot(cx, &state->exception);
4764 JS_free(cx, state);
4765 }
4766 #endif
4767 }
4769 JS_PUBLIC_API(JSErrorReport *)
4770 JS_ErrorFromException(JSContext *cx, jsval v)
4771 {
4772 #if JS_HAS_ERROR_EXCEPTIONS
4773 CHECK_REQUEST(cx);
4774 return js_ErrorFromException(cx, v);
4775 #else
4776 return NULL;
4777 #endif
4778 }
4780 JS_PUBLIC_API(JSBool)
4781 JS_ThrowReportedError(JSContext *cx, const char *message,
4782 JSErrorReport *reportp)
4783 {
4784 return js_ErrorToException(cx, message, reportp);
4785 }
4787 #ifdef JS_THREADSAFE
4788 JS_PUBLIC_API(jsword)
4789 JS_GetContextThread(JSContext *cx)
4790 {
4791 return cx->thread;
4792 }
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 }
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
4811 /************************************************************************/
4813 #if defined(XP_WIN)
4814 #include <windows.h>
4815 /*
4816 * Initialization routine for the JS DLL...
4817 */
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 */
4827 #ifdef _WIN32
4828 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
4829 {
4830 return TRUE;
4831 }
4833 #else /* !_WIN32 */
4835 int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg,
4836 WORD cbHeapSize, LPSTR lpszCmdLine )
4837 {
4838 return TRUE;
4839 }
4841 BOOL CALLBACK __loadds WEP(BOOL fSystemExit)
4842 {
4843 return TRUE;
4844 }
4846 #endif /* !_WIN32 */
4847 #endif /* XP_WIN */