Bug 463806 - [PATCH][@font-face] Downloaded font activation on Mac may fail due to...
[wine-gecko.git] / js / src / jsapi.cpp
blobf0d6294fab0cf051754f974cd0bdddfd2d7ee5d3
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=78:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
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.
25 * Contributor(s):
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.
39 * ***** END LICENSE BLOCK ***** */
42 * JavaScript API.
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 "jsbuiltins.h"
60 #include "jscntxt.h"
61 #include "jsversion.h"
62 #include "jsdate.h"
63 #include "jsdtoa.h"
64 #include "jsemit.h"
65 #include "jsexn.h"
66 #include "jsfun.h"
67 #include "jsgc.h"
68 #include "jsinterp.h"
69 #include "jsiter.h"
70 #include "jslock.h"
71 #include "jsmath.h"
72 #include "jsnum.h"
73 #include "json.h"
74 #include "jsobj.h"
75 #include "jsopcode.h"
76 #include "jsparse.h"
77 #include "jsregexp.h"
78 #include "jsscan.h"
79 #include "jsscope.h"
80 #include "jsscript.h"
81 #include "jsstr.h"
82 #include "jsdbgapi.h"
83 #include "prmjtime.h"
84 #include "jsstaticcheck.h"
86 #if !defined JS_THREADSAFE && defined JS_TRACER
87 #include "jstracer.h"
88 #endif
90 #if JS_HAS_FILE_OBJECT
91 #include "jsfile.h"
92 #endif
94 #if JS_HAS_XML_SUPPORT
95 #include "jsxml.h"
96 #endif
98 #ifdef HAVE_VA_LIST_AS_ARRAY
99 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
100 #else
101 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
102 #endif
104 #if defined(JS_THREADSAFE)
105 #define CHECK_REQUEST(cx) \
106 JS_ASSERT((cx)->requestDepth || (cx)->thread == (cx)->runtime->gcThread)
107 #else
108 #define CHECK_REQUEST(cx) ((void)0)
109 #endif
111 JS_PUBLIC_API(int64)
112 JS_Now()
114 return PRMJ_Now();
117 JS_PUBLIC_API(jsval)
118 JS_GetNaNValue(JSContext *cx)
120 return DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
123 JS_PUBLIC_API(jsval)
124 JS_GetNegativeInfinityValue(JSContext *cx)
126 return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
129 JS_PUBLIC_API(jsval)
130 JS_GetPositiveInfinityValue(JSContext *cx)
132 return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
135 JS_PUBLIC_API(jsval)
136 JS_GetEmptyStringValue(JSContext *cx)
138 return STRING_TO_JSVAL(cx->runtime->emptyString);
141 static JSBool
142 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS,
143 jsval **vpp, va_list *app)
145 const char *format;
146 JSArgumentFormatMap *map;
148 format = *formatp;
149 for (map = cx->argumentFormatMap; map; map = map->next) {
150 if (!strncmp(format, map->format, map->length)) {
151 *formatp = format + map->length;
152 return map->formatter(cx, format, fromJS, vpp, app);
155 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
156 return JS_FALSE;
159 JS_PUBLIC_API(JSBool)
160 JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
161 ...)
163 va_list ap;
164 JSBool ok;
166 va_start(ap, format);
167 ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
168 va_end(ap);
169 return ok;
172 JS_PUBLIC_API(JSBool)
173 JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
174 const char *format, va_list ap)
176 jsval *sp;
177 JSBool required;
178 char c;
179 JSFunction *fun;
180 jsdouble d;
181 JSString *str;
182 JSObject *obj;
184 CHECK_REQUEST(cx);
185 sp = argv;
186 required = JS_TRUE;
187 while ((c = *format++) != '\0') {
188 if (isspace(c))
189 continue;
190 if (c == '/') {
191 required = JS_FALSE;
192 continue;
194 if (sp == argv + argc) {
195 if (required) {
196 fun = js_ValueToFunction(cx, &argv[-2], 0);
197 if (fun) {
198 char numBuf[12];
199 JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
200 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
201 JSMSG_MORE_ARGS_NEEDED,
202 JS_GetFunctionName(fun), numBuf,
203 (argc == 1) ? "" : "s");
205 return JS_FALSE;
207 break;
209 switch (c) {
210 case 'b':
211 *va_arg(ap, JSBool *) = js_ValueToBoolean(*sp);
212 break;
213 case 'c':
214 if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
215 return JS_FALSE;
216 break;
217 case 'i':
218 if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
219 return JS_FALSE;
220 break;
221 case 'u':
222 if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
223 return JS_FALSE;
224 break;
225 case 'j':
226 if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
227 return JS_FALSE;
228 break;
229 case 'd':
230 if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
231 return JS_FALSE;
232 break;
233 case 'I':
234 if (!JS_ValueToNumber(cx, *sp, &d))
235 return JS_FALSE;
236 *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
237 break;
238 case 's':
239 case 'S':
240 case 'W':
241 str = js_ValueToString(cx, *sp);
242 if (!str)
243 return JS_FALSE;
244 *sp = STRING_TO_JSVAL(str);
245 if (c == 's') {
246 const char *bytes = js_GetStringBytes(cx, str);
247 if (!bytes)
248 return JS_FALSE;
249 *va_arg(ap, const char **) = bytes;
250 } else if (c == 'W') {
251 const jschar *chars = js_GetStringChars(cx, str);
252 if (!chars)
253 return JS_FALSE;
254 *va_arg(ap, const jschar **) = chars;
255 } else {
256 *va_arg(ap, JSString **) = str;
258 break;
259 case 'o':
260 if (!js_ValueToObject(cx, *sp, &obj))
261 return JS_FALSE;
262 *sp = OBJECT_TO_JSVAL(obj);
263 *va_arg(ap, JSObject **) = obj;
264 break;
265 case 'f':
266 obj = js_ValueToFunctionObject(cx, sp, 0);
267 if (!obj)
268 return JS_FALSE;
269 *sp = OBJECT_TO_JSVAL(obj);
270 *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj);
271 break;
272 case 'v':
273 *va_arg(ap, jsval *) = *sp;
274 break;
275 case '*':
276 break;
277 default:
278 format--;
279 if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
280 JS_ADDRESSOF_VA_LIST(ap))) {
281 return JS_FALSE;
283 /* NB: the formatter already updated sp, so we continue here. */
284 continue;
286 sp++;
288 return JS_TRUE;
291 JS_PUBLIC_API(jsval *)
292 JS_PushArguments(JSContext *cx, void **markp, const char *format, ...)
294 va_list ap;
295 jsval *argv;
297 va_start(ap, format);
298 argv = JS_PushArgumentsVA(cx, markp, format, ap);
299 va_end(ap);
300 return argv;
303 JS_PUBLIC_API(jsval *)
304 JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap)
306 uintN argc;
307 jsval *argv, *sp;
308 char c;
309 const char *cp;
310 JSString *str;
311 JSFunction *fun;
312 JSStackHeader *sh;
314 CHECK_REQUEST(cx);
315 *markp = NULL;
316 argc = 0;
317 for (cp = format; (c = *cp) != '\0'; cp++) {
319 * Count non-space non-star characters as individual jsval arguments.
320 * This may over-allocate stack, but we'll fix below.
322 if (isspace(c) || c == '*')
323 continue;
324 argc++;
326 sp = js_AllocStack(cx, argc, markp);
327 if (!sp)
328 return NULL;
329 argv = sp;
330 while ((c = *format++) != '\0') {
331 if (isspace(c) || c == '*')
332 continue;
333 switch (c) {
334 case 'b':
335 *sp = BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int));
336 break;
337 case 'c':
338 *sp = INT_TO_JSVAL((uint16) va_arg(ap, unsigned int));
339 break;
340 case 'i':
341 case 'j':
343 * Use JS_New{Double,Number}Value here and in the next two cases,
344 * not js_New{Double,Number}InRootedValue, as sp may point to an
345 * unrooted location.
347 if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp))
348 goto bad;
349 break;
350 case 'u':
351 if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp))
352 goto bad;
353 break;
354 case 'd':
355 case 'I':
356 if (!JS_NewDoubleValue(cx, va_arg(ap, jsdouble), sp))
357 goto bad;
358 break;
359 case 's':
360 str = JS_NewStringCopyZ(cx, va_arg(ap, char *));
361 if (!str)
362 goto bad;
363 *sp = STRING_TO_JSVAL(str);
364 break;
365 case 'W':
366 str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *));
367 if (!str)
368 goto bad;
369 *sp = STRING_TO_JSVAL(str);
370 break;
371 case 'S':
372 str = va_arg(ap, JSString *);
373 *sp = STRING_TO_JSVAL(str);
374 break;
375 case 'o':
376 *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *));
377 break;
378 case 'f':
379 fun = va_arg(ap, JSFunction *);
380 *sp = fun ? OBJECT_TO_JSVAL(FUN_OBJECT(fun)) : JSVAL_NULL;
381 break;
382 case 'v':
383 *sp = va_arg(ap, jsval);
384 break;
385 default:
386 format--;
387 if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp,
388 JS_ADDRESSOF_VA_LIST(ap))) {
389 goto bad;
391 /* NB: the formatter already updated sp, so we continue here. */
392 continue;
394 sp++;
398 * We may have overallocated stack due to a multi-character format code
399 * handled by a JSArgumentFormatter. Give back that stack space!
401 JS_ASSERT(sp <= argv + argc);
402 if (sp < argv + argc) {
403 /* Return slots not pushed to the current stack arena. */
404 cx->stackPool.current->avail = (jsuword)sp;
406 /* Reduce the count of slots the GC will scan in this stack segment. */
407 sh = cx->stackHeaders;
408 JS_ASSERT(JS_STACK_SEGMENT(sh) + sh->nslots == argv + argc);
409 sh->nslots -= argc - (sp - argv);
411 return argv;
413 bad:
414 js_FreeStack(cx, *markp);
415 return NULL;
418 JS_PUBLIC_API(void)
419 JS_PopArguments(JSContext *cx, void *mark)
421 CHECK_REQUEST(cx);
422 js_FreeStack(cx, mark);
425 JS_PUBLIC_API(JSBool)
426 JS_AddArgumentFormatter(JSContext *cx, const char *format,
427 JSArgumentFormatter formatter)
429 size_t length;
430 JSArgumentFormatMap **mpp, *map;
432 length = strlen(format);
433 mpp = &cx->argumentFormatMap;
434 while ((map = *mpp) != NULL) {
435 /* Insert before any shorter string to match before prefixes. */
436 if (map->length < length)
437 break;
438 if (map->length == length && !strcmp(map->format, format))
439 goto out;
440 mpp = &map->next;
442 map = (JSArgumentFormatMap *) JS_malloc(cx, sizeof *map);
443 if (!map)
444 return JS_FALSE;
445 map->format = format;
446 map->length = length;
447 map->next = *mpp;
448 *mpp = map;
449 out:
450 map->formatter = formatter;
451 return JS_TRUE;
454 JS_PUBLIC_API(void)
455 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
457 size_t length;
458 JSArgumentFormatMap **mpp, *map;
460 length = strlen(format);
461 mpp = &cx->argumentFormatMap;
462 while ((map = *mpp) != NULL) {
463 if (map->length == length && !strcmp(map->format, format)) {
464 *mpp = map->next;
465 JS_free(cx, map);
466 return;
468 mpp = &map->next;
472 JS_PUBLIC_API(JSBool)
473 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
475 JSBool ok;
476 JSObject *obj;
477 JSString *str;
478 jsdouble d, *dp;
480 CHECK_REQUEST(cx);
481 switch (type) {
482 case JSTYPE_VOID:
483 *vp = JSVAL_VOID;
484 ok = JS_TRUE;
485 break;
486 case JSTYPE_OBJECT:
487 ok = js_ValueToObject(cx, v, &obj);
488 if (ok)
489 *vp = OBJECT_TO_JSVAL(obj);
490 break;
491 case JSTYPE_FUNCTION:
492 *vp = v;
493 obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK);
494 ok = (obj != NULL);
495 break;
496 case JSTYPE_STRING:
497 str = js_ValueToString(cx, v);
498 ok = (str != NULL);
499 if (ok)
500 *vp = STRING_TO_JSVAL(str);
501 break;
502 case JSTYPE_NUMBER:
503 ok = JS_ValueToNumber(cx, v, &d);
504 if (ok) {
505 dp = js_NewWeaklyRootedDouble(cx, d);
506 ok = (dp != NULL);
507 if (ok)
508 *vp = DOUBLE_TO_JSVAL(dp);
510 break;
511 case JSTYPE_BOOLEAN:
512 *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(v));
513 return JS_TRUE;
514 default: {
515 char numBuf[12];
516 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
517 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
518 numBuf);
519 ok = JS_FALSE;
520 break;
523 return ok;
526 JS_PUBLIC_API(JSBool)
527 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
529 CHECK_REQUEST(cx);
530 return js_ValueToObject(cx, v, objp);
533 JS_PUBLIC_API(JSFunction *)
534 JS_ValueToFunction(JSContext *cx, jsval v)
536 CHECK_REQUEST(cx);
537 return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
540 JS_PUBLIC_API(JSFunction *)
541 JS_ValueToConstructor(JSContext *cx, jsval v)
543 CHECK_REQUEST(cx);
544 return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
547 JS_PUBLIC_API(JSString *)
548 JS_ValueToString(JSContext *cx, jsval v)
550 CHECK_REQUEST(cx);
551 return js_ValueToString(cx, v);
554 JS_PUBLIC_API(JSString *)
555 JS_ValueToSource(JSContext *cx, jsval v)
557 CHECK_REQUEST(cx);
558 return js_ValueToSource(cx, v);
561 JS_PUBLIC_API(JSBool)
562 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
564 JSTempValueRooter tvr;
566 CHECK_REQUEST(cx);
567 JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
568 *dp = js_ValueToNumber(cx, &tvr.u.value);
569 JS_POP_TEMP_ROOT(cx, &tvr);
570 return !JSVAL_IS_NULL(tvr.u.value);
573 JS_PUBLIC_API(JSBool)
574 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
576 JSTempValueRooter tvr;
578 CHECK_REQUEST(cx);
579 JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
580 *ip = js_ValueToECMAInt32(cx, &tvr.u.value);
581 JS_POP_TEMP_ROOT(cx, &tvr);
582 return !JSVAL_IS_NULL(tvr.u.value);
585 JS_PUBLIC_API(JSBool)
586 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
588 JSTempValueRooter tvr;
590 CHECK_REQUEST(cx);
591 JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
592 *ip = js_ValueToECMAUint32(cx, &tvr.u.value);
593 JS_POP_TEMP_ROOT(cx, &tvr);
594 return !JSVAL_IS_NULL(tvr.u.value);
597 JS_PUBLIC_API(JSBool)
598 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
600 JSTempValueRooter tvr;
602 CHECK_REQUEST(cx);
603 JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
604 *ip = js_ValueToInt32(cx, &tvr.u.value);
605 JS_POP_TEMP_ROOT(cx, &tvr);
606 return !JSVAL_IS_NULL(tvr.u.value);
609 JS_PUBLIC_API(JSBool)
610 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
612 JSTempValueRooter tvr;
614 CHECK_REQUEST(cx);
615 JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
616 *ip = js_ValueToUint16(cx, &tvr.u.value);
617 JS_POP_TEMP_ROOT(cx, &tvr);
618 return !JSVAL_IS_NULL(tvr.u.value);
621 JS_PUBLIC_API(JSBool)
622 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
624 CHECK_REQUEST(cx);
625 *bp = js_ValueToBoolean(v);
626 return JS_TRUE;
629 JS_PUBLIC_API(JSType)
630 JS_TypeOfValue(JSContext *cx, jsval v)
632 JSType type;
633 JSObject *obj;
634 JSObjectOps *ops;
635 JSClass *clasp;
637 CHECK_REQUEST(cx);
638 if (JSVAL_IS_OBJECT(v)) {
639 type = JSTYPE_OBJECT; /* XXXbe JSTYPE_NULL for JS2 */
640 obj = JSVAL_TO_OBJECT(v);
641 if (obj) {
642 JSObject *wrapped;
644 wrapped = js_GetWrappedObject(cx, obj);
645 if (wrapped)
646 obj = wrapped;
648 ops = obj->map->ops;
649 #if JS_HAS_XML_SUPPORT
650 if (ops == &js_XMLObjectOps.base) {
651 type = JSTYPE_XML;
652 } else
653 #endif
656 * ECMA 262, 11.4.3 says that any native object that implements
657 * [[Call]] should be of type "function". Note that RegExp and
658 * Script are both of type "function" for compatibility with
659 * older SpiderMonkeys.
661 clasp = OBJ_GET_CLASS(cx, obj);
662 if ((ops == &js_ObjectOps)
663 ? (clasp->call
664 ? clasp == &js_ScriptClass
665 : clasp == &js_FunctionClass)
666 : ops->call != NULL) {
667 type = JSTYPE_FUNCTION;
668 } else {
669 #ifdef NARCISSUS
670 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
672 if (!OBJ_GET_PROPERTY(cx, obj,
673 ATOM_TO_JSID(cx->runtime->atomState
674 .__call__Atom),
675 &v)) {
676 JS_ClearPendingException(cx);
677 } else if (VALUE_IS_FUNCTION(cx, v)) {
678 type = JSTYPE_FUNCTION;
680 #endif
684 } else if (JSVAL_IS_NUMBER(v)) {
685 type = JSTYPE_NUMBER;
686 } else if (JSVAL_IS_STRING(v)) {
687 type = JSTYPE_STRING;
688 } else if (JSVAL_IS_BOOLEAN(v)) {
689 type = JSTYPE_BOOLEAN;
690 } else {
691 type = JSTYPE_VOID;
693 return type;
696 JS_PUBLIC_API(const char *)
697 JS_GetTypeName(JSContext *cx, JSType type)
699 if ((uintN)type >= (uintN)JSTYPE_LIMIT)
700 return NULL;
701 return JS_TYPE_STR(type);
704 /************************************************************************/
707 * Has a new runtime ever been created? This flag is used to detect unsafe
708 * changes to js_CStringsAreUTF8 after a runtime has been created, and to
709 * ensure that "first checks" on runtime creation are run only once.
711 #ifdef DEBUG
712 static JSBool js_NewRuntimeWasCalled = JS_FALSE;
713 #endif
715 JS_PUBLIC_API(JSRuntime *)
716 JS_NewRuntime(uint32 maxbytes)
718 JSRuntime *rt;
720 #ifdef DEBUG
721 if (!js_NewRuntimeWasCalled) {
723 * This code asserts that the numbers associated with the error names
724 * in jsmsg.def are monotonically increasing. It uses values for the
725 * error names enumerated in jscntxt.c. It's not a compile-time check
726 * but it's better than nothing.
728 int errorNumber = 0;
729 #define MSG_DEF(name, number, count, exception, format) \
730 JS_ASSERT(name == errorNumber++);
731 #include "js.msg"
732 #undef MSG_DEF
734 #define MSG_DEF(name, number, count, exception, format) \
735 JS_BEGIN_MACRO \
736 uintN numfmtspecs = 0; \
737 const char *fmt; \
738 for (fmt = format; *fmt != '\0'; fmt++) { \
739 if (*fmt == '{' && isdigit(fmt[1])) \
740 ++numfmtspecs; \
742 JS_ASSERT(count == numfmtspecs); \
743 JS_END_MACRO;
744 #include "js.msg"
745 #undef MSG_DEF
747 js_NewRuntimeWasCalled = JS_TRUE;
749 #endif /* DEBUG */
751 rt = (JSRuntime *) malloc(sizeof(JSRuntime));
752 if (!rt)
753 return NULL;
755 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
756 memset(rt, 0, sizeof(JSRuntime));
757 JS_INIT_CLIST(&rt->contextList);
758 JS_INIT_CLIST(&rt->trapList);
759 JS_INIT_CLIST(&rt->watchPointList);
761 if (!js_InitDtoa())
762 goto bad;
763 if (!js_InitGC(rt, maxbytes))
764 goto bad;
765 if (!js_InitAtomState(rt))
766 goto bad;
767 if (!js_InitDeflatedStringCache(rt))
768 goto bad;
769 #ifdef JS_THREADSAFE
770 if (!js_InitThreadPrivateIndex(js_ThreadDestructorCB))
771 goto bad;
772 rt->gcLock = JS_NEW_LOCK();
773 if (!rt->gcLock)
774 goto bad;
775 rt->gcDone = JS_NEW_CONDVAR(rt->gcLock);
776 if (!rt->gcDone)
777 goto bad;
778 rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
779 if (!rt->requestDone)
780 goto bad;
781 /* this is asymmetric with JS_ShutDown: */
782 if (!js_SetupLocks(8, 16))
783 goto bad;
784 rt->rtLock = JS_NEW_LOCK();
785 if (!rt->rtLock)
786 goto bad;
787 rt->stateChange = JS_NEW_CONDVAR(rt->gcLock);
788 if (!rt->stateChange)
789 goto bad;
790 rt->titleSharingDone = JS_NEW_CONDVAR(rt->gcLock);
791 if (!rt->titleSharingDone)
792 goto bad;
793 rt->titleSharingTodo = NO_TITLE_SHARING_TODO;
794 rt->debuggerLock = JS_NEW_LOCK();
795 if (!rt->debuggerLock)
796 goto bad;
797 #endif
798 if (!js_InitPropertyTree(rt))
799 goto bad;
801 #if !defined JS_THREADSAFE && defined JS_TRACER
802 js_InitJIT(&rt->traceMonitor);
803 #endif
805 return rt;
807 bad:
808 JS_DestroyRuntime(rt);
809 return NULL;
812 JS_PUBLIC_API(void)
813 JS_DestroyRuntime(JSRuntime *rt)
815 #ifdef DEBUG
816 /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
817 if (!JS_CLIST_IS_EMPTY(&rt->contextList)) {
818 JSContext *cx, *iter = NULL;
819 uintN cxcount = 0;
820 while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL) {
821 fprintf(stderr,
822 "JS API usage error: found live context at %p\n",
823 (void *) cx);
824 cxcount++;
826 fprintf(stderr,
827 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
828 cxcount, (cxcount == 1) ? "" : "s");
830 #endif
832 #if !defined JS_THREADSAFE && defined JS_TRACER
833 js_FinishJIT(&rt->traceMonitor);
834 #endif
836 js_FreeRuntimeScriptState(rt);
837 js_FinishAtomState(rt);
840 * Free unit string storage only after all strings have been finalized, so
841 * that js_FinalizeString can detect unit strings and avoid calling free
842 * on their chars storage.
844 js_FinishUnitStrings(rt);
847 * Finish the deflated string cache after the last GC and after
848 * calling js_FinishAtomState, which finalizes strings.
850 js_FinishDeflatedStringCache(rt);
851 js_FinishGC(rt);
852 #ifdef JS_THREADSAFE
853 if (rt->gcLock)
854 JS_DESTROY_LOCK(rt->gcLock);
855 if (rt->gcDone)
856 JS_DESTROY_CONDVAR(rt->gcDone);
857 if (rt->requestDone)
858 JS_DESTROY_CONDVAR(rt->requestDone);
859 if (rt->rtLock)
860 JS_DESTROY_LOCK(rt->rtLock);
861 if (rt->stateChange)
862 JS_DESTROY_CONDVAR(rt->stateChange);
863 if (rt->titleSharingDone)
864 JS_DESTROY_CONDVAR(rt->titleSharingDone);
865 if (rt->debuggerLock)
866 JS_DESTROY_LOCK(rt->debuggerLock);
867 #else
868 GSN_CACHE_CLEAR(&rt->gsnCache);
869 #endif
870 js_FinishPropertyTree(rt);
871 free(rt);
874 JS_PUBLIC_API(void)
875 JS_ShutDown(void)
877 #ifdef JS_OPMETER
878 extern void js_DumpOpMeters();
880 js_DumpOpMeters();
881 #endif
883 js_FinishDtoa();
884 #ifdef JS_THREADSAFE
885 js_CleanupThreadPrivateData(); /* Fixes bug 464828. */
886 js_CleanupLocks();
887 #endif
888 PRMJ_NowShutdown();
891 JS_PUBLIC_API(void *)
892 JS_GetRuntimePrivate(JSRuntime *rt)
894 return rt->data;
897 JS_PUBLIC_API(void)
898 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
900 rt->data = data;
903 JS_PUBLIC_API(void)
904 JS_BeginRequest(JSContext *cx)
906 #ifdef JS_THREADSAFE
907 JSRuntime *rt;
909 JS_ASSERT(cx->thread->id == js_CurrentThreadId());
910 if (!cx->requestDepth) {
911 JS_ASSERT(cx->gcLocalFreeLists == &js_GCEmptyFreeListSet);
913 /* Wait until the GC is finished. */
914 rt = cx->runtime;
915 JS_LOCK_GC(rt);
917 /* NB: we use cx->thread here, not js_GetCurrentThread(). */
918 if (rt->gcThread != cx->thread) {
919 while (rt->gcLevel > 0)
920 JS_AWAIT_GC_DONE(rt);
923 /* Indicate that a request is running. */
924 rt->requestCount++;
925 cx->requestDepth = 1;
926 cx->outstandingRequests++;
927 JS_UNLOCK_GC(rt);
928 return;
930 cx->requestDepth++;
931 cx->outstandingRequests++;
932 #endif
935 JS_PUBLIC_API(void)
936 JS_EndRequest(JSContext *cx)
938 #ifdef JS_THREADSAFE
939 JSRuntime *rt;
940 JSTitle *title, **todop;
941 JSBool shared;
943 CHECK_REQUEST(cx);
944 JS_ASSERT(cx->requestDepth > 0);
945 JS_ASSERT(cx->outstandingRequests > 0);
946 if (cx->requestDepth == 1) {
947 /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
948 rt = cx->runtime;
949 JS_LOCK_GC(rt);
950 cx->requestDepth = 0;
951 cx->outstandingRequests--;
953 /* See whether cx has any single-threaded titles to start sharing. */
954 todop = &rt->titleSharingTodo;
955 shared = JS_FALSE;
956 while ((title = *todop) != NO_TITLE_SHARING_TODO) {
957 if (title->ownercx != cx) {
958 todop = &title->u.link;
959 continue;
961 *todop = title->u.link;
962 title->u.link = NULL; /* null u.link for sanity ASAP */
965 * If js_DropObjectMap returns null, we held the last ref to scope.
966 * The waiting thread(s) must have been killed, after which the GC
967 * collected the object that held this scope. Unlikely, because it
968 * requires that the GC ran (e.g., from an operation callback)
969 * during this request, but possible.
971 if (js_DropObjectMap(cx, TITLE_TO_MAP(title), NULL)) {
972 js_InitLock(&title->lock);
973 title->u.count = 0; /* NULL may not pun as 0 */
974 js_FinishSharingTitle(cx, title); /* set ownercx = NULL */
975 shared = JS_TRUE;
978 if (shared)
979 JS_NOTIFY_ALL_CONDVAR(rt->titleSharingDone);
981 js_RevokeGCLocalFreeLists(cx);
983 /* Give the GC a chance to run if this was the last request running. */
984 JS_ASSERT(rt->requestCount > 0);
985 rt->requestCount--;
986 if (rt->requestCount == 0)
987 JS_NOTIFY_REQUEST_DONE(rt);
989 JS_UNLOCK_GC(rt);
990 return;
993 cx->requestDepth--;
994 cx->outstandingRequests--;
995 #endif
998 /* Yield to pending GC operations, regardless of request depth */
999 JS_PUBLIC_API(void)
1000 JS_YieldRequest(JSContext *cx)
1002 #ifdef JS_THREADSAFE
1003 JS_ASSERT(cx->thread);
1004 CHECK_REQUEST(cx);
1005 JS_ResumeRequest(cx, JS_SuspendRequest(cx));
1006 #endif
1009 JS_PUBLIC_API(jsrefcount)
1010 JS_SuspendRequest(JSContext *cx)
1012 #ifdef JS_THREADSAFE
1013 jsrefcount saveDepth = cx->requestDepth;
1015 while (cx->requestDepth) {
1016 cx->outstandingRequests++; /* compensate for JS_EndRequest */
1017 JS_EndRequest(cx);
1019 return saveDepth;
1020 #else
1021 return 0;
1022 #endif
1025 JS_PUBLIC_API(void)
1026 JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
1028 #ifdef JS_THREADSAFE
1029 JS_ASSERT(!cx->requestDepth);
1030 while (--saveDepth >= 0) {
1031 JS_BeginRequest(cx);
1032 cx->outstandingRequests--; /* compensate for JS_BeginRequest */
1034 #endif
1037 JS_PUBLIC_API(void)
1038 JS_Lock(JSRuntime *rt)
1040 JS_LOCK_RUNTIME(rt);
1043 JS_PUBLIC_API(void)
1044 JS_Unlock(JSRuntime *rt)
1046 JS_UNLOCK_RUNTIME(rt);
1049 JS_PUBLIC_API(JSContextCallback)
1050 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
1052 JSContextCallback old;
1054 old = rt->cxCallback;
1055 rt->cxCallback = cxCallback;
1056 return old;
1059 JS_PUBLIC_API(JSContext *)
1060 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
1062 return js_NewContext(rt, stackChunkSize);
1065 JS_PUBLIC_API(void)
1066 JS_DestroyContext(JSContext *cx)
1068 js_DestroyContext(cx, JSDCM_FORCE_GC);
1071 JS_PUBLIC_API(void)
1072 JS_DestroyContextNoGC(JSContext *cx)
1074 js_DestroyContext(cx, JSDCM_NO_GC);
1077 JS_PUBLIC_API(void)
1078 JS_DestroyContextMaybeGC(JSContext *cx)
1080 js_DestroyContext(cx, JSDCM_MAYBE_GC);
1083 JS_PUBLIC_API(void *)
1084 JS_GetContextPrivate(JSContext *cx)
1086 return cx->data;
1089 JS_PUBLIC_API(void)
1090 JS_SetContextPrivate(JSContext *cx, void *data)
1092 cx->data = data;
1095 JS_PUBLIC_API(JSRuntime *)
1096 JS_GetRuntime(JSContext *cx)
1098 return cx->runtime;
1101 JS_PUBLIC_API(JSContext *)
1102 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
1104 return js_ContextIterator(rt, JS_TRUE, iterp);
1107 JS_PUBLIC_API(JSVersion)
1108 JS_GetVersion(JSContext *cx)
1110 return JSVERSION_NUMBER(cx);
1113 JS_PUBLIC_API(JSVersion)
1114 JS_SetVersion(JSContext *cx, JSVersion version)
1116 JSVersion oldVersion;
1118 JS_ASSERT(version != JSVERSION_UNKNOWN);
1119 JS_ASSERT((version & ~JSVERSION_MASK) == 0);
1121 oldVersion = JSVERSION_NUMBER(cx);
1122 if (version == oldVersion)
1123 return oldVersion;
1125 /* We no longer support 1.4 or below. */
1126 if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4)
1127 return oldVersion;
1129 cx->version = (cx->version & ~JSVERSION_MASK) | version;
1130 js_OnVersionChange(cx);
1131 return oldVersion;
1134 static struct v2smap {
1135 JSVersion version;
1136 const char *string;
1137 } v2smap[] = {
1138 {JSVERSION_1_0, "1.0"},
1139 {JSVERSION_1_1, "1.1"},
1140 {JSVERSION_1_2, "1.2"},
1141 {JSVERSION_1_3, "1.3"},
1142 {JSVERSION_1_4, "1.4"},
1143 {JSVERSION_ECMA_3, "ECMAv3"},
1144 {JSVERSION_1_5, "1.5"},
1145 {JSVERSION_1_6, "1.6"},
1146 {JSVERSION_1_7, "1.7"},
1147 {JSVERSION_1_8, "1.8"},
1148 {JSVERSION_DEFAULT, js_default_str},
1149 {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
1152 JS_PUBLIC_API(const char *)
1153 JS_VersionToString(JSVersion version)
1155 int i;
1157 for (i = 0; v2smap[i].string; i++)
1158 if (v2smap[i].version == version)
1159 return v2smap[i].string;
1160 return "unknown";
1163 JS_PUBLIC_API(JSVersion)
1164 JS_StringToVersion(const char *string)
1166 int i;
1168 for (i = 0; v2smap[i].string; i++)
1169 if (strcmp(v2smap[i].string, string) == 0)
1170 return v2smap[i].version;
1171 return JSVERSION_UNKNOWN;
1174 JS_PUBLIC_API(uint32)
1175 JS_GetOptions(JSContext *cx)
1177 return cx->options;
1180 #define SYNC_OPTIONS_TO_VERSION(cx) \
1181 JS_BEGIN_MACRO \
1182 if ((cx)->options & JSOPTION_XML) \
1183 (cx)->version |= JSVERSION_HAS_XML; \
1184 else \
1185 (cx)->version &= ~JSVERSION_HAS_XML; \
1186 JS_END_MACRO
1188 JS_PUBLIC_API(uint32)
1189 JS_SetOptions(JSContext *cx, uint32 options)
1191 uint32 oldopts = cx->options;
1192 cx->options = options;
1193 SYNC_OPTIONS_TO_VERSION(cx);
1194 return oldopts;
1197 JS_PUBLIC_API(uint32)
1198 JS_ToggleOptions(JSContext *cx, uint32 options)
1200 uint32 oldopts = cx->options;
1201 cx->options ^= options;
1202 SYNC_OPTIONS_TO_VERSION(cx);
1203 return oldopts;
1206 JS_PUBLIC_API(const char *)
1207 JS_GetImplementationVersion(void)
1209 return "JavaScript-C 1.8.0 pre-release 1 2007-10-03";
1213 JS_PUBLIC_API(JSObject *)
1214 JS_GetGlobalObject(JSContext *cx)
1216 return cx->globalObject;
1219 JS_PUBLIC_API(void)
1220 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1222 cx->globalObject = obj;
1224 #if JS_HAS_XML_SUPPORT
1225 cx->xmlSettingFlags = 0;
1226 #endif
1229 JS_BEGIN_EXTERN_C
1231 JSObject *
1232 js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1234 JSDHashTable *table;
1235 JSBool resolving;
1236 JSRuntime *rt;
1237 JSResolvingKey key;
1238 JSResolvingEntry *entry;
1239 JSObject *fun_proto, *obj_proto;
1241 /* If cx has no global object, use obj so prototypes can be found. */
1242 if (!cx->globalObject)
1243 JS_SetGlobalObject(cx, obj);
1245 /* Record Function and Object in cx->resolvingTable, if we are resolving. */
1246 table = cx->resolvingTable;
1247 resolving = (table && table->entryCount);
1248 rt = cx->runtime;
1249 key.obj = obj;
1250 if (resolving) {
1251 key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]);
1252 entry = (JSResolvingEntry *)
1253 JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1254 if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) {
1255 /* Already resolving Function, record Object too. */
1256 JS_ASSERT(entry->key.obj == obj);
1257 key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1258 entry = (JSResolvingEntry *)
1259 JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1261 if (!entry) {
1262 JS_ReportOutOfMemory(cx);
1263 return NULL;
1265 JS_ASSERT(!entry->key.obj && entry->flags == 0);
1266 entry->key = key;
1267 entry->flags = JSRESFLAG_LOOKUP;
1268 } else {
1269 key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1270 if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry))
1271 return NULL;
1273 key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]);
1274 if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) {
1275 key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1276 JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1277 return NULL;
1280 table = cx->resolvingTable;
1283 /* Initialize the function class first so constructors can be made. */
1284 if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Function),
1285 &fun_proto)) {
1286 fun_proto = NULL;
1287 goto out;
1289 if (!fun_proto) {
1290 fun_proto = js_InitFunctionClass(cx, obj);
1291 if (!fun_proto)
1292 goto out;
1293 } else {
1294 JSObject *ctor;
1296 ctor = JS_GetConstructor(cx, fun_proto);
1297 if (!ctor) {
1298 fun_proto = NULL;
1299 goto out;
1301 OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
1302 OBJECT_TO_JSVAL(ctor), 0, 0, 0, NULL);
1305 /* Initialize the object class next so Object.prototype works. */
1306 if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object),
1307 &obj_proto)) {
1308 fun_proto = NULL;
1309 goto out;
1311 if (!obj_proto)
1312 obj_proto = js_InitObjectClass(cx, obj);
1313 if (!obj_proto) {
1314 fun_proto = NULL;
1315 goto out;
1318 /* Function.prototype and the global object delegate to Object.prototype. */
1319 OBJ_SET_PROTO(cx, fun_proto, obj_proto);
1320 if (!OBJ_GET_PROTO(cx, obj))
1321 OBJ_SET_PROTO(cx, obj, obj_proto);
1323 out:
1324 /* If resolving, remove the other entry (Object or Function) from table. */
1325 JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1326 if (!resolving) {
1327 /* If not resolving, remove the first entry added above, for Object. */
1328 JS_ASSERT(key.id == \
1329 ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]));
1330 key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1331 JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1333 return fun_proto;
1336 JS_END_EXTERN_C
1338 JS_PUBLIC_API(JSBool)
1339 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1341 JSAtom *atom;
1343 CHECK_REQUEST(cx);
1345 /* Define a top-level property 'undefined' with the undefined value. */
1346 atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1347 if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1348 NULL, NULL, JSPROP_PERMANENT, NULL)) {
1349 return JS_FALSE;
1352 /* Function and Object require cooperative bootstrapping magic. */
1353 if (!js_InitFunctionAndObjectClasses(cx, obj))
1354 return JS_FALSE;
1356 /* Initialize the rest of the standard objects and functions. */
1357 return js_InitArrayClass(cx, obj) &&
1358 js_InitBlockClass(cx, obj) &&
1359 js_InitBooleanClass(cx, obj) &&
1360 js_InitCallClass(cx, obj) &&
1361 js_InitExceptionClasses(cx, obj) &&
1362 js_InitMathClass(cx, obj) &&
1363 js_InitNumberClass(cx, obj) &&
1364 js_InitJSONClass(cx, obj) &&
1365 js_InitRegExpClass(cx, obj) &&
1366 js_InitStringClass(cx, obj) &&
1367 js_InitEval(cx, obj) &&
1368 #if JS_HAS_SCRIPT_OBJECT
1369 js_InitScriptClass(cx, obj) &&
1370 #endif
1371 #if JS_HAS_XML_SUPPORT
1372 js_InitXMLClasses(cx, obj) &&
1373 #endif
1374 #if JS_HAS_FILE_OBJECT
1375 js_InitFileClass(cx, obj) &&
1376 #endif
1377 #if JS_HAS_GENERATORS
1378 js_InitIteratorClasses(cx, obj) &&
1379 #endif
1380 js_InitDateClass(cx, obj);
1383 #define CLASP(name) (&js_##name##Class)
1384 #define EXT_CLASP(name) (&js_##name##Class.base)
1385 #define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
1386 #define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
1387 #define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
1388 #define EAGER_ATOM_AND_EXT_CLASP(name) EAGER_CLASS_ATOM(name), EXT_CLASP(name)
1389 #define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
1391 typedef struct JSStdName {
1392 JSObjectOp init;
1393 size_t atomOffset; /* offset of atom pointer in JSAtomState */
1394 const char *name; /* null if atom is pre-pinned, else name */
1395 JSClass *clasp;
1396 } JSStdName;
1398 static JSAtom *
1399 StdNameToAtom(JSContext *cx, JSStdName *stdn)
1401 size_t offset;
1402 JSAtom *atom;
1403 const char *name;
1405 offset = stdn->atomOffset;
1406 atom = OFFSET_TO_ATOM(cx->runtime, offset);
1407 if (!atom) {
1408 name = stdn->name;
1409 if (name) {
1410 atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1411 OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1414 return atom;
1418 * Table of class initializers and their atom offsets in rt->atomState.
1419 * If you add a "standard" class, remember to update this table.
1421 static JSStdName standard_class_atoms[] = {
1422 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Function)},
1423 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Object)},
1424 {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)},
1425 {js_InitBlockClass, EAGER_ATOM_AND_CLASP(Block)},
1426 {js_InitBooleanClass, EAGER_ATOM_AND_CLASP(Boolean)},
1427 {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)},
1428 {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)},
1429 {js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)},
1430 {js_InitStringClass, EAGER_ATOM_AND_CLASP(String)},
1431 {js_InitCallClass, EAGER_ATOM_AND_CLASP(Call)},
1432 {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)},
1433 {js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)},
1434 #if JS_HAS_SCRIPT_OBJECT
1435 {js_InitScriptClass, EAGER_ATOM_AND_CLASP(Script)},
1436 #endif
1437 #if JS_HAS_XML_SUPPORT
1438 {js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)},
1439 {js_InitNamespaceClass, EAGER_ATOM_AND_EXT_CLASP(Namespace)},
1440 {js_InitQNameClass, EAGER_ATOM_AND_EXT_CLASP(QName)},
1441 #endif
1442 #if JS_HAS_FILE_OBJECT
1443 {js_InitFileClass, EAGER_ATOM_AND_CLASP(File)},
1444 #endif
1445 #if JS_HAS_GENERATORS
1446 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
1447 #endif
1448 {js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
1449 {NULL, 0, NULL, NULL}
1453 * Table of top-level function and constant names and their init functions.
1454 * If you add a "standard" global function or property, remember to update
1455 * this table.
1457 static JSStdName standard_class_names[] = {
1458 /* ECMA requires that eval be a direct property of the global object. */
1459 {js_InitEval, EAGER_ATOM(eval), NULL},
1461 /* Global properties and functions defined by the Number class. */
1462 {js_InitNumberClass, LAZY_ATOM(NaN), NULL},
1463 {js_InitNumberClass, LAZY_ATOM(Infinity), NULL},
1464 {js_InitNumberClass, LAZY_ATOM(isNaN), NULL},
1465 {js_InitNumberClass, LAZY_ATOM(isFinite), NULL},
1466 {js_InitNumberClass, LAZY_ATOM(parseFloat), NULL},
1467 {js_InitNumberClass, LAZY_ATOM(parseInt), NULL},
1469 /* String global functions. */
1470 {js_InitStringClass, LAZY_ATOM(escape), NULL},
1471 {js_InitStringClass, LAZY_ATOM(unescape), NULL},
1472 {js_InitStringClass, LAZY_ATOM(decodeURI), NULL},
1473 {js_InitStringClass, LAZY_ATOM(encodeURI), NULL},
1474 {js_InitStringClass, LAZY_ATOM(decodeURIComponent), NULL},
1475 {js_InitStringClass, LAZY_ATOM(encodeURIComponent), NULL},
1476 #if JS_HAS_UNEVAL
1477 {js_InitStringClass, LAZY_ATOM(uneval), NULL},
1478 #endif
1480 /* Exception constructors. */
1481 {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)},
1482 {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
1483 {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
1484 {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
1485 {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
1486 {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
1487 {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
1488 {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)},
1490 #if JS_HAS_XML_SUPPORT
1491 {js_InitAnyNameClass, EAGER_ATOM_AND_CLASP(AnyName)},
1492 {js_InitAttributeNameClass, EAGER_ATOM_AND_CLASP(AttributeName)},
1493 {js_InitXMLClass, LAZY_ATOM(XMLList), &js_XMLClass},
1494 {js_InitXMLClass, LAZY_ATOM(isXMLName), NULL},
1495 #endif
1497 #if JS_HAS_GENERATORS
1498 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)},
1499 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Generator)},
1500 #endif
1502 {NULL, 0, NULL, NULL}
1505 static JSStdName object_prototype_names[] = {
1506 /* Object.prototype properties (global delegates to Object.prototype). */
1507 {js_InitObjectClass, EAGER_ATOM(proto), NULL},
1508 {js_InitObjectClass, EAGER_ATOM(parent), NULL},
1509 {js_InitObjectClass, EAGER_ATOM(count), NULL},
1510 #if JS_HAS_TOSOURCE
1511 {js_InitObjectClass, EAGER_ATOM(toSource), NULL},
1512 #endif
1513 {js_InitObjectClass, EAGER_ATOM(toString), NULL},
1514 {js_InitObjectClass, EAGER_ATOM(toLocaleString), NULL},
1515 {js_InitObjectClass, EAGER_ATOM(valueOf), NULL},
1516 #if JS_HAS_OBJ_WATCHPOINT
1517 {js_InitObjectClass, LAZY_ATOM(watch), NULL},
1518 {js_InitObjectClass, LAZY_ATOM(unwatch), NULL},
1519 #endif
1520 {js_InitObjectClass, LAZY_ATOM(hasOwnProperty), NULL},
1521 {js_InitObjectClass, LAZY_ATOM(isPrototypeOf), NULL},
1522 {js_InitObjectClass, LAZY_ATOM(propertyIsEnumerable), NULL},
1523 #if JS_HAS_GETTER_SETTER
1524 {js_InitObjectClass, LAZY_ATOM(defineGetter), NULL},
1525 {js_InitObjectClass, LAZY_ATOM(defineSetter), NULL},
1526 {js_InitObjectClass, LAZY_ATOM(lookupGetter), NULL},
1527 {js_InitObjectClass, LAZY_ATOM(lookupSetter), NULL},
1528 #endif
1530 {NULL, 0, NULL, NULL}
1533 JS_PUBLIC_API(JSBool)
1534 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
1535 JSBool *resolved)
1537 JSString *idstr;
1538 JSRuntime *rt;
1539 JSAtom *atom;
1540 JSStdName *stdnm;
1541 uintN i;
1543 CHECK_REQUEST(cx);
1544 *resolved = JS_FALSE;
1546 rt = cx->runtime;
1547 JS_ASSERT(rt->state != JSRTS_DOWN);
1548 if (rt->state == JSRTS_LANDING || !JSVAL_IS_STRING(id))
1549 return JS_TRUE;
1551 idstr = JSVAL_TO_STRING(id);
1553 /* Check whether we're resolving 'undefined', and define it if so. */
1554 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1555 if (idstr == ATOM_TO_STRING(atom)) {
1556 *resolved = JS_TRUE;
1557 return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1558 NULL, NULL, JSPROP_PERMANENT, NULL);
1561 /* Try for class constructors/prototypes named by well-known atoms. */
1562 stdnm = NULL;
1563 for (i = 0; standard_class_atoms[i].init; i++) {
1564 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1565 if (idstr == ATOM_TO_STRING(atom)) {
1566 stdnm = &standard_class_atoms[i];
1567 break;
1571 if (!stdnm) {
1572 /* Try less frequently used top-level functions and constants. */
1573 for (i = 0; standard_class_names[i].init; i++) {
1574 atom = StdNameToAtom(cx, &standard_class_names[i]);
1575 if (!atom)
1576 return JS_FALSE;
1577 if (idstr == ATOM_TO_STRING(atom)) {
1578 stdnm = &standard_class_names[i];
1579 break;
1583 if (!stdnm && !OBJ_GET_PROTO(cx, obj)) {
1585 * Try even less frequently used names delegated from the global
1586 * object to Object.prototype, but only if the Object class hasn't
1587 * yet been initialized.
1589 for (i = 0; object_prototype_names[i].init; i++) {
1590 atom = StdNameToAtom(cx, &object_prototype_names[i]);
1591 if (!atom)
1592 return JS_FALSE;
1593 if (idstr == ATOM_TO_STRING(atom)) {
1594 stdnm = &standard_class_names[i];
1595 break;
1601 if (stdnm) {
1603 * If this standard class is anonymous and obj advertises itself as a
1604 * global object (in order to reserve slots for standard class object
1605 * pointers), then we don't want to resolve by name.
1607 * If inversely, either id does not name a class, or id does not name
1608 * an anonymous class, or the global does not reserve slots for class
1609 * objects, then we must call the init hook here.
1611 if (stdnm->clasp &&
1612 (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS) &&
1613 (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL)) {
1614 return JS_TRUE;
1617 if (!stdnm->init(cx, obj))
1618 return JS_FALSE;
1619 *resolved = JS_TRUE;
1621 return JS_TRUE;
1624 static JSBool
1625 AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom)
1627 JSScopeProperty *sprop;
1628 JSScope *scope;
1630 JS_ASSERT(OBJ_IS_NATIVE(obj));
1631 JS_LOCK_OBJ(cx, obj);
1632 scope = OBJ_SCOPE(obj);
1633 sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom));
1634 JS_UNLOCK_SCOPE(cx, scope);
1635 return sprop != NULL;
1638 JS_PUBLIC_API(JSBool)
1639 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1641 JSRuntime *rt;
1642 JSAtom *atom;
1643 uintN i;
1645 CHECK_REQUEST(cx);
1646 rt = cx->runtime;
1648 /* Check whether we need to bind 'undefined' and define it if so. */
1649 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1650 if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1651 !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1652 NULL, NULL, JSPROP_PERMANENT, NULL)) {
1653 return JS_FALSE;
1656 /* Initialize any classes that have not been resolved yet. */
1657 for (i = 0; standard_class_atoms[i].init; i++) {
1658 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1659 if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1660 !standard_class_atoms[i].init(cx, obj)) {
1661 return JS_FALSE;
1665 return JS_TRUE;
1668 static JSIdArray *
1669 NewIdArray(JSContext *cx, jsint length)
1671 JSIdArray *ida;
1673 ida = (JSIdArray *)
1674 JS_malloc(cx, offsetof(JSIdArray, vector) + length * sizeof(jsval));
1675 if (ida)
1676 ida->length = length;
1677 return ida;
1681 * Unlike realloc(3), this function frees ida on failure.
1683 static JSIdArray *
1684 SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
1686 JSIdArray *rida;
1688 rida = (JSIdArray *)
1689 JS_realloc(cx, ida,
1690 offsetof(JSIdArray, vector) + length * sizeof(jsval));
1691 if (!rida)
1692 JS_DestroyIdArray(cx, ida);
1693 else
1694 rida->length = length;
1695 return rida;
1698 static JSIdArray *
1699 AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1701 jsint i, length;
1703 i = *ip;
1704 length = ida->length;
1705 if (i >= length) {
1706 ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
1707 if (!ida)
1708 return NULL;
1709 JS_ASSERT(i < ida->length);
1711 ida->vector[i] = ATOM_TO_JSID(atom);
1712 *ip = i + 1;
1713 return ida;
1716 static JSIdArray *
1717 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
1718 jsint *ip, JSBool *foundp)
1720 *foundp = AlreadyHasOwnProperty(cx, obj, atom);
1721 if (*foundp)
1722 ida = AddAtomToArray(cx, atom, ida, ip);
1723 return ida;
1726 JS_PUBLIC_API(JSIdArray *)
1727 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
1728 JSIdArray *ida)
1730 JSRuntime *rt;
1731 jsint i, j, k;
1732 JSAtom *atom;
1733 JSBool found;
1734 JSObjectOp init;
1736 CHECK_REQUEST(cx);
1737 rt = cx->runtime;
1738 if (ida) {
1739 i = ida->length;
1740 } else {
1741 ida = NewIdArray(cx, 8);
1742 if (!ida)
1743 return NULL;
1744 i = 0;
1747 /* Check whether 'undefined' has been resolved and enumerate it if so. */
1748 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1749 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1750 if (!ida)
1751 return NULL;
1753 /* Enumerate only classes that *have* been resolved. */
1754 for (j = 0; standard_class_atoms[j].init; j++) {
1755 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
1756 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1757 if (!ida)
1758 return NULL;
1760 if (found) {
1761 init = standard_class_atoms[j].init;
1763 for (k = 0; standard_class_names[k].init; k++) {
1764 if (standard_class_names[k].init == init) {
1765 atom = StdNameToAtom(cx, &standard_class_names[k]);
1766 ida = AddAtomToArray(cx, atom, ida, &i);
1767 if (!ida)
1768 return NULL;
1772 if (init == js_InitObjectClass) {
1773 for (k = 0; object_prototype_names[k].init; k++) {
1774 atom = StdNameToAtom(cx, &object_prototype_names[k]);
1775 ida = AddAtomToArray(cx, atom, ida, &i);
1776 if (!ida)
1777 return NULL;
1783 /* Trim to exact length. */
1784 return SetIdArrayLength(cx, ida, i);
1787 #undef CLASP
1788 #undef EAGER_ATOM
1789 #undef EAGER_CLASS_ATOM
1790 #undef EAGER_ATOM_CLASP
1791 #undef LAZY_ATOM
1793 JS_PUBLIC_API(JSBool)
1794 JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
1795 JSObject **objp)
1797 CHECK_REQUEST(cx);
1798 return js_GetClassObject(cx, obj, key, objp);
1801 JS_PUBLIC_API(JSObject *)
1802 JS_GetScopeChain(JSContext *cx)
1804 JSStackFrame *fp;
1806 CHECK_REQUEST(cx);
1807 fp = js_GetTopStackFrame(cx);
1808 if (!fp) {
1810 * There is no code active on this context. In place of an actual
1811 * scope chain, use the context's global object, which is set in
1812 * js_InitFunctionAndObjectClasses, and which represents the default
1813 * scope chain for the embedding. See also js_FindClassObject.
1815 * For embeddings that use the inner and outer object hooks, the inner
1816 * object represents the ultimate global object, with the outer object
1817 * acting as a stand-in.
1819 JSObject *obj = cx->globalObject;
1820 if (!obj) {
1821 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
1822 return NULL;
1825 OBJ_TO_INNER_OBJECT(cx, obj);
1826 return obj;
1828 return js_GetScopeChain(cx, fp);
1831 JS_PUBLIC_API(JSObject *)
1832 JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
1834 JSObject *parent;
1836 while ((parent = OBJ_GET_PARENT(cx, obj)) != NULL)
1837 obj = parent;
1838 return obj;
1841 JS_PUBLIC_API(jsval)
1842 JS_ComputeThis(JSContext *cx, jsval *vp)
1844 if (!js_ComputeThis(cx, JS_FALSE, vp + 2))
1845 return JSVAL_NULL;
1846 return vp[1];
1849 JS_PUBLIC_API(void *)
1850 JS_malloc(JSContext *cx, size_t nbytes)
1852 void *p;
1854 JS_ASSERT(nbytes != 0);
1855 JS_COUNT_OPERATION(cx, JSOW_ALLOCATION);
1856 if (nbytes == 0)
1857 nbytes = 1;
1859 p = malloc(nbytes);
1860 if (!p) {
1861 JS_ReportOutOfMemory(cx);
1862 return NULL;
1864 js_UpdateMallocCounter(cx, nbytes);
1866 return p;
1869 JS_PUBLIC_API(void *)
1870 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1872 JS_COUNT_OPERATION(cx, JSOW_ALLOCATION);
1873 p = realloc(p, nbytes);
1874 if (!p)
1875 JS_ReportOutOfMemory(cx);
1876 return p;
1879 JS_PUBLIC_API(void)
1880 JS_free(JSContext *cx, void *p)
1882 if (p)
1883 free(p);
1886 JS_PUBLIC_API(char *)
1887 JS_strdup(JSContext *cx, const char *s)
1889 size_t n;
1890 void *p;
1892 n = strlen(s) + 1;
1893 p = JS_malloc(cx, n);
1894 if (!p)
1895 return NULL;
1896 return (char *)memcpy(p, s, n);
1899 JS_PUBLIC_API(jsdouble *)
1900 JS_NewDouble(JSContext *cx, jsdouble d)
1902 CHECK_REQUEST(cx);
1903 return js_NewWeaklyRootedDouble(cx, d);
1906 JS_PUBLIC_API(JSBool)
1907 JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
1909 jsdouble *dp;
1911 CHECK_REQUEST(cx);
1912 dp = js_NewWeaklyRootedDouble(cx, d);
1913 if (!dp)
1914 return JS_FALSE;
1915 *rval = DOUBLE_TO_JSVAL(dp);
1916 return JS_TRUE;
1919 JS_PUBLIC_API(JSBool)
1920 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
1922 jsint i;
1924 CHECK_REQUEST(cx);
1925 if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
1926 *rval = INT_TO_JSVAL(i);
1927 return JS_TRUE;
1929 return JS_NewDoubleValue(cx, d, rval);
1932 #undef JS_AddRoot
1933 JS_PUBLIC_API(JSBool)
1934 JS_AddRoot(JSContext *cx, void *rp)
1936 CHECK_REQUEST(cx);
1937 return js_AddRoot(cx, rp, NULL);
1940 JS_PUBLIC_API(JSBool)
1941 JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name)
1943 return js_AddRootRT(rt, rp, name);
1946 JS_PUBLIC_API(JSBool)
1947 JS_RemoveRoot(JSContext *cx, void *rp)
1949 CHECK_REQUEST(cx);
1950 return js_RemoveRoot(cx->runtime, rp);
1953 JS_PUBLIC_API(JSBool)
1954 JS_RemoveRootRT(JSRuntime *rt, void *rp)
1956 return js_RemoveRoot(rt, rp);
1959 JS_PUBLIC_API(JSBool)
1960 JS_AddNamedRoot(JSContext *cx, void *rp, const char *name)
1962 CHECK_REQUEST(cx);
1963 return js_AddRoot(cx, rp, name);
1966 JS_PUBLIC_API(void)
1967 JS_ClearNewbornRoots(JSContext *cx)
1969 JS_CLEAR_WEAK_ROOTS(&cx->weakRoots);
1972 JS_PUBLIC_API(JSBool)
1973 JS_EnterLocalRootScope(JSContext *cx)
1975 CHECK_REQUEST(cx);
1976 return js_EnterLocalRootScope(cx);
1979 JS_PUBLIC_API(void)
1980 JS_LeaveLocalRootScope(JSContext *cx)
1982 CHECK_REQUEST(cx);
1983 js_LeaveLocalRootScope(cx);
1986 JS_PUBLIC_API(void)
1987 JS_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval)
1989 CHECK_REQUEST(cx);
1990 js_LeaveLocalRootScopeWithResult(cx, rval);
1993 JS_PUBLIC_API(void)
1994 JS_ForgetLocalRoot(JSContext *cx, void *thing)
1996 CHECK_REQUEST(cx);
1997 js_ForgetLocalRoot(cx, (jsval) thing);
2000 #ifdef DEBUG
2002 JS_PUBLIC_API(void)
2003 JS_DumpNamedRoots(JSRuntime *rt,
2004 void (*dump)(const char *name, void *rp, void *data),
2005 void *data)
2007 js_DumpNamedRoots(rt, dump, data);
2010 #endif /* DEBUG */
2012 JS_PUBLIC_API(uint32)
2013 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
2015 return js_MapGCRoots(rt, map, data);
2018 JS_PUBLIC_API(JSBool)
2019 JS_LockGCThing(JSContext *cx, void *thing)
2021 JSBool ok;
2023 CHECK_REQUEST(cx);
2024 ok = js_LockGCThingRT(cx->runtime, thing);
2025 if (!ok)
2026 JS_ReportOutOfMemory(cx);
2027 return ok;
2030 JS_PUBLIC_API(JSBool)
2031 JS_LockGCThingRT(JSRuntime *rt, void *thing)
2033 return js_LockGCThingRT(rt, thing);
2036 JS_PUBLIC_API(JSBool)
2037 JS_UnlockGCThing(JSContext *cx, void *thing)
2039 JSBool ok;
2041 CHECK_REQUEST(cx);
2042 ok = js_UnlockGCThingRT(cx->runtime, thing);
2043 if (!ok)
2044 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_UNLOCK);
2045 return ok;
2048 JS_PUBLIC_API(JSBool)
2049 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
2051 return js_UnlockGCThingRT(rt, thing);
2054 JS_PUBLIC_API(void)
2055 JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
2057 rt->gcExtraRootsTraceOp = traceOp;
2058 rt->gcExtraRootsData = data;
2061 JS_PUBLIC_API(void)
2062 JS_TraceRuntime(JSTracer *trc)
2064 JSBool allAtoms = trc->context->runtime->gcKeepAtoms != 0;
2066 js_TraceRuntime(trc, allAtoms);
2069 #ifdef DEBUG
2071 #ifdef HAVE_XPCONNECT
2072 #include "dump_xpc.h"
2073 #endif
2075 JS_PUBLIC_API(void)
2076 JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc,
2077 void *thing, uint32 kind, JSBool details)
2079 const char *name;
2080 size_t n;
2082 if (bufsize == 0)
2083 return;
2085 switch (kind) {
2086 case JSTRACE_OBJECT:
2088 JSObject *obj = (JSObject *)thing;
2089 JSClass *clasp = STOBJ_GET_CLASS(obj);
2091 name = clasp->name;
2092 #ifdef HAVE_XPCONNECT
2093 if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
2094 jsval privateValue = STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
2096 JS_ASSERT(clasp->flags & JSCLASS_HAS_PRIVATE);
2097 if (!JSVAL_IS_VOID(privateValue)) {
2098 void *privateThing = JSVAL_TO_PRIVATE(privateValue);
2099 const char *xpcClassName = GetXPCObjectClassName(privateThing);
2101 if (xpcClassName)
2102 name = xpcClassName;
2105 #endif
2106 break;
2109 case JSTRACE_STRING:
2110 name = JSSTRING_IS_DEPENDENT((JSString *)thing)
2111 ? "substring"
2112 : "string";
2113 break;
2115 case JSTRACE_DOUBLE:
2116 name = "double";
2117 break;
2119 #if JS_HAS_XML_SUPPORT
2120 case JSTRACE_XML:
2121 name = "xml";
2122 break;
2123 #endif
2124 default:
2125 JS_ASSERT(0);
2126 return;
2127 break;
2130 n = strlen(name);
2131 if (n > bufsize - 1)
2132 n = bufsize - 1;
2133 memcpy(buf, name, n + 1);
2134 buf += n;
2135 bufsize -= n;
2137 if (details && bufsize > 2) {
2138 *buf++ = ' ';
2139 bufsize--;
2141 switch (kind) {
2142 case JSTRACE_OBJECT:
2144 JSObject *obj = (JSObject *)thing;
2145 JSClass *clasp = STOBJ_GET_CLASS(obj);
2146 if (clasp == &js_FunctionClass) {
2147 JSFunction *fun = (JSFunction *)
2148 JS_GetPrivate(trc->context, obj);
2150 if (!fun) {
2151 JS_snprintf(buf, bufsize, "<newborn>");
2152 } else if (FUN_OBJECT(fun) != obj) {
2153 JS_snprintf(buf, bufsize, "%p", fun);
2154 } else {
2155 if (fun->atom && ATOM_IS_STRING(fun->atom))
2156 js_PutEscapedString(buf, bufsize,
2157 ATOM_TO_STRING(fun->atom), 0);
2159 } else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
2160 jsval privateValue = STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
2161 void *privateThing = JSVAL_IS_VOID(privateValue)
2162 ? NULL
2163 : JSVAL_TO_PRIVATE(privateValue);
2165 JS_snprintf(buf, bufsize, "%p", privateThing);
2166 } else {
2167 JS_snprintf(buf, bufsize, "<no private>");
2169 break;
2172 case JSTRACE_STRING:
2173 js_PutEscapedString(buf, bufsize, (JSString *)thing, 0);
2174 break;
2176 case JSTRACE_DOUBLE:
2177 JS_snprintf(buf, bufsize, "%g", *(jsdouble *)thing);
2178 break;
2180 #if JS_HAS_XML_SUPPORT
2181 case JSTRACE_XML:
2183 extern const char *js_xml_class_str[];
2184 JSXML *xml = (JSXML *)thing;
2186 JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]);
2187 break;
2189 #endif
2190 default:
2191 JS_ASSERT(0);
2192 break;
2195 buf[bufsize - 1] = '\0';
2198 typedef struct JSHeapDumpNode JSHeapDumpNode;
2200 struct JSHeapDumpNode {
2201 void *thing;
2202 uint32 kind;
2203 JSHeapDumpNode *next; /* next sibling */
2204 JSHeapDumpNode *parent; /* node with the thing that refer to thing
2205 from this node */
2206 char edgeName[1]; /* name of the edge from parent->thing
2207 into thing */
2210 typedef struct JSDumpingTracer {
2211 JSTracer base;
2212 JSDHashTable visited;
2213 JSBool ok;
2214 void *startThing;
2215 void *thingToFind;
2216 void *thingToIgnore;
2217 JSHeapDumpNode *parentNode;
2218 JSHeapDumpNode **lastNodep;
2219 char buffer[200];
2220 } JSDumpingTracer;
2222 static void
2223 DumpNotify(JSTracer *trc, void *thing, uint32 kind)
2225 JSDumpingTracer *dtrc;
2226 JSContext *cx;
2227 JSDHashEntryStub *entry;
2228 JSHeapDumpNode *node;
2229 const char *edgeName;
2230 size_t edgeNameSize;
2232 JS_ASSERT(trc->callback == DumpNotify);
2233 dtrc = (JSDumpingTracer *)trc;
2235 if (!dtrc->ok || thing == dtrc->thingToIgnore)
2236 return;
2238 cx = trc->context;
2241 * Check if we have already seen thing unless it is thingToFind to include
2242 * it to the graph each time we reach it and print all live things that
2243 * refer to thingToFind.
2245 * This does not print all possible paths leading to thingToFind since
2246 * when a thing A refers directly or indirectly to thingToFind and A is
2247 * present several times in the graph, we will print only the first path
2248 * leading to A and thingToFind, other ways to reach A will be ignored.
2250 if (dtrc->thingToFind != thing) {
2252 * The startThing check allows to avoid putting startThing into the
2253 * hash table before tracing startThing in JS_DumpHeap.
2255 if (thing == dtrc->startThing)
2256 return;
2257 entry = (JSDHashEntryStub *)
2258 JS_DHashTableOperate(&dtrc->visited, thing, JS_DHASH_ADD);
2259 if (!entry) {
2260 JS_ReportOutOfMemory(cx);
2261 dtrc->ok = JS_FALSE;
2262 return;
2264 if (entry->key)
2265 return;
2266 entry->key = thing;
2269 if (dtrc->base.debugPrinter) {
2270 dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer));
2271 edgeName = dtrc->buffer;
2272 } else if (dtrc->base.debugPrintIndex != (size_t)-1) {
2273 JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]",
2274 (const char *)dtrc->base.debugPrintArg,
2275 dtrc->base.debugPrintIndex);
2276 edgeName = dtrc->buffer;
2277 } else {
2278 edgeName = (const char*)dtrc->base.debugPrintArg;
2281 edgeNameSize = strlen(edgeName) + 1;
2282 node = (JSHeapDumpNode *)
2283 JS_malloc(cx, offsetof(JSHeapDumpNode, edgeName) + edgeNameSize);
2284 if (!node) {
2285 dtrc->ok = JS_FALSE;
2286 return;
2289 node->thing = thing;
2290 node->kind = kind;
2291 node->next = NULL;
2292 node->parent = dtrc->parentNode;
2293 memcpy(node->edgeName, edgeName, edgeNameSize);
2295 JS_ASSERT(!*dtrc->lastNodep);
2296 *dtrc->lastNodep = node;
2297 dtrc->lastNodep = &node->next;
2300 /* Dump node and the chain that leads to thing it contains. */
2301 static JSBool
2302 DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
2304 JSHeapDumpNode *prev, *following;
2305 size_t chainLimit;
2306 JSBool ok;
2307 enum { MAX_PARENTS_TO_PRINT = 10 };
2309 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2310 &dtrc->base, node->thing, node->kind, JS_TRUE);
2311 if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
2312 return JS_FALSE;
2315 * We need to print the parent chain in the reverse order. To do it in
2316 * O(N) time where N is the chain length we first reverse the chain while
2317 * searching for the top and then print each node while restoring the
2318 * chain order.
2320 chainLimit = MAX_PARENTS_TO_PRINT;
2321 prev = NULL;
2322 for (;;) {
2323 following = node->parent;
2324 node->parent = prev;
2325 prev = node;
2326 node = following;
2327 if (!node)
2328 break;
2329 if (chainLimit == 0) {
2330 if (fputs("...", fp) < 0)
2331 return JS_FALSE;
2332 break;
2334 --chainLimit;
2337 node = prev;
2338 prev = following;
2339 ok = JS_TRUE;
2340 do {
2341 /* Loop must continue even when !ok to restore the parent chain. */
2342 if (ok) {
2343 if (!prev) {
2344 /* Print edge from some runtime root or startThing. */
2345 if (fputs(node->edgeName, fp) < 0)
2346 ok = JS_FALSE;
2347 } else {
2348 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2349 &dtrc->base, prev->thing, prev->kind,
2350 JS_FALSE);
2351 if (fprintf(fp, "(%p %s).%s",
2352 prev->thing, dtrc->buffer, node->edgeName) < 0) {
2353 ok = JS_FALSE;
2357 following = node->parent;
2358 node->parent = prev;
2359 prev = node;
2360 node = following;
2361 } while (node);
2363 return ok && putc('\n', fp) >= 0;
2366 JS_PUBLIC_API(JSBool)
2367 JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind,
2368 void *thingToFind, size_t maxDepth, void *thingToIgnore)
2370 JSDumpingTracer dtrc;
2371 JSHeapDumpNode *node, *children, *next, *parent;
2372 size_t depth;
2373 JSBool thingToFindWasTraced;
2375 if (maxDepth == 0)
2376 return JS_TRUE;
2378 JS_TRACER_INIT(&dtrc.base, cx, DumpNotify);
2379 if (!JS_DHashTableInit(&dtrc.visited, JS_DHashGetStubOps(),
2380 NULL, sizeof(JSDHashEntryStub),
2381 JS_DHASH_DEFAULT_CAPACITY(100))) {
2382 JS_ReportOutOfMemory(cx);
2383 return JS_FALSE;
2385 dtrc.ok = JS_TRUE;
2386 dtrc.startThing = startThing;
2387 dtrc.thingToFind = thingToFind;
2388 dtrc.thingToIgnore = thingToIgnore;
2389 dtrc.parentNode = NULL;
2390 node = NULL;
2391 dtrc.lastNodep = &node;
2392 if (!startThing) {
2393 JS_ASSERT(startKind == 0);
2394 JS_TraceRuntime(&dtrc.base);
2395 } else {
2396 JS_TraceChildren(&dtrc.base, startThing, startKind);
2399 depth = 1;
2400 if (!node)
2401 goto dump_out;
2403 thingToFindWasTraced = thingToFind && thingToFind == startThing;
2404 for (;;) {
2406 * Loop must continue even when !dtrc.ok to free all nodes allocated
2407 * so far.
2409 if (dtrc.ok) {
2410 if (thingToFind == NULL || thingToFind == node->thing)
2411 dtrc.ok = DumpNode(&dtrc, fp, node);
2413 /* Descend into children. */
2414 if (dtrc.ok &&
2415 depth < maxDepth &&
2416 (thingToFind != node->thing || !thingToFindWasTraced)) {
2417 dtrc.parentNode = node;
2418 children = NULL;
2419 dtrc.lastNodep = &children;
2420 JS_TraceChildren(&dtrc.base, node->thing, node->kind);
2421 if (thingToFind == node->thing)
2422 thingToFindWasTraced = JS_TRUE;
2423 if (children != NULL) {
2424 ++depth;
2425 node = children;
2426 continue;
2431 /* Move to next or parents next and free the node. */
2432 for (;;) {
2433 next = node->next;
2434 parent = node->parent;
2435 JS_free(cx, node);
2436 node = next;
2437 if (node)
2438 break;
2439 if (!parent)
2440 goto dump_out;
2441 JS_ASSERT(depth > 1);
2442 --depth;
2443 node = parent;
2447 dump_out:
2448 JS_ASSERT(depth == 1);
2449 JS_DHashTableFinish(&dtrc.visited);
2450 return dtrc.ok;
2453 #endif /* DEBUG */
2455 JS_PUBLIC_API(void)
2456 JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg)
2458 JSTracer *trc;
2460 trc = (JSTracer *)arg;
2461 if (!trc)
2462 trc = cx->runtime->gcMarkingTracer;
2463 else
2464 JS_ASSERT(trc == cx->runtime->gcMarkingTracer);
2466 #ifdef JS_THREADSAFE
2467 JS_ASSERT(cx->runtime->gcThread == trc->context->thread);
2468 #endif
2469 JS_SET_TRACING_NAME(trc, name ? name : "unknown");
2470 js_CallValueTracerIfGCThing(trc, (jsval)thing);
2473 extern JS_PUBLIC_API(JSBool)
2474 JS_IsGCMarkingTracer(JSTracer *trc)
2476 return IS_GC_MARKING_TRACER(trc);
2479 JS_PUBLIC_API(void)
2480 JS_GC(JSContext *cx)
2482 /* Don't nuke active arenas if executing or compiling. */
2483 if (cx->stackPool.current == &cx->stackPool.first)
2484 JS_FinishArenaPool(&cx->stackPool);
2485 if (cx->tempPool.current == &cx->tempPool.first)
2486 JS_FinishArenaPool(&cx->tempPool);
2487 js_GC(cx, GC_NORMAL);
2490 JS_PUBLIC_API(void)
2491 JS_MaybeGC(JSContext *cx)
2493 JSRuntime *rt;
2494 uint32 bytes, lastBytes;
2496 rt = cx->runtime;
2498 #ifdef JS_GC_ZEAL
2499 if (rt->gcZeal > 0) {
2500 JS_GC(cx);
2501 return;
2503 #endif
2505 bytes = rt->gcBytes;
2506 lastBytes = rt->gcLastBytes;
2509 * We run the GC if we used all available free GC cells and had to
2510 * allocate extra 1/3 of GC arenas since the last run of GC, or if
2511 * we have malloc'd more bytes through JS_malloc than we were told
2512 * to allocate by JS_NewRuntime.
2514 * The reason for
2515 * bytes > 4/3 lastBytes
2516 * condition is the following. Bug 312238 changed bytes and lastBytes
2517 * to mean the total amount of memory that the GC uses now and right
2518 * after the last GC.
2520 * Before the bug the variables meant the size of allocated GC things
2521 * now and right after the last GC. That size did not include the
2522 * memory taken by free GC cells and the condition was
2523 * bytes > 3/2 lastBytes.
2524 * That is, we run the GC if we have half again as many bytes of
2525 * GC-things as the last time we GC'd. To be compatible we need to
2526 * express that condition through the new meaning of bytes and
2527 * lastBytes.
2529 * We write the original condition as
2530 * B*(1-F) > 3/2 Bl*(1-Fl)
2531 * where B is the total memory size allocated by GC and F is the free
2532 * cell density currently and Sl and Fl are the size and the density
2533 * right after GC. The density by definition is memory taken by free
2534 * cells divided by total amount of memory. In other words, B and Bl
2535 * are bytes and lastBytes with the new meaning and B*(1-F) and
2536 * Bl*(1-Fl) are bytes and lastBytes with the original meaning.
2538 * Our task is to exclude F and Fl from the last statement. According
2539 * to the stats from bug 331966 comment 23, Fl is about 10-25% for a
2540 * typical run of the browser. It means that the original condition
2541 * implied that we did not run GC unless we exhausted the pool of
2542 * free cells. Indeed if we still have free cells, then B == Bl since
2543 * we did not yet allocated any new arenas and the condition means
2544 * 1 - F > 3/2 (1-Fl) or 3/2Fl > 1/2 + F
2545 * That implies 3/2 Fl > 1/2 or Fl > 1/3. That can not be fulfilled
2546 * for the state described by the stats. So we can write the original
2547 * condition as:
2548 * F == 0 && B > 3/2 Bl(1-Fl)
2549 * Again using the stats we see that Fl is about 11% when the browser
2550 * starts up and when we are far from hitting rt->gcMaxBytes. With
2551 * this F we have
2552 * F == 0 && B > 3/2 Bl(1-0.11)
2553 * or approximately F == 0 && B > 4/3 Bl.
2555 if ((bytes > 8192 && bytes > lastBytes + lastBytes / 3) ||
2556 rt->gcMallocBytes >= rt->gcMaxMallocBytes) {
2557 JS_GC(cx);
2561 JS_PUBLIC_API(JSGCCallback)
2562 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
2564 CHECK_REQUEST(cx);
2565 return JS_SetGCCallbackRT(cx->runtime, cb);
2568 JS_PUBLIC_API(JSGCCallback)
2569 JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
2571 JSGCCallback oldcb;
2573 oldcb = rt->gcCallback;
2574 rt->gcCallback = cb;
2575 return oldcb;
2578 JS_PUBLIC_API(JSBool)
2579 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
2581 JS_ASSERT(thing);
2582 return js_IsAboutToBeFinalized(cx, thing);
2585 JS_PUBLIC_API(void)
2586 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
2588 switch (key) {
2589 case JSGC_MAX_BYTES:
2590 rt->gcMaxBytes = value;
2591 break;
2592 case JSGC_MAX_MALLOC_BYTES:
2593 rt->gcMaxMallocBytes = value;
2594 break;
2595 case JSGC_STACKPOOL_LIFESPAN:
2596 rt->gcEmptyArenaPoolLifespan = value;
2597 break;
2601 JS_PUBLIC_API(intN)
2602 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
2604 return js_ChangeExternalStringFinalizer(NULL, finalizer);
2607 JS_PUBLIC_API(intN)
2608 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
2610 return js_ChangeExternalStringFinalizer(finalizer, NULL);
2613 JS_PUBLIC_API(JSString *)
2614 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
2616 JSString *str;
2618 CHECK_REQUEST(cx);
2619 JS_ASSERT((uintN) type < (uintN) (GCX_NTYPES - GCX_EXTERNAL_STRING));
2621 str = (JSString *) js_NewGCThing(cx, (uintN) type + GCX_EXTERNAL_STRING,
2622 sizeof(JSString));
2623 if (!str)
2624 return NULL;
2625 JSFLATSTR_INIT(str, chars, length);
2626 return str;
2629 JS_PUBLIC_API(intN)
2630 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
2632 return js_GetExternalStringGCType(str);
2635 JS_PUBLIC_API(void)
2636 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
2638 #if JS_STACK_GROWTH_DIRECTION > 0
2639 if (limitAddr == 0)
2640 limitAddr = (jsuword)-1;
2641 #endif
2642 cx->stackLimit = limitAddr;
2645 JS_PUBLIC_API(void)
2646 JS_SetScriptStackQuota(JSContext *cx, size_t quota)
2648 cx->scriptStackQuota = quota;
2651 /************************************************************************/
2653 JS_PUBLIC_API(void)
2654 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
2656 JS_free(cx, ida);
2659 JS_PUBLIC_API(JSBool)
2660 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
2662 CHECK_REQUEST(cx);
2663 if (JSVAL_IS_INT(v))
2664 *idp = INT_JSVAL_TO_JSID(v);
2665 #if JS_HAS_XML_SUPPORT
2666 else if (!JSVAL_IS_PRIMITIVE(v))
2667 *idp = OBJECT_JSVAL_TO_JSID(v);
2668 #endif
2669 else
2670 return js_ValueToStringId(cx, v, idp);
2671 return JS_TRUE;
2674 JS_PUBLIC_API(JSBool)
2675 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
2677 CHECK_REQUEST(cx);
2678 *vp = ID_TO_VALUE(id);
2679 return JS_TRUE;
2682 JS_PUBLIC_API(JSBool)
2683 JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
2685 return JS_TRUE;
2688 JS_PUBLIC_API(JSBool)
2689 JS_EnumerateStub(JSContext *cx, JSObject *obj)
2691 return JS_TRUE;
2694 JS_PUBLIC_API(JSBool)
2695 JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id)
2697 return JS_TRUE;
2700 JS_PUBLIC_API(JSBool)
2701 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
2703 return js_TryValueOf(cx, obj, type, vp);
2706 JS_PUBLIC_API(void)
2707 JS_FinalizeStub(JSContext *cx, JSObject *obj)
2711 JS_PUBLIC_API(JSObject *)
2712 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
2713 JSClass *clasp, JSNative constructor, uintN nargs,
2714 JSPropertySpec *ps, JSFunctionSpec *fs,
2715 JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
2717 JSAtom *atom;
2718 JSProtoKey key;
2719 JSObject *proto, *ctor;
2720 JSTempValueRooter tvr;
2721 jsval cval, rval;
2722 JSBool named;
2723 JSFunction *fun;
2725 CHECK_REQUEST(cx);
2726 atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
2727 if (!atom)
2728 return NULL;
2731 * When initializing a standard class, if no parent_proto (grand-proto of
2732 * instances of the class, parent-proto of the class's prototype object)
2733 * is given, we must use Object.prototype if it is available. Otherwise,
2734 * we could look up the wrong binding for a class name in obj. Example:
2736 * String = Array;
2737 * print("hi there".join);
2739 * should print undefined, not Array.prototype.join. This is required by
2740 * ECMA-262, alas. It might have been better to make String readonly and
2741 * permanent in the global object, instead -- but that's too big a change
2742 * to swallow at this point.
2744 key = JSCLASS_CACHED_PROTO_KEY(clasp);
2745 if (key != JSProto_Null &&
2746 !parent_proto &&
2747 !js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object),
2748 &parent_proto)) {
2749 return NULL;
2752 /* Create a prototype object for this class. */
2753 proto = js_NewObject(cx, clasp, parent_proto, obj, 0);
2754 if (!proto)
2755 return NULL;
2757 /* After this point, control must exit via label bad or out. */
2758 JS_PUSH_TEMP_ROOT_OBJECT(cx, proto, &tvr);
2760 if (!constructor) {
2762 * Lacking a constructor, name the prototype (e.g., Math) unless this
2763 * class (a) is anonymous, i.e. for internal use only; (b) the class
2764 * of obj (the global object) is has a reserved slot indexed by key;
2765 * and (c) key is not the null key.
2767 if ((clasp->flags & JSCLASS_IS_ANONYMOUS) &&
2768 (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL) &&
2769 key != JSProto_Null) {
2770 named = JS_FALSE;
2771 } else {
2772 named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
2773 OBJECT_TO_JSVAL(proto),
2774 JS_PropertyStub, JS_PropertyStub,
2775 (clasp->flags & JSCLASS_IS_ANONYMOUS)
2776 ? JSPROP_READONLY | JSPROP_PERMANENT
2777 : 0,
2778 NULL);
2779 if (!named)
2780 goto bad;
2783 ctor = proto;
2784 } else {
2785 /* Define the constructor function in obj's scope. */
2786 fun = js_DefineFunction(cx, obj, atom, constructor, nargs,
2787 JSFUN_STUB_GSOPS);
2788 named = (fun != NULL);
2789 if (!fun)
2790 goto bad;
2793 * Remember the class this function is a constructor for so that
2794 * we know to create an object of this class when we call the
2795 * constructor.
2797 FUN_CLASP(fun) = clasp;
2800 * Optionally construct the prototype object, before the class has
2801 * been fully initialized. Allow the ctor to replace proto with a
2802 * different object, as is done for operator new -- and as at least
2803 * XML support requires.
2805 ctor = FUN_OBJECT(fun);
2806 if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) {
2807 cval = OBJECT_TO_JSVAL(ctor);
2808 if (!js_InternalConstruct(cx, proto, cval, 0, NULL, &rval))
2809 goto bad;
2810 if (!JSVAL_IS_PRIMITIVE(rval) && JSVAL_TO_OBJECT(rval) != proto)
2811 proto = JSVAL_TO_OBJECT(rval);
2814 /* Connect constructor and prototype by named properties. */
2815 if (!js_SetClassPrototype(cx, ctor, proto,
2816 JSPROP_READONLY | JSPROP_PERMANENT)) {
2817 goto bad;
2820 /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
2821 if (OBJ_GET_CLASS(cx, ctor) == clasp) {
2822 OBJ_SET_PROTO(cx, ctor, proto);
2826 /* Add properties and methods to the prototype and the constructor. */
2827 if ((ps && !JS_DefineProperties(cx, proto, ps)) ||
2828 (fs && !JS_DefineFunctions(cx, proto, fs)) ||
2829 (static_ps && !JS_DefineProperties(cx, ctor, static_ps)) ||
2830 (static_fs && !JS_DefineFunctions(cx, ctor, static_fs))) {
2831 goto bad;
2834 /* If this is a standard class, cache its prototype. */
2835 if (key != JSProto_Null && !js_SetClassObject(cx, obj, key, ctor))
2836 goto bad;
2838 out:
2839 JS_POP_TEMP_ROOT(cx, &tvr);
2840 return proto;
2842 bad:
2843 if (named)
2844 (void) OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &rval);
2845 proto = NULL;
2846 goto out;
2849 #ifdef JS_THREADSAFE
2850 JS_PUBLIC_API(JSClass *)
2851 JS_GetClass(JSContext *cx, JSObject *obj)
2853 return OBJ_GET_CLASS(cx, obj);
2855 #else
2856 JS_PUBLIC_API(JSClass *)
2857 JS_GetClass(JSObject *obj)
2859 return LOCKED_OBJ_GET_CLASS(obj);
2861 #endif
2863 JS_PUBLIC_API(JSBool)
2864 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2866 JSFunction *fun;
2868 CHECK_REQUEST(cx);
2869 if (obj && OBJ_GET_CLASS(cx, obj) == clasp)
2870 return JS_TRUE;
2871 if (argv) {
2872 fun = js_ValueToFunction(cx, &argv[-2], 0);
2873 if (fun) {
2874 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2875 JSMSG_INCOMPATIBLE_PROTO,
2876 clasp->name, JS_GetFunctionName(fun),
2878 ? OBJ_GET_CLASS(cx, obj)->name
2879 : js_null_str);
2882 return JS_FALSE;
2885 JS_PUBLIC_API(JSBool)
2886 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
2888 return js_HasInstance(cx, obj, v, bp);
2891 JS_PUBLIC_API(void *)
2892 JS_GetPrivate(JSContext *cx, JSObject *obj)
2894 jsval v;
2896 JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2897 v = obj->fslots[JSSLOT_PRIVATE];
2898 if (!JSVAL_IS_INT(v))
2899 return NULL;
2900 return JSVAL_TO_PRIVATE(v);
2903 JS_PUBLIC_API(JSBool)
2904 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2906 JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2907 obj->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(data);
2908 return JS_TRUE;
2911 JS_PUBLIC_API(void *)
2912 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp,
2913 jsval *argv)
2915 if (!JS_InstanceOf(cx, obj, clasp, argv))
2916 return NULL;
2917 return JS_GetPrivate(cx, obj);
2920 JS_PUBLIC_API(JSObject *)
2921 JS_GetPrototype(JSContext *cx, JSObject *obj)
2923 JSObject *proto;
2925 CHECK_REQUEST(cx);
2926 proto = OBJ_GET_PROTO(cx, obj);
2928 /* Beware ref to dead object (we may be called from obj's finalizer). */
2929 return proto && proto->map ? proto : NULL;
2932 JS_PUBLIC_API(JSBool)
2933 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
2935 CHECK_REQUEST(cx);
2936 JS_ASSERT(obj != proto);
2937 #ifdef DEBUG
2939 * FIXME: bug 408416. The cycle-detection required for script-writeable
2940 * __proto__ lives in js_SetProtoOrParent over in jsobj.c, also known as
2941 * js_ObjectOps.setProto. This hook must detect cycles, to prevent scripts
2942 * from ilooping SpiderMonkey trivially. But the overhead of detecting
2943 * cycles is high enough, and the threat from JS-API-calling C++ code is
2944 * low enough, that it's not worth burdening the non-DEBUG callers. Same
2945 * goes for JS_SetParent, below.
2947 if (obj->map->ops->setProto)
2948 return obj->map->ops->setProto(cx, obj, JSSLOT_PROTO, proto);
2949 #else
2950 if (OBJ_IS_NATIVE(obj)) {
2951 JS_LOCK_OBJ(cx, obj);
2952 if (!js_GetMutableScope(cx, obj)) {
2953 JS_UNLOCK_OBJ(cx, obj);
2954 return JS_FALSE;
2956 LOCKED_OBJ_SET_PROTO(obj, proto);
2957 JS_UNLOCK_OBJ(cx, obj);
2958 return JS_TRUE;
2960 #endif
2961 OBJ_SET_PROTO(cx, obj, proto);
2962 return JS_TRUE;
2965 JS_PUBLIC_API(JSObject *)
2966 JS_GetParent(JSContext *cx, JSObject *obj)
2968 JSObject *parent;
2970 parent = OBJ_GET_PARENT(cx, obj);
2972 /* Beware ref to dead object (we may be called from obj's finalizer). */
2973 return parent && parent->map ? parent : NULL;
2976 JS_PUBLIC_API(JSBool)
2977 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
2979 CHECK_REQUEST(cx);
2980 JS_ASSERT(obj != parent);
2981 #ifdef DEBUG
2982 /* FIXME: bug 408416, see JS_SetPrototype just above. */
2983 if (obj->map->ops->setParent)
2984 return obj->map->ops->setParent(cx, obj, JSSLOT_PARENT, parent);
2985 #endif
2986 OBJ_SET_PARENT(cx, obj, parent);
2987 return JS_TRUE;
2990 JS_PUBLIC_API(JSObject *)
2991 JS_GetConstructor(JSContext *cx, JSObject *proto)
2993 jsval cval;
2995 CHECK_REQUEST(cx);
2997 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
2999 if (!OBJ_GET_PROPERTY(cx, proto,
3000 ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
3001 &cval)) {
3002 return NULL;
3005 if (!VALUE_IS_FUNCTION(cx, cval)) {
3006 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
3007 OBJ_GET_CLASS(cx, proto)->name);
3008 return NULL;
3010 return JSVAL_TO_OBJECT(cval);
3013 JS_PUBLIC_API(JSBool)
3014 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
3016 JS_ASSERT(JSID_IS_OBJECT(obj));
3017 *idp = OBJECT_TO_JSID(obj);
3018 return JS_TRUE;
3021 JS_PUBLIC_API(JSObject *)
3022 JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
3024 CHECK_REQUEST(cx);
3025 if (!clasp)
3026 clasp = &js_ObjectClass; /* default class is Object */
3027 return js_NewObject(cx, clasp, proto, parent, 0);
3030 JS_PUBLIC_API(JSObject *)
3031 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
3032 JSObject *parent)
3034 CHECK_REQUEST(cx);
3035 if (!clasp)
3036 clasp = &js_ObjectClass; /* default class is Object */
3037 return js_NewObjectWithGivenProto(cx, clasp, proto, parent, 0);
3040 JS_PUBLIC_API(JSBool)
3041 JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
3043 JSScope *scope;
3044 JSIdArray *ida;
3045 uint32 nslots, i;
3046 jsval v;
3048 if (OBJ_IS_DENSE_ARRAY(cx, obj) && !js_MakeArraySlow(cx, obj))
3049 return JS_FALSE;
3051 if (!OBJ_IS_NATIVE(obj)) {
3052 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3053 JSMSG_CANT_SEAL_OBJECT,
3054 OBJ_GET_CLASS(cx, obj)->name);
3055 return JS_FALSE;
3058 scope = OBJ_SCOPE(obj);
3060 #if defined JS_THREADSAFE && defined DEBUG
3061 /* Insist on scope being used exclusively by cx's thread. */
3062 if (scope->title.ownercx != cx) {
3063 JS_LOCK_OBJ(cx, obj);
3064 JS_ASSERT(OBJ_SCOPE(obj) == scope);
3065 JS_ASSERT(scope->title.ownercx == cx);
3066 JS_UNLOCK_SCOPE(cx, scope);
3068 #endif
3070 /* Nothing to do if obj's scope is already sealed. */
3071 if (SCOPE_IS_SEALED(scope))
3072 return JS_TRUE;
3074 /* XXX Enumerate lazy properties now, as they can't be added later. */
3075 ida = JS_Enumerate(cx, obj);
3076 if (!ida)
3077 return JS_FALSE;
3078 JS_DestroyIdArray(cx, ida);
3080 /* Ensure that obj has its own, mutable scope, and seal that scope. */
3081 JS_LOCK_OBJ(cx, obj);
3082 scope = js_GetMutableScope(cx, obj);
3083 if (scope) {
3084 SCOPE_SET_SEALED(scope);
3085 SCOPE_MAKE_UNIQUE_SHAPE(cx, scope);
3087 JS_UNLOCK_OBJ(cx, obj);
3088 if (!scope)
3089 return JS_FALSE;
3091 /* If we are not sealing an entire object graph, we're done. */
3092 if (!deep)
3093 return JS_TRUE;
3095 /* Walk slots in obj and if any value is a non-null object, seal it. */
3096 nslots = scope->map.freeslot;
3097 for (i = 0; i != nslots; ++i) {
3098 v = STOBJ_GET_SLOT(obj, i);
3099 if (JSVAL_IS_PRIMITIVE(v))
3100 continue;
3101 if (!JS_SealObject(cx, JSVAL_TO_OBJECT(v), deep))
3102 return JS_FALSE;
3104 return JS_TRUE;
3107 JS_PUBLIC_API(JSObject *)
3108 JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
3109 JSObject *parent)
3111 CHECK_REQUEST(cx);
3112 if (!clasp)
3113 clasp = &js_ObjectClass; /* default class is Object */
3114 return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
3117 JS_PUBLIC_API(JSObject *)
3118 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto,
3119 JSObject *parent, uintN argc, jsval *argv)
3121 CHECK_REQUEST(cx);
3122 if (!clasp)
3123 clasp = &js_ObjectClass; /* default class is Object */
3124 return js_ConstructObject(cx, clasp, proto, parent, argc, argv);
3127 static JSBool
3128 DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
3129 JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
3130 uintN flags, intN tinyid)
3132 if (flags != 0 && OBJ_IS_NATIVE(obj)) {
3133 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
3134 return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
3135 attrs, flags, tinyid, NULL);
3137 return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs,
3138 NULL);
3141 static JSBool
3142 DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
3143 JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
3144 uintN flags, intN tinyid)
3146 jsid id;
3147 JSAtom *atom;
3149 if (attrs & JSPROP_INDEX) {
3150 id = INT_TO_JSID(JS_PTR_TO_INT32(name));
3151 atom = NULL;
3152 attrs &= ~JSPROP_INDEX;
3153 } else {
3154 atom = js_Atomize(cx, name, strlen(name), 0);
3155 if (!atom)
3156 return JS_FALSE;
3157 id = ATOM_TO_JSID(atom);
3159 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs,
3160 flags, tinyid);
3163 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
3165 static JSBool
3166 DefineUCProperty(JSContext *cx, JSObject *obj,
3167 const jschar *name, size_t namelen, jsval value,
3168 JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
3169 uintN flags, intN tinyid)
3171 JSAtom *atom;
3173 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3174 if (!atom)
3175 return JS_FALSE;
3176 if (flags != 0 && OBJ_IS_NATIVE(obj)) {
3177 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
3178 return js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
3179 getter, setter, attrs, flags, tinyid,
3180 NULL);
3182 return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), value,
3183 getter, setter, attrs, NULL);
3186 JS_PUBLIC_API(JSObject *)
3187 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
3188 JSObject *proto, uintN attrs)
3190 JSObject *nobj;
3192 CHECK_REQUEST(cx);
3193 if (!clasp)
3194 clasp = &js_ObjectClass; /* default class is Object */
3195 nobj = js_NewObject(cx, clasp, proto, obj, 0);
3196 if (!nobj)
3197 return NULL;
3198 if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs,
3199 0, 0)) {
3200 cx->weakRoots.newborn[GCX_OBJECT] = NULL;
3201 return NULL;
3203 return nobj;
3206 JS_PUBLIC_API(JSBool)
3207 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
3209 JSBool ok;
3210 jsval value;
3211 uintN attrs;
3213 CHECK_REQUEST(cx);
3214 for (ok = JS_TRUE; cds->name; cds++) {
3215 ok = js_NewNumberInRootedValue(cx, cds->dval, &value);
3216 if (!ok)
3217 break;
3218 attrs = cds->flags;
3219 if (!attrs)
3220 attrs = JSPROP_READONLY | JSPROP_PERMANENT;
3221 ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
3222 if (!ok)
3223 break;
3225 return ok;
3228 JS_PUBLIC_API(JSBool)
3229 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
3231 JSBool ok;
3233 CHECK_REQUEST(cx);
3234 for (ok = JS_TRUE; ps->name; ps++) {
3235 ok = DefineProperty(cx, obj, ps->name, JSVAL_VOID,
3236 ps->getter, ps->setter, ps->flags,
3237 SPROP_HAS_SHORTID, ps->tinyid);
3238 if (!ok)
3239 break;
3241 return ok;
3244 JS_PUBLIC_API(JSBool)
3245 JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
3246 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3248 CHECK_REQUEST(cx);
3249 return DefineProperty(cx, obj, name, value, getter, setter, attrs, 0, 0);
3252 JS_PUBLIC_API(JSBool)
3253 JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
3254 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3256 CHECK_REQUEST(cx);
3257 return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, 0, 0);
3260 JS_PUBLIC_API(JSBool)
3261 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
3262 int8 tinyid, jsval value,
3263 JSPropertyOp getter, JSPropertyOp setter,
3264 uintN attrs)
3266 CHECK_REQUEST(cx);
3267 return DefineProperty(cx, obj, name, value, getter, setter, attrs,
3268 SPROP_HAS_SHORTID, tinyid);
3271 static JSBool
3272 LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3273 JSObject **objp, JSProperty **propp)
3275 JSAutoResolveFlags rf(cx, flags);
3276 return OBJ_LOOKUP_PROPERTY(cx, obj, id, objp, propp);
3279 static JSBool
3280 LookupProperty(JSContext *cx, JSObject *obj, const char *name, uintN flags,
3281 JSObject **objp, JSProperty **propp)
3283 JSAtom *atom;
3285 atom = js_Atomize(cx, name, strlen(name), 0);
3286 if (!atom)
3287 return JS_FALSE;
3288 return LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), flags, objp, propp);
3291 static JSBool
3292 LookupUCProperty(JSContext *cx, JSObject *obj,
3293 const jschar *name, size_t namelen, uintN flags,
3294 JSObject **objp, JSProperty **propp)
3296 JSAtom *atom;
3298 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3299 if (!atom)
3300 return JS_FALSE;
3301 return LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), flags, objp, propp);
3304 JS_PUBLIC_API(JSBool)
3305 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
3306 const char *alias)
3308 JSObject *obj2;
3309 JSProperty *prop;
3310 JSAtom *atom;
3311 JSBool ok;
3312 JSScopeProperty *sprop;
3314 CHECK_REQUEST(cx);
3315 if (!LookupProperty(cx, obj, name, JSRESOLVE_QUALIFIED, &obj2, &prop))
3316 return JS_FALSE;
3317 if (!prop) {
3318 js_ReportIsNotDefined(cx, name);
3319 return JS_FALSE;
3321 if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
3322 OBJ_DROP_PROPERTY(cx, obj2, prop);
3323 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3324 alias, name, OBJ_GET_CLASS(cx, obj2)->name);
3325 return JS_FALSE;
3327 atom = js_Atomize(cx, alias, strlen(alias), 0);
3328 if (!atom) {
3329 ok = JS_FALSE;
3330 } else {
3331 sprop = (JSScopeProperty *)prop;
3332 ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
3333 sprop->getter, sprop->setter, sprop->slot,
3334 sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
3335 sprop->shortid)
3336 != NULL);
3338 OBJ_DROP_PROPERTY(cx, obj, prop);
3339 return ok;
3342 static jsval
3343 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop)
3345 JSScopeProperty *sprop;
3346 jsval rval;
3348 if (!prop) {
3349 /* XXX bad API: no way to tell "not defined" from "void value" */
3350 return JSVAL_VOID;
3352 if (OBJ_IS_NATIVE(obj2)) {
3353 /* Peek at the native property's slot value, without doing a Get. */
3354 sprop = (JSScopeProperty *)prop;
3355 rval = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2))
3356 ? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot)
3357 : JSVAL_TRUE;
3358 } else {
3359 /* XXX bad API: no way to return "defined but value unknown" */
3360 rval = JSVAL_TRUE;
3362 OBJ_DROP_PROPERTY(cx, obj2, prop);
3363 return rval;
3366 static JSBool
3367 GetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
3368 uintN *attrsp, JSBool *foundp,
3369 JSPropertyOp *getterp, JSPropertyOp *setterp)
3371 JSObject *obj2;
3372 JSProperty *prop;
3373 JSBool ok;
3375 if (!atom)
3376 return JS_FALSE;
3377 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED,
3378 &obj2, &prop)) {
3379 return JS_FALSE;
3382 if (!prop || obj != obj2) {
3383 *attrsp = 0;
3384 *foundp = JS_FALSE;
3385 if (getterp)
3386 *getterp = NULL;
3387 if (setterp)
3388 *setterp = NULL;
3389 if (prop)
3390 OBJ_DROP_PROPERTY(cx, obj2, prop);
3391 return JS_TRUE;
3394 *foundp = JS_TRUE;
3395 ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, attrsp);
3396 if (ok && OBJ_IS_NATIVE(obj)) {
3397 JSScopeProperty *sprop = (JSScopeProperty *) prop;
3399 if (getterp)
3400 *getterp = sprop->getter;
3401 if (setterp)
3402 *setterp = sprop->setter;
3404 OBJ_DROP_PROPERTY(cx, obj, prop);
3405 return ok;
3408 static JSBool
3409 SetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
3410 uintN attrs, JSBool *foundp)
3412 JSObject *obj2;
3413 JSProperty *prop;
3414 JSBool ok;
3416 if (!atom)
3417 return JS_FALSE;
3418 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED,
3419 &obj2, &prop)) {
3420 return JS_FALSE;
3422 if (!prop || obj != obj2) {
3423 *foundp = JS_FALSE;
3424 if (prop)
3425 OBJ_DROP_PROPERTY(cx, obj2, prop);
3426 return JS_TRUE;
3429 *foundp = JS_TRUE;
3430 ok = OBJ_SET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs);
3431 OBJ_DROP_PROPERTY(cx, obj, prop);
3432 return ok;
3435 JS_PUBLIC_API(JSBool)
3436 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3437 uintN *attrsp, JSBool *foundp)
3439 CHECK_REQUEST(cx);
3440 return GetPropertyAttributes(cx, obj,
3441 js_Atomize(cx, name, strlen(name), 0),
3442 attrsp, foundp, NULL, NULL);
3445 JS_PUBLIC_API(JSBool)
3446 JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
3447 const char *name,
3448 uintN *attrsp, JSBool *foundp,
3449 JSPropertyOp *getterp,
3450 JSPropertyOp *setterp)
3452 CHECK_REQUEST(cx);
3453 return GetPropertyAttributes(cx, obj,
3454 js_Atomize(cx, name, strlen(name), 0),
3455 attrsp, foundp, getterp, setterp);
3458 JS_PUBLIC_API(JSBool)
3459 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3460 uintN attrs, JSBool *foundp)
3462 CHECK_REQUEST(cx);
3463 return SetPropertyAttributes(cx, obj,
3464 js_Atomize(cx, name, strlen(name), 0),
3465 attrs, foundp);
3468 static JSBool
3469 AlreadyHasOwnPropertyHelper(JSContext *cx, JSObject *obj, jsid id,
3470 JSBool *foundp)
3472 JSScope *scope;
3474 if (!OBJ_IS_NATIVE(obj)) {
3475 JSObject *obj2;
3476 JSProperty *prop;
3478 if (!LookupPropertyById(cx, obj, id,
3479 JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3480 &obj2, &prop)) {
3481 return JS_FALSE;
3483 *foundp = (obj == obj2);
3484 if (prop)
3485 OBJ_DROP_PROPERTY(cx, obj2, prop);
3486 return JS_TRUE;
3489 JS_LOCK_OBJ(cx, obj);
3490 scope = OBJ_SCOPE(obj);
3491 *foundp = (scope->object == obj && SCOPE_GET_PROPERTY(scope, id));
3492 JS_UNLOCK_SCOPE(cx, scope);
3493 return JS_TRUE;
3496 JS_PUBLIC_API(JSBool)
3497 JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name,
3498 JSBool *foundp)
3500 JSAtom *atom;
3502 CHECK_REQUEST(cx);
3503 atom = js_Atomize(cx, name, strlen(name), 0);
3504 if (!atom)
3505 return JS_FALSE;
3506 return AlreadyHasOwnPropertyHelper(cx, obj, ATOM_TO_JSID(atom), foundp);
3509 JS_PUBLIC_API(JSBool)
3510 JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id,
3511 JSBool *foundp)
3513 CHECK_REQUEST(cx);
3514 return AlreadyHasOwnPropertyHelper(cx, obj, id, foundp);
3517 JS_PUBLIC_API(JSBool)
3518 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3520 JSBool ok;
3521 JSObject *obj2;
3522 JSProperty *prop;
3524 CHECK_REQUEST(cx);
3525 ok = LookupProperty(cx, obj, name,
3526 JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3527 &obj2, &prop);
3528 if (ok) {
3529 *foundp = (prop != NULL);
3530 if (prop)
3531 OBJ_DROP_PROPERTY(cx, obj2, prop);
3533 return ok;
3536 JS_PUBLIC_API(JSBool)
3537 JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
3539 JSBool ok;
3540 JSObject *obj2;
3541 JSProperty *prop;
3543 CHECK_REQUEST(cx);
3544 ok = LookupPropertyById(cx, obj, id,
3545 JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3546 &obj2, &prop);
3547 if (ok) {
3548 *foundp = (prop != NULL);
3549 if (prop)
3550 OBJ_DROP_PROPERTY(cx, obj2, prop);
3552 return ok;
3555 JS_PUBLIC_API(JSBool)
3556 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3558 JSBool ok;
3559 JSObject *obj2;
3560 JSProperty *prop;
3562 CHECK_REQUEST(cx);
3563 ok = LookupProperty(cx, obj, name, JSRESOLVE_QUALIFIED, &obj2, &prop);
3564 if (ok)
3565 *vp = LookupResult(cx, obj, obj2, prop);
3566 return ok;
3569 JS_PUBLIC_API(JSBool)
3570 JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3572 JSBool ok;
3573 JSObject *obj2;
3574 JSProperty *prop;
3576 CHECK_REQUEST(cx);
3577 ok = LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop);
3578 if (ok)
3579 *vp = LookupResult(cx, obj, obj2, prop);
3580 return ok;
3583 JS_PUBLIC_API(JSBool)
3584 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name,
3585 uintN flags, jsval *vp)
3587 JSAtom *atom;
3588 JSObject *obj2;
3590 atom = js_Atomize(cx, name, strlen(name), 0);
3591 return atom &&
3592 JS_LookupPropertyWithFlagsById(cx, obj, ATOM_TO_JSID(atom), flags,
3593 &obj2, vp);
3596 JS_PUBLIC_API(JSBool)
3597 JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id,
3598 uintN flags, JSObject **objp, jsval *vp)
3600 JSBool ok;
3601 JSProperty *prop;
3603 CHECK_REQUEST(cx);
3604 ok = OBJ_IS_NATIVE(obj)
3605 ? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0
3606 : OBJ_LOOKUP_PROPERTY(cx, obj, id, objp, &prop);
3607 if (ok)
3608 *vp = LookupResult(cx, obj, *objp, prop);
3609 return ok;
3612 JS_PUBLIC_API(JSBool)
3613 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3615 JSAtom *atom;
3617 CHECK_REQUEST(cx);
3618 atom = js_Atomize(cx, name, strlen(name), 0);
3619 if (!atom)
3620 return JS_FALSE;
3622 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3623 return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
3626 JS_PUBLIC_API(JSBool)
3627 JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3629 CHECK_REQUEST(cx);
3630 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3631 return OBJ_GET_PROPERTY(cx, obj, id, vp);
3634 JS_PUBLIC_API(JSBool)
3635 JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
3636 jsval *vp)
3638 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3640 CHECK_REQUEST(cx);
3641 #if JS_HAS_XML_SUPPORT
3642 if (OBJECT_IS_XML(cx, obj)) {
3643 JSXMLObjectOps *ops;
3645 ops = (JSXMLObjectOps *) obj->map->ops;
3646 obj = ops->getMethod(cx, obj, id, vp);
3647 if (!obj)
3648 return JS_FALSE;
3649 } else
3650 #endif
3652 if (!OBJ_GET_PROPERTY(cx, obj, id, vp))
3653 return JS_FALSE;
3656 *objp = obj;
3657 return JS_TRUE;
3660 JS_PUBLIC_API(JSBool)
3661 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
3662 jsval *vp)
3664 JSAtom *atom;
3666 atom = js_Atomize(cx, name, strlen(name), 0);
3667 if (!atom)
3668 return JS_FALSE;
3669 return JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), objp, vp);
3672 JS_PUBLIC_API(JSBool)
3673 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3675 JSAtom *atom;
3677 CHECK_REQUEST(cx);
3678 atom = js_Atomize(cx, name, strlen(name), 0);
3679 if (!atom)
3680 return JS_FALSE;
3682 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
3683 return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
3686 JS_PUBLIC_API(JSBool)
3687 JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
3689 CHECK_REQUEST(cx);
3690 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
3691 return OBJ_SET_PROPERTY(cx, obj, id, vp);
3694 JS_PUBLIC_API(JSBool)
3695 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
3697 jsval junk;
3699 return JS_DeleteProperty2(cx, obj, name, &junk);
3702 JS_PUBLIC_API(JSBool)
3703 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name,
3704 jsval *rval)
3706 JSAtom *atom;
3708 CHECK_REQUEST(cx);
3709 atom = js_Atomize(cx, name, strlen(name), 0);
3710 if (!atom)
3711 return JS_FALSE;
3713 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3714 return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
3717 JS_PUBLIC_API(JSBool)
3718 JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id)
3720 jsval junk;
3722 return JS_DeletePropertyById2(cx, obj, id, &junk);
3725 JS_PUBLIC_API(JSBool)
3726 JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
3728 CHECK_REQUEST(cx);
3729 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3730 return OBJ_DELETE_PROPERTY(cx, obj, id, rval);
3733 JS_PUBLIC_API(JSBool)
3734 JS_DefineUCProperty(JSContext *cx, JSObject *obj,
3735 const jschar *name, size_t namelen, jsval value,
3736 JSPropertyOp getter, JSPropertyOp setter,
3737 uintN attrs)
3739 CHECK_REQUEST(cx);
3740 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
3741 attrs, 0, 0);
3744 JS_PUBLIC_API(JSBool)
3745 JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj,
3746 const jschar *name, size_t namelen,
3747 uintN *attrsp, JSBool *foundp)
3749 CHECK_REQUEST(cx);
3750 return GetPropertyAttributes(cx, obj,
3751 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
3752 attrsp, foundp, NULL, NULL);
3755 JS_PUBLIC_API(JSBool)
3756 JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
3757 const jschar *name, size_t namelen,
3758 uintN *attrsp, JSBool *foundp,
3759 JSPropertyOp *getterp,
3760 JSPropertyOp *setterp)
3762 CHECK_REQUEST(cx);
3763 return GetPropertyAttributes(cx, obj,
3764 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
3765 attrsp, foundp, getterp, setterp);
3768 JS_PUBLIC_API(JSBool)
3769 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj,
3770 const jschar *name, size_t namelen,
3771 uintN attrs, JSBool *foundp)
3773 CHECK_REQUEST(cx);
3774 return SetPropertyAttributes(cx, obj,
3775 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
3776 attrs, foundp);
3779 JS_PUBLIC_API(JSBool)
3780 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
3781 const jschar *name, size_t namelen,
3782 int8 tinyid, jsval value,
3783 JSPropertyOp getter, JSPropertyOp setter,
3784 uintN attrs)
3786 CHECK_REQUEST(cx);
3787 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
3788 attrs, SPROP_HAS_SHORTID, tinyid);
3791 JS_PUBLIC_API(JSBool)
3792 JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj,
3793 const jschar *name, size_t namelen,
3794 JSBool *foundp)
3796 JSAtom *atom;
3798 CHECK_REQUEST(cx);
3799 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3800 if (!atom)
3801 return JS_FALSE;
3802 return AlreadyHasOwnPropertyHelper(cx, obj, ATOM_TO_JSID(atom), foundp);
3805 JS_PUBLIC_API(JSBool)
3806 JS_HasUCProperty(JSContext *cx, JSObject *obj,
3807 const jschar *name, size_t namelen,
3808 JSBool *vp)
3810 JSBool ok;
3811 JSObject *obj2;
3812 JSProperty *prop;
3814 CHECK_REQUEST(cx);
3815 ok = LookupUCProperty(cx, obj, name, namelen,
3816 JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3817 &obj2, &prop);
3818 if (ok) {
3819 *vp = (prop != NULL);
3820 if (prop)
3821 OBJ_DROP_PROPERTY(cx, obj2, prop);
3823 return ok;
3826 JS_PUBLIC_API(JSBool)
3827 JS_LookupUCProperty(JSContext *cx, JSObject *obj,
3828 const jschar *name, size_t namelen,
3829 jsval *vp)
3831 JSBool ok;
3832 JSObject *obj2;
3833 JSProperty *prop;
3835 CHECK_REQUEST(cx);
3836 ok = LookupUCProperty(cx, obj, name, namelen, JSRESOLVE_QUALIFIED,
3837 &obj2, &prop);
3838 if (ok)
3839 *vp = LookupResult(cx, obj, obj2, prop);
3840 return ok;
3843 JS_PUBLIC_API(JSBool)
3844 JS_GetUCProperty(JSContext *cx, JSObject *obj,
3845 const jschar *name, size_t namelen,
3846 jsval *vp)
3848 JSAtom *atom;
3850 CHECK_REQUEST(cx);
3851 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3852 if (!atom)
3853 return JS_FALSE;
3855 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3856 return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
3859 JS_PUBLIC_API(JSBool)
3860 JS_SetUCProperty(JSContext *cx, JSObject *obj,
3861 const jschar *name, size_t namelen,
3862 jsval *vp)
3864 JSAtom *atom;
3866 CHECK_REQUEST(cx);
3867 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3868 if (!atom)
3869 return JS_FALSE;
3871 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
3872 return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
3875 JS_PUBLIC_API(JSBool)
3876 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
3877 const jschar *name, size_t namelen,
3878 jsval *rval)
3880 JSAtom *atom;
3882 CHECK_REQUEST(cx);
3883 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3884 if (!atom)
3885 return JS_FALSE;
3887 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3888 return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
3891 JS_PUBLIC_API(JSObject *)
3892 JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
3894 CHECK_REQUEST(cx);
3895 /* NB: jsuint cast does ToUint32. */
3896 return js_NewArrayObject(cx, (jsuint)length, vector);
3899 JS_PUBLIC_API(JSBool)
3900 JS_IsArrayObject(JSContext *cx, JSObject *obj)
3902 return OBJ_IS_ARRAY(cx, obj);
3905 JS_PUBLIC_API(JSBool)
3906 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
3908 CHECK_REQUEST(cx);
3909 return js_GetLengthProperty(cx, obj, lengthp);
3912 JS_PUBLIC_API(JSBool)
3913 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
3915 CHECK_REQUEST(cx);
3916 return js_SetLengthProperty(cx, obj, length);
3919 JS_PUBLIC_API(JSBool)
3920 JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
3922 CHECK_REQUEST(cx);
3923 return js_HasLengthProperty(cx, obj, lengthp);
3926 JS_PUBLIC_API(JSBool)
3927 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
3928 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3930 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
3932 CHECK_REQUEST(cx);
3933 return OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(index), value,
3934 getter, setter, attrs, NULL);
3937 JS_PUBLIC_API(JSBool)
3938 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
3940 JSObject *obj2;
3941 JSProperty *prop;
3942 JSScopeProperty *sprop;
3943 JSBool ok;
3945 CHECK_REQUEST(cx);
3946 if (!LookupProperty(cx, obj, name, JSRESOLVE_QUALIFIED, &obj2, &prop))
3947 return JS_FALSE;
3948 if (!prop) {
3949 js_ReportIsNotDefined(cx, name);
3950 return JS_FALSE;
3952 if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
3953 char numBuf[12];
3954 OBJ_DROP_PROPERTY(cx, obj2, prop);
3955 JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
3956 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3957 numBuf, name, OBJ_GET_CLASS(cx, obj2)->name);
3958 return JS_FALSE;
3960 sprop = (JSScopeProperty *)prop;
3961 ok = (js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
3962 sprop->getter, sprop->setter, sprop->slot,
3963 sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
3964 sprop->shortid)
3965 != NULL);
3966 OBJ_DROP_PROPERTY(cx, obj, prop);
3967 return ok;
3970 JS_PUBLIC_API(JSBool)
3971 JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index,
3972 JSBool *foundp)
3974 return AlreadyHasOwnPropertyHelper(cx, obj, INT_TO_JSID(index), foundp);
3977 JS_PUBLIC_API(JSBool)
3978 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3980 JSBool ok;
3981 JSObject *obj2;
3982 JSProperty *prop;
3984 CHECK_REQUEST(cx);
3985 ok = LookupPropertyById(cx, obj, INT_TO_JSID(index),
3986 JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3987 &obj2, &prop);
3988 if (ok) {
3989 *foundp = (prop != NULL);
3990 if (prop)
3991 OBJ_DROP_PROPERTY(cx, obj2, prop);
3993 return ok;
3996 JS_PUBLIC_API(JSBool)
3997 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3999 JSBool ok;
4000 JSObject *obj2;
4001 JSProperty *prop;
4003 CHECK_REQUEST(cx);
4004 ok = LookupPropertyById(cx, obj, INT_TO_JSID(index), JSRESOLVE_QUALIFIED,
4005 &obj2, &prop);
4006 if (ok)
4007 *vp = LookupResult(cx, obj, obj2, prop);
4008 return ok;
4011 JS_PUBLIC_API(JSBool)
4012 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
4014 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
4016 CHECK_REQUEST(cx);
4017 return OBJ_GET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
4020 JS_PUBLIC_API(JSBool)
4021 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
4023 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
4025 CHECK_REQUEST(cx);
4026 return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
4029 JS_PUBLIC_API(JSBool)
4030 JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
4032 jsval junk;
4034 return JS_DeleteElement2(cx, obj, index, &junk);
4037 JS_PUBLIC_API(JSBool)
4038 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
4040 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
4042 CHECK_REQUEST(cx);
4043 return OBJ_DELETE_PROPERTY(cx, obj, INT_TO_JSID(index), rval);
4046 JS_PUBLIC_API(void)
4047 JS_ClearScope(JSContext *cx, JSObject *obj)
4049 CHECK_REQUEST(cx);
4051 if (obj->map->ops->clear)
4052 obj->map->ops->clear(cx, obj);
4054 /* Clear cached class objects on the global object. */
4055 if (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL) {
4056 int key;
4058 for (key = JSProto_Null; key < JSProto_LIMIT; key++)
4059 JS_SetReservedSlot(cx, obj, key, JSVAL_VOID);
4063 JS_PUBLIC_API(JSIdArray *)
4064 JS_Enumerate(JSContext *cx, JSObject *obj)
4066 jsint i, n;
4067 jsval iter_state, num_properties;
4068 jsid id;
4069 JSIdArray *ida;
4070 jsval *vector;
4072 CHECK_REQUEST(cx);
4074 ida = NULL;
4075 iter_state = JSVAL_NULL;
4077 /* Get the number of properties to enumerate. */
4078 if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, &num_properties))
4079 goto error;
4080 if (!JSVAL_IS_INT(num_properties)) {
4081 JS_ASSERT(0);
4082 goto error;
4085 /* Grow as needed if we don't know the exact amount ahead of time. */
4086 n = JSVAL_TO_INT(num_properties);
4087 if (n <= 0)
4088 n = 8;
4090 /* Create an array of jsids large enough to hold all the properties */
4091 ida = NewIdArray(cx, n);
4092 if (!ida)
4093 goto error;
4095 i = 0;
4096 vector = &ida->vector[0];
4097 for (;;) {
4098 if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &id))
4099 goto error;
4101 /* No more jsid's to enumerate ? */
4102 if (iter_state == JSVAL_NULL)
4103 break;
4105 if (i == ida->length) {
4106 ida = SetIdArrayLength(cx, ida, ida->length * 2);
4107 if (!ida)
4108 goto error;
4109 vector = &ida->vector[0];
4111 vector[i++] = id;
4113 return SetIdArrayLength(cx, ida, i);
4115 error:
4116 if (iter_state != JSVAL_NULL)
4117 OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0);
4118 if (ida)
4119 JS_DestroyIdArray(cx, ida);
4120 return NULL;
4124 * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
4125 * prop_iterator_class somehow...
4126 * + preserve the OBJ_ENUMERATE API while optimizing the native object case
4127 * + native case here uses a JSScopeProperty *, but that iterates in reverse!
4128 * + so we make non-native match, by reverse-iterating after JS_Enumerating
4130 #define JSSLOT_ITER_INDEX (JSSLOT_PRIVATE + 1)
4132 #if JSSLOT_ITER_INDEX >= JS_INITIAL_NSLOTS
4133 # error "JSSLOT_ITER_INDEX botch!"
4134 #endif
4136 static void
4137 prop_iter_finalize(JSContext *cx, JSObject *obj)
4139 jsval v;
4140 jsint i;
4141 JSIdArray *ida;
4143 v = obj->fslots[JSSLOT_ITER_INDEX];
4144 if (JSVAL_IS_VOID(v))
4145 return;
4147 i = JSVAL_TO_INT(v);
4148 if (i >= 0) {
4149 /* Non-native case: destroy the ida enumerated when obj was created. */
4150 ida = (JSIdArray *) JS_GetPrivate(cx, obj);
4151 if (ida)
4152 JS_DestroyIdArray(cx, ida);
4156 static void
4157 prop_iter_trace(JSTracer *trc, JSObject *obj)
4159 jsval v;
4160 jsint i, n;
4161 JSScopeProperty *sprop;
4162 JSIdArray *ida;
4163 jsid id;
4165 v = obj->fslots[JSSLOT_PRIVATE];
4166 JS_ASSERT(!JSVAL_IS_VOID(v));
4168 i = JSVAL_TO_INT(obj->fslots[JSSLOT_ITER_INDEX]);
4169 if (i < 0) {
4170 /* Native case: just mark the next property to visit. */
4171 sprop = (JSScopeProperty *) JSVAL_TO_PRIVATE(v);
4172 if (sprop)
4173 TRACE_SCOPE_PROPERTY(trc, sprop);
4174 } else {
4175 /* Non-native case: mark each id in the JSIdArray private. */
4176 ida = (JSIdArray *) JSVAL_TO_PRIVATE(v);
4177 for (i = 0, n = ida->length; i < n; i++) {
4178 id = ida->vector[i];
4179 TRACE_ID(trc, id);
4184 static JSClass prop_iter_class = {
4185 "PropertyIterator",
4186 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
4187 JSCLASS_MARK_IS_TRACE,
4188 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
4189 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, prop_iter_finalize,
4190 NULL, NULL, NULL, NULL,
4191 NULL, NULL, JS_CLASS_TRACE(prop_iter_trace), NULL
4194 JS_PUBLIC_API(JSObject *)
4195 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
4197 JSObject *iterobj;
4198 JSScope *scope;
4199 void *pdata;
4200 jsint index;
4201 JSIdArray *ida;
4203 CHECK_REQUEST(cx);
4204 iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj, 0);
4205 if (!iterobj)
4206 return NULL;
4208 if (OBJ_IS_NATIVE(obj)) {
4209 /* Native case: start with the last property in obj's own scope. */
4210 scope = OBJ_SCOPE(obj);
4211 pdata = (scope->object == obj) ? scope->lastProp : NULL;
4212 index = -1;
4213 } else {
4214 JSTempValueRooter tvr;
4217 * Non-native case: enumerate a JSIdArray and keep it via private.
4219 * Note: we have to make sure that we root obj around the call to
4220 * JS_Enumerate to protect against multiple allocations under it.
4222 JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(iterobj), &tvr);
4223 ida = JS_Enumerate(cx, obj);
4224 JS_POP_TEMP_ROOT(cx, &tvr);
4225 if (!ida)
4226 goto bad;
4227 pdata = ida;
4228 index = ida->length;
4231 /* iterobj can not escape to other threads here. */
4232 STOBJ_SET_SLOT(iterobj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(pdata));
4233 STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(index));
4234 return iterobj;
4236 bad:
4237 cx->weakRoots.newborn[GCX_OBJECT] = NULL;
4238 return NULL;
4241 JS_PUBLIC_API(JSBool)
4242 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
4244 jsint i;
4245 JSObject *obj;
4246 JSScope *scope;
4247 JSScopeProperty *sprop;
4248 JSIdArray *ida;
4250 CHECK_REQUEST(cx);
4251 i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX));
4252 if (i < 0) {
4253 /* Native case: private data is a property tree node pointer. */
4254 obj = OBJ_GET_PARENT(cx, iterobj);
4255 JS_ASSERT(OBJ_IS_NATIVE(obj));
4256 scope = OBJ_SCOPE(obj);
4257 JS_ASSERT(scope->object == obj);
4258 sprop = (JSScopeProperty *) JS_GetPrivate(cx, iterobj);
4261 * If the next property mapped by scope in the property tree ancestor
4262 * line is not enumerable, or it's an alias, or one or more properties
4263 * were deleted from the "middle" of the scope-mapped ancestor line
4264 * and the next property was among those deleted, skip it and keep on
4265 * trying to find an enumerable property that is still in scope.
4267 while (sprop &&
4268 (!(sprop->attrs & JSPROP_ENUMERATE) ||
4269 (sprop->flags & SPROP_IS_ALIAS) ||
4270 (SCOPE_HAD_MIDDLE_DELETE(scope) &&
4271 !SCOPE_HAS_PROPERTY(scope, sprop)))) {
4272 sprop = sprop->parent;
4275 if (!sprop) {
4276 *idp = JSVAL_VOID;
4277 } else {
4278 if (!JS_SetPrivate(cx, iterobj, sprop->parent))
4279 return JS_FALSE;
4280 *idp = sprop->id;
4282 } else {
4283 /* Non-native case: use the ida enumerated when iterobj was created. */
4284 ida = (JSIdArray *) JS_GetPrivate(cx, iterobj);
4285 JS_ASSERT(i <= ida->length);
4286 if (i == 0) {
4287 *idp = JSVAL_VOID;
4288 } else {
4289 *idp = ida->vector[--i];
4290 STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(i));
4293 return JS_TRUE;
4296 JS_PUBLIC_API(JSBool)
4297 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
4298 jsval *vp, uintN *attrsp)
4300 CHECK_REQUEST(cx);
4301 return OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, attrsp);
4304 static JSBool
4305 ReservedSlotIndexOK(JSContext *cx, JSObject *obj, JSClass *clasp,
4306 uint32 index, uint32 limit)
4308 /* Check the computed, possibly per-instance, upper bound. */
4309 if (clasp->reserveSlots)
4310 JS_LOCK_OBJ_VOID(cx, obj, limit += clasp->reserveSlots(cx, obj));
4311 if (index >= limit) {
4312 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4313 JSMSG_RESERVED_SLOT_RANGE);
4314 return JS_FALSE;
4316 return JS_TRUE;
4319 JS_PUBLIC_API(JSBool)
4320 JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
4322 JSClass *clasp;
4323 uint32 limit, slot;
4325 CHECK_REQUEST(cx);
4326 clasp = OBJ_GET_CLASS(cx, obj);
4327 limit = JSCLASS_RESERVED_SLOTS(clasp);
4328 if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
4329 return JS_FALSE;
4330 slot = JSSLOT_START(clasp) + index;
4331 *vp = OBJ_GET_REQUIRED_SLOT(cx, obj, slot);
4332 return JS_TRUE;
4335 JS_PUBLIC_API(JSBool)
4336 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
4338 JSClass *clasp;
4339 uint32 limit, slot;
4341 CHECK_REQUEST(cx);
4342 clasp = OBJ_GET_CLASS(cx, obj);
4343 limit = JSCLASS_RESERVED_SLOTS(clasp);
4344 if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
4345 return JS_FALSE;
4346 slot = JSSLOT_START(clasp) + index;
4347 return OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v);
4350 #ifdef JS_THREADSAFE
4351 JS_PUBLIC_API(jsrefcount)
4352 JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
4354 return JS_ATOMIC_INCREMENT(&principals->refcount);
4357 JS_PUBLIC_API(jsrefcount)
4358 JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
4360 jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
4361 if (rc == 0)
4362 principals->destroy(cx, principals);
4363 return rc;
4365 #endif
4367 JS_PUBLIC_API(JSSecurityCallbacks *)
4368 JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks)
4370 JSSecurityCallbacks *oldcallbacks;
4372 oldcallbacks = rt->securityCallbacks;
4373 rt->securityCallbacks = callbacks;
4374 return oldcallbacks;
4377 JS_PUBLIC_API(JSSecurityCallbacks *)
4378 JS_GetRuntimeSecurityCallbacks(JSRuntime *rt)
4380 return rt->securityCallbacks;
4383 JS_PUBLIC_API(JSSecurityCallbacks *)
4384 JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks)
4386 JSSecurityCallbacks *oldcallbacks;
4388 oldcallbacks = cx->securityCallbacks;
4389 cx->securityCallbacks = callbacks;
4390 return oldcallbacks;
4393 JS_PUBLIC_API(JSSecurityCallbacks *)
4394 JS_GetSecurityCallbacks(JSContext *cx)
4396 return cx->securityCallbacks
4397 ? cx->securityCallbacks
4398 : cx->runtime->securityCallbacks;
4401 JS_PUBLIC_API(JSFunction *)
4402 JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
4403 JSObject *parent, const char *name)
4405 JSAtom *atom;
4407 CHECK_REQUEST(cx);
4409 if (!name) {
4410 atom = NULL;
4411 } else {
4412 atom = js_Atomize(cx, name, strlen(name), 0);
4413 if (!atom)
4414 return NULL;
4416 return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom);
4419 JS_PUBLIC_API(JSObject *)
4420 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
4422 CHECK_REQUEST(cx);
4423 if (OBJ_GET_CLASS(cx, funobj) != &js_FunctionClass) {
4424 /* Indicate we cannot clone this object. */
4425 return funobj;
4427 return js_CloneFunctionObject(cx, GET_FUNCTION_PRIVATE(cx, funobj), parent);
4430 JS_PUBLIC_API(JSObject *)
4431 JS_GetFunctionObject(JSFunction *fun)
4433 return FUN_OBJECT(fun);
4436 JS_PUBLIC_API(const char *)
4437 JS_GetFunctionName(JSFunction *fun)
4439 return fun->atom
4440 ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
4441 : js_anonymous_str;
4444 JS_PUBLIC_API(JSString *)
4445 JS_GetFunctionId(JSFunction *fun)
4447 return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
4450 JS_PUBLIC_API(uintN)
4451 JS_GetFunctionFlags(JSFunction *fun)
4453 #ifdef MOZILLA_1_8_BRANCH
4454 uintN flags = fun->flags;
4456 return JSFUN_DISJOINT_FLAGS(flags) |
4457 (JSFUN_GETTER_TEST(flags) ? JSFUN_GETTER : 0) |
4458 (JSFUN_SETTER_TEST(flags) ? JSFUN_SETTER : 0) |
4459 (JSFUN_BOUND_METHOD_TEST(flags) ? JSFUN_BOUND_METHOD : 0) |
4460 (JSFUN_HEAVYWEIGHT_TEST(flags) ? JSFUN_HEAVYWEIGHT : 0);
4461 #else
4462 return fun->flags;
4463 #endif
4466 JS_PUBLIC_API(uint16)
4467 JS_GetFunctionArity(JSFunction *fun)
4469 return fun->nargs;
4472 JS_PUBLIC_API(JSBool)
4473 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
4475 return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass;
4478 JS_BEGIN_EXTERN_C
4479 static JSBool
4480 js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, jsval *vp)
4482 jsval fsv;
4483 JSFunctionSpec *fs;
4484 JSObject *tmp;
4485 JSFastNative native;
4487 if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(*vp), 0, &fsv))
4488 return JS_FALSE;
4489 fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv);
4490 JS_ASSERT((~fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) == 0);
4493 * We know that vp[2] is valid because JS_DefineFunctions, which is our
4494 * only (indirect) referrer, defined us as requiring at least one argument
4495 * (notice how it passes fs->nargs + 1 as the next-to-last argument to
4496 * JS_DefineFunction).
4498 if (JSVAL_IS_PRIMITIVE(vp[2])) {
4500 * Make sure that this is an object or null, as required by the generic
4501 * functions.
4503 if (!js_ValueToObject(cx, vp[2], &tmp))
4504 return JS_FALSE;
4505 vp[2] = OBJECT_TO_JSVAL(tmp);
4509 * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
4510 * which is almost always the class constructor object, e.g. Array. Then
4511 * call the corresponding prototype native method with our first argument
4512 * passed as |this|.
4514 memmove(vp + 1, vp + 2, argc * sizeof(jsval));
4517 * Follow Function.prototype.apply and .call by using the global object as
4518 * the 'this' param if no args.
4520 if (!js_ComputeThis(cx, JS_FALSE, vp + 2))
4521 return JS_FALSE;
4523 * Protect against argc underflowing. By calling js_ComputeThis, we made
4524 * it as if the static was called with one parameter, the explicit |this|
4525 * object.
4527 if (argc != 0)
4528 --argc;
4530 native =
4531 #ifdef JS_TRACER
4532 (fs->flags & JSFUN_TRACEABLE)
4533 ? ((JSTraceableNative *) fs->call)->native
4535 #endif
4536 (JSFastNative) fs->call;
4537 return native(cx, argc, vp);
4540 static JSBool
4541 js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
4542 uintN argc, jsval *argv, jsval *rval)
4544 jsval fsv;
4545 JSFunctionSpec *fs;
4546 JSObject *tmp;
4548 if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &fsv))
4549 return JS_FALSE;
4550 fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv);
4551 JS_ASSERT((fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) ==
4552 JSFUN_GENERIC_NATIVE);
4555 * We know that argv[0] is valid because JS_DefineFunctions, which is our
4556 * only (indirect) referrer, defined us as requiring at least one argument
4557 * (notice how it passes fs->nargs + 1 as the next-to-last argument to
4558 * JS_DefineFunction).
4560 if (JSVAL_IS_PRIMITIVE(argv[0])) {
4562 * Make sure that this is an object or null, as required by the generic
4563 * functions.
4565 if (!js_ValueToObject(cx, argv[0], &tmp))
4566 return JS_FALSE;
4567 argv[0] = OBJECT_TO_JSVAL(tmp);
4571 * Copy all actual (argc) arguments down over our |this| parameter,
4572 * argv[-1], which is almost always the class constructor object, e.g.
4573 * Array. Then call the corresponding prototype native method with our
4574 * first argument passed as |this|.
4576 memmove(argv - 1, argv, argc * sizeof(jsval));
4579 * Follow Function.prototype.apply and .call by using the global object as
4580 * the 'this' param if no args.
4582 if (!js_ComputeThis(cx, JS_TRUE, argv))
4583 return JS_FALSE;
4584 js_GetTopStackFrame(cx)->thisp = JSVAL_TO_OBJECT(argv[-1]);
4585 JS_ASSERT(cx->fp->argv == argv);
4588 * Protect against argc underflowing. By calling js_ComputeThis, we made
4589 * it as if the static was called with one parameter, the explicit |this|
4590 * object.
4592 if (argc != 0)
4593 --argc;
4595 return fs->call(cx, JSVAL_TO_OBJECT(argv[-1]), argc, argv, rval);
4597 JS_END_EXTERN_C
4599 JS_PUBLIC_API(JSBool)
4600 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
4602 uintN flags;
4603 JSObject *ctor;
4604 JSFunction *fun;
4606 CHECK_REQUEST(cx);
4607 ctor = NULL;
4608 for (; fs->name; fs++) {
4609 flags = fs->flags;
4612 * Define a generic arity N+1 static method for the arity N prototype
4613 * method if flags contains JSFUN_GENERIC_NATIVE.
4615 if (flags & JSFUN_GENERIC_NATIVE) {
4616 if (!ctor) {
4617 ctor = JS_GetConstructor(cx, obj);
4618 if (!ctor)
4619 return JS_FALSE;
4622 flags &= ~JSFUN_GENERIC_NATIVE;
4623 fun = JS_DefineFunction(cx, ctor, fs->name,
4624 (flags & JSFUN_FAST_NATIVE)
4625 ? (JSNative)
4626 js_generic_fast_native_method_dispatcher
4627 : js_generic_native_method_dispatcher,
4628 fs->nargs + 1,
4629 flags & ~JSFUN_TRACEABLE);
4630 if (!fun)
4631 return JS_FALSE;
4632 fun->u.n.extra = (uint16)fs->extra;
4635 * As jsapi.h notes, fs must point to storage that lives as long
4636 * as fun->object lives.
4638 if (!JS_SetReservedSlot(cx, FUN_OBJECT(fun), 0, PRIVATE_TO_JSVAL(fs)))
4639 return JS_FALSE;
4642 JS_ASSERT(!(flags & JSFUN_FAST_NATIVE) ||
4643 (uint16)(fs->extra >> 16) <= fs->nargs);
4644 fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
4645 if (!fun)
4646 return JS_FALSE;
4647 fun->u.n.extra = (uint16)fs->extra;
4649 return JS_TRUE;
4652 JS_PUBLIC_API(JSFunction *)
4653 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
4654 uintN nargs, uintN attrs)
4656 JSAtom *atom;
4658 CHECK_REQUEST(cx);
4659 atom = js_Atomize(cx, name, strlen(name), 0);
4660 if (!atom)
4661 return NULL;
4662 return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
4665 JS_PUBLIC_API(JSFunction *)
4666 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
4667 const jschar *name, size_t namelen, JSNative call,
4668 uintN nargs, uintN attrs)
4670 JSAtom *atom;
4672 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
4673 if (!atom)
4674 return NULL;
4675 return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
4678 JS_PUBLIC_API(JSScript *)
4679 JS_CompileScript(JSContext *cx, JSObject *obj,
4680 const char *bytes, size_t length,
4681 const char *filename, uintN lineno)
4683 jschar *chars;
4684 JSScript *script;
4686 CHECK_REQUEST(cx);
4687 chars = js_InflateString(cx, bytes, &length);
4688 if (!chars)
4689 return NULL;
4690 script = JS_CompileUCScript(cx, obj, chars, length, filename, lineno);
4691 JS_free(cx, chars);
4692 return script;
4695 JS_PUBLIC_API(JSScript *)
4696 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
4697 JSPrincipals *principals,
4698 const char *bytes, size_t length,
4699 const char *filename, uintN lineno)
4701 jschar *chars;
4702 JSScript *script;
4704 CHECK_REQUEST(cx);
4705 chars = js_InflateString(cx, bytes, &length);
4706 if (!chars)
4707 return NULL;
4708 script = JS_CompileUCScriptForPrincipals(cx, obj, principals,
4709 chars, length, filename, lineno);
4710 JS_free(cx, chars);
4711 return script;
4714 JS_PUBLIC_API(JSScript *)
4715 JS_CompileUCScript(JSContext *cx, JSObject *obj,
4716 const jschar *chars, size_t length,
4717 const char *filename, uintN lineno)
4719 CHECK_REQUEST(cx);
4720 return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length,
4721 filename, lineno);
4724 #define LAST_FRAME_EXCEPTION_CHECK(cx,result) \
4725 JS_BEGIN_MACRO \
4726 if (!(result) && !((cx)->options & JSOPTION_DONT_REPORT_UNCAUGHT)) \
4727 js_ReportUncaughtException(cx); \
4728 JS_END_MACRO
4730 #define LAST_FRAME_CHECKS(cx,result) \
4731 JS_BEGIN_MACRO \
4732 if (!JS_IsRunning(cx)) { \
4733 (cx)->weakRoots.lastInternalResult = JSVAL_NULL; \
4734 LAST_FRAME_EXCEPTION_CHECK(cx, result); \
4736 JS_END_MACRO
4738 #define JS_OPTIONS_TO_TCFLAGS(cx) \
4739 ((((cx)->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) | \
4740 (((cx)->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0))
4742 JS_PUBLIC_API(JSScript *)
4743 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
4744 JSPrincipals *principals,
4745 const jschar *chars, size_t length,
4746 const char *filename, uintN lineno)
4748 uint32 tcflags;
4749 JSScript *script;
4751 CHECK_REQUEST(cx);
4752 tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
4753 script = js_CompileScript(cx, obj, NULL, principals, tcflags,
4754 chars, length, NULL, filename, lineno);
4755 LAST_FRAME_CHECKS(cx, script);
4756 return script;
4759 JS_PUBLIC_API(JSBool)
4760 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
4761 const char *bytes, size_t length)
4763 jschar *chars;
4764 JSBool result;
4765 JSExceptionState *exnState;
4766 JSParseContext pc;
4767 JSErrorReporter older;
4769 CHECK_REQUEST(cx);
4770 chars = js_InflateString(cx, bytes, &length);
4771 if (!chars)
4772 return JS_TRUE;
4775 * Return true on any out-of-memory error, so our caller doesn't try to
4776 * collect more buffered source.
4778 result = JS_TRUE;
4779 exnState = JS_SaveExceptionState(cx);
4780 if (js_InitParseContext(cx, &pc, NULL, NULL, chars, length, NULL, NULL,
4781 1)) {
4782 older = JS_SetErrorReporter(cx, NULL);
4783 if (!js_ParseScript(cx, obj, &pc) &&
4784 (pc.tokenStream.flags & TSF_UNEXPECTED_EOF)) {
4786 * We ran into an error. If it was because we ran out of source,
4787 * we return false, so our caller will know to try to collect more
4788 * buffered source.
4790 result = JS_FALSE;
4792 JS_SetErrorReporter(cx, older);
4793 js_FinishParseContext(cx, &pc);
4795 JS_free(cx, chars);
4796 JS_RestoreExceptionState(cx, exnState);
4797 return result;
4800 JS_PUBLIC_API(JSScript *)
4801 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
4803 FILE *fp;
4804 uint32 tcflags;
4805 JSScript *script;
4807 CHECK_REQUEST(cx);
4808 if (!filename || strcmp(filename, "-") == 0) {
4809 fp = stdin;
4810 } else {
4811 fp = fopen(filename, "r");
4812 if (!fp) {
4813 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
4814 filename, "No such file or directory");
4815 return NULL;
4819 tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
4820 script = js_CompileScript(cx, obj, NULL, NULL, tcflags,
4821 NULL, 0, fp, filename, 1);
4822 if (fp != stdin)
4823 fclose(fp);
4824 LAST_FRAME_CHECKS(cx, script);
4825 return script;
4828 JS_PUBLIC_API(JSScript *)
4829 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename,
4830 FILE *file)
4832 return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
4835 JS_PUBLIC_API(JSScript *)
4836 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
4837 const char *filename, FILE *file,
4838 JSPrincipals *principals)
4840 uint32 tcflags;
4841 JSScript *script;
4843 CHECK_REQUEST(cx);
4844 tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
4845 script = js_CompileScript(cx, obj, NULL, principals, tcflags,
4846 NULL, 0, file, filename, 1);
4847 LAST_FRAME_CHECKS(cx, script);
4848 return script;
4851 JS_PUBLIC_API(JSObject *)
4852 JS_NewScriptObject(JSContext *cx, JSScript *script)
4854 JSTempValueRooter tvr;
4855 JSObject *obj;
4857 CHECK_REQUEST(cx);
4858 if (!script)
4859 return js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0);
4861 JS_ASSERT(!script->u.object);
4863 JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr);
4864 obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0);
4865 if (obj) {
4866 JS_SetPrivate(cx, obj, script);
4867 script->u.object = obj;
4868 #ifdef CHECK_SCRIPT_OWNER
4869 script->owner = NULL;
4870 #endif
4872 JS_POP_TEMP_ROOT(cx, &tvr);
4873 return obj;
4876 JS_PUBLIC_API(JSObject *)
4877 JS_GetScriptObject(JSScript *script)
4879 return script->u.object;
4882 JS_PUBLIC_API(void)
4883 JS_DestroyScript(JSContext *cx, JSScript *script)
4885 CHECK_REQUEST(cx);
4886 js_DestroyScript(cx, script);
4889 JS_PUBLIC_API(JSFunction *)
4890 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
4891 uintN nargs, const char **argnames,
4892 const char *bytes, size_t length,
4893 const char *filename, uintN lineno)
4895 jschar *chars;
4896 JSFunction *fun;
4898 CHECK_REQUEST(cx);
4899 chars = js_InflateString(cx, bytes, &length);
4900 if (!chars)
4901 return NULL;
4902 fun = JS_CompileUCFunction(cx, obj, name, nargs, argnames, chars, length,
4903 filename, lineno);
4904 JS_free(cx, chars);
4905 return fun;
4908 JS_PUBLIC_API(JSFunction *)
4909 JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
4910 JSPrincipals *principals, const char *name,
4911 uintN nargs, const char **argnames,
4912 const char *bytes, size_t length,
4913 const char *filename, uintN lineno)
4915 jschar *chars;
4916 JSFunction *fun;
4918 CHECK_REQUEST(cx);
4919 chars = js_InflateString(cx, bytes, &length);
4920 if (!chars)
4921 return NULL;
4922 fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
4923 nargs, argnames, chars, length,
4924 filename, lineno);
4925 JS_free(cx, chars);
4926 return fun;
4929 JS_PUBLIC_API(JSFunction *)
4930 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
4931 uintN nargs, const char **argnames,
4932 const jschar *chars, size_t length,
4933 const char *filename, uintN lineno)
4935 CHECK_REQUEST(cx);
4936 return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name,
4937 nargs, argnames,
4938 chars, length,
4939 filename, lineno);
4942 JS_PUBLIC_API(JSFunction *)
4943 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
4944 JSPrincipals *principals, const char *name,
4945 uintN nargs, const char **argnames,
4946 const jschar *chars, size_t length,
4947 const char *filename, uintN lineno)
4949 JSFunction *fun;
4950 JSTempValueRooter tvr;
4951 JSAtom *funAtom, *argAtom;
4952 uintN i;
4954 CHECK_REQUEST(cx);
4955 if (!name) {
4956 funAtom = NULL;
4957 } else {
4958 funAtom = js_Atomize(cx, name, strlen(name), 0);
4959 if (!funAtom) {
4960 fun = NULL;
4961 goto out2;
4964 fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
4965 if (!fun)
4966 goto out2;
4968 MUST_FLOW_THROUGH("out");
4969 JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr);
4970 for (i = 0; i < nargs; i++) {
4971 argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
4972 if (!argAtom) {
4973 fun = NULL;
4974 goto out;
4976 if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) {
4977 fun = NULL;
4978 goto out;
4982 if (!js_CompileFunctionBody(cx, fun, principals, chars, length,
4983 filename, lineno)) {
4984 fun = NULL;
4985 goto out;
4988 if (obj &&
4989 funAtom &&
4990 !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(funAtom),
4991 OBJECT_TO_JSVAL(FUN_OBJECT(fun)),
4992 NULL, NULL, JSPROP_ENUMERATE, NULL)) {
4993 fun = NULL;
4996 #ifdef JS_SCOPE_DEPTH_METER
4997 if (fun && obj) {
4998 JSObject *pobj = obj;
4999 uintN depth = 1;
5001 while ((pobj = OBJ_GET_PARENT(cx, pobj)) != NULL)
5002 ++depth;
5003 JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
5005 #endif
5007 out:
5008 cx->weakRoots.newborn[JSTRACE_OBJECT] = FUN_OBJECT(fun);
5009 JS_POP_TEMP_ROOT(cx, &tvr);
5011 out2:
5012 LAST_FRAME_CHECKS(cx, fun);
5013 return fun;
5016 JS_PUBLIC_API(JSString *)
5017 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
5018 uintN indent)
5020 JSPrinter *jp;
5021 JSString *str;
5023 CHECK_REQUEST(cx);
5024 jp = JS_NEW_PRINTER(cx, name, NULL,
5025 indent & ~JS_DONT_PRETTY_PRINT,
5026 !(indent & JS_DONT_PRETTY_PRINT));
5027 if (!jp)
5028 return NULL;
5029 if (js_DecompileScript(jp, script))
5030 str = js_GetPrinterOutput(jp);
5031 else
5032 str = NULL;
5033 js_DestroyPrinter(jp);
5034 return str;
5037 JS_PUBLIC_API(JSString *)
5038 JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
5040 JSPrinter *jp;
5041 JSString *str;
5043 CHECK_REQUEST(cx);
5044 jp = JS_NEW_PRINTER(cx, "JS_DecompileFunction", fun,
5045 indent & ~JS_DONT_PRETTY_PRINT,
5046 !(indent & JS_DONT_PRETTY_PRINT));
5047 if (!jp)
5048 return NULL;
5049 if (js_DecompileFunction(jp))
5050 str = js_GetPrinterOutput(jp);
5051 else
5052 str = NULL;
5053 js_DestroyPrinter(jp);
5054 return str;
5057 JS_PUBLIC_API(JSString *)
5058 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
5060 JSPrinter *jp;
5061 JSString *str;
5063 CHECK_REQUEST(cx);
5064 jp = JS_NEW_PRINTER(cx, "JS_DecompileFunctionBody", fun,
5065 indent & ~JS_DONT_PRETTY_PRINT,
5066 !(indent & JS_DONT_PRETTY_PRINT));
5067 if (!jp)
5068 return NULL;
5069 if (js_DecompileFunctionBody(jp))
5070 str = js_GetPrinterOutput(jp);
5071 else
5072 str = NULL;
5073 js_DestroyPrinter(jp);
5074 return str;
5077 JS_PUBLIC_API(JSBool)
5078 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
5080 JSBool ok;
5082 CHECK_REQUEST(cx);
5083 ok = js_Execute(cx, obj, script, NULL, 0, rval);
5084 LAST_FRAME_CHECKS(cx, ok);
5085 return ok;
5088 JS_PUBLIC_API(JSBool)
5089 JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script,
5090 JSExecPart part, jsval *rval)
5092 JSScript tmp;
5093 JSDebugHooks *hooks;
5094 JSBool ok;
5096 /* Make a temporary copy of the JSScript structure and farble it a bit. */
5097 tmp = *script;
5098 if (part == JSEXEC_PROLOG) {
5099 tmp.length = PTRDIFF(tmp.main, tmp.code, jsbytecode);
5100 } else {
5101 tmp.length -= PTRDIFF(tmp.main, tmp.code, jsbytecode);
5102 tmp.code = tmp.main;
5105 /* Tell the debugger about our temporary copy of the script structure. */
5106 hooks = cx->debugHooks;
5107 if (hooks->newScriptHook) {
5108 hooks->newScriptHook(cx, tmp.filename, tmp.lineno, &tmp, NULL,
5109 hooks->newScriptHookData);
5112 /* Execute the farbled struct and tell the debugger to forget about it. */
5113 ok = JS_ExecuteScript(cx, obj, &tmp, rval);
5114 if (hooks->destroyScriptHook)
5115 hooks->destroyScriptHook(cx, &tmp, hooks->destroyScriptHookData);
5116 return ok;
5119 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
5120 JS_PUBLIC_API(JSBool)
5121 JS_EvaluateScript(JSContext *cx, JSObject *obj,
5122 const char *bytes, uintN nbytes,
5123 const char *filename, uintN lineno,
5124 jsval *rval)
5126 size_t length = nbytes;
5127 jschar *chars;
5128 JSBool ok;
5130 CHECK_REQUEST(cx);
5131 chars = js_InflateString(cx, bytes, &length);
5132 if (!chars)
5133 return JS_FALSE;
5134 ok = JS_EvaluateUCScript(cx, obj, chars, length, filename, lineno, rval);
5135 JS_free(cx, chars);
5136 return ok;
5139 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
5140 JS_PUBLIC_API(JSBool)
5141 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj,
5142 JSPrincipals *principals,
5143 const char *bytes, uintN nbytes,
5144 const char *filename, uintN lineno,
5145 jsval *rval)
5147 size_t length = nbytes;
5148 jschar *chars;
5149 JSBool ok;
5151 CHECK_REQUEST(cx);
5152 chars = js_InflateString(cx, bytes, &length);
5153 if (!chars)
5154 return JS_FALSE;
5155 ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
5156 filename, lineno, rval);
5157 JS_free(cx, chars);
5158 return ok;
5161 JS_PUBLIC_API(JSBool)
5162 JS_EvaluateUCScript(JSContext *cx, JSObject *obj,
5163 const jschar *chars, uintN length,
5164 const char *filename, uintN lineno,
5165 jsval *rval)
5167 CHECK_REQUEST(cx);
5168 return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length,
5169 filename, lineno, rval);
5172 JS_PUBLIC_API(JSBool)
5173 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
5174 JSPrincipals *principals,
5175 const jschar *chars, uintN length,
5176 const char *filename, uintN lineno,
5177 jsval *rval)
5179 JSScript *script;
5180 JSBool ok;
5182 CHECK_REQUEST(cx);
5183 script = js_CompileScript(cx, obj, NULL, principals,
5184 !rval
5185 ? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
5186 : TCF_COMPILE_N_GO,
5187 chars, length, NULL, filename, lineno);
5188 if (!script) {
5189 LAST_FRAME_CHECKS(cx, script);
5190 return JS_FALSE;
5192 ok = js_Execute(cx, obj, script, NULL, 0, rval);
5193 LAST_FRAME_CHECKS(cx, ok);
5194 JS_DestroyScript(cx, script);
5195 return ok;
5198 JS_PUBLIC_API(JSBool)
5199 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc,
5200 jsval *argv, jsval *rval)
5202 JSBool ok;
5204 CHECK_REQUEST(cx);
5205 ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(FUN_OBJECT(fun)), argc, argv,
5206 rval);
5207 LAST_FRAME_CHECKS(cx, ok);
5208 return ok;
5211 JS_PUBLIC_API(JSBool)
5212 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
5213 jsval *argv, jsval *rval)
5215 JSBool ok;
5216 jsval fval;
5218 CHECK_REQUEST(cx);
5219 #if JS_HAS_XML_SUPPORT
5220 if (OBJECT_IS_XML(cx, obj)) {
5221 JSXMLObjectOps *ops;
5222 JSAtom *atom;
5224 ops = (JSXMLObjectOps *) obj->map->ops;
5225 atom = js_Atomize(cx, name, strlen(name), 0);
5226 if (!atom)
5227 return JS_FALSE;
5228 obj = ops->getMethod(cx, obj, ATOM_TO_JSID(atom), &fval);
5229 if (!obj)
5230 return JS_FALSE;
5231 } else
5232 #endif
5233 if (!JS_GetProperty(cx, obj, name, &fval))
5234 return JS_FALSE;
5235 ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
5236 LAST_FRAME_CHECKS(cx, ok);
5237 return ok;
5240 JS_PUBLIC_API(JSBool)
5241 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
5242 jsval *argv, jsval *rval)
5244 JSBool ok;
5246 CHECK_REQUEST(cx);
5247 ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
5248 LAST_FRAME_CHECKS(cx, ok);
5249 return ok;
5252 JS_PUBLIC_API(void)
5253 JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback,
5254 uint32 operationLimit)
5256 JS_ASSERT(callback);
5257 JS_ASSERT(operationLimit <= JS_MAX_OPERATION_LIMIT);
5258 JS_ASSERT(operationLimit > 0);
5260 cx->operationCount = (int32) operationLimit;
5261 cx->operationLimit = operationLimit;
5262 cx->operationCallbackIsSet = 1;
5263 cx->operationCallback = callback;
5266 JS_PUBLIC_API(void)
5267 JS_ClearOperationCallback(JSContext *cx)
5269 cx->operationCount = (int32) JS_MAX_OPERATION_LIMIT;
5270 cx->operationLimit = JS_MAX_OPERATION_LIMIT;
5271 cx->operationCallbackIsSet = 0;
5272 cx->operationCallback = NULL;
5275 JS_PUBLIC_API(JSOperationCallback)
5276 JS_GetOperationCallback(JSContext *cx)
5278 JS_ASSERT(cx->operationCallbackIsSet || !cx->operationCallback);
5279 return cx->operationCallback;
5282 JS_PUBLIC_API(uint32)
5283 JS_GetOperationLimit(JSContext *cx)
5285 JS_ASSERT(cx->operationCallbackIsSet);
5286 return cx->operationLimit;
5289 JS_PUBLIC_API(void)
5290 JS_SetOperationLimit(JSContext *cx, uint32 operationLimit)
5292 JS_ASSERT(operationLimit <= JS_MAX_OPERATION_LIMIT);
5293 JS_ASSERT(operationLimit > 0);
5294 JS_ASSERT(cx->operationCallbackIsSet);
5296 cx->operationLimit = operationLimit;
5297 if (cx->operationCount > (int32) operationLimit)
5298 cx->operationCount = (int32) operationLimit;
5301 JS_PUBLIC_API(JSBranchCallback)
5302 JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb)
5304 JSBranchCallback oldcb;
5306 if (cx->operationCallbackIsSet) {
5307 #ifdef DEBUG
5308 fprintf(stderr,
5309 "JS API usage error: call to JS_SetOperationCallback is followed by\n"
5310 "invocation of deprecated JS_SetBranchCallback\n");
5311 JS_ASSERT(0);
5312 #endif
5313 cx->operationCallbackIsSet = 0;
5314 oldcb = NULL;
5315 } else {
5316 oldcb = (JSBranchCallback) cx->operationCallback;
5318 if (cb) {
5319 cx->operationCount = JSOW_SCRIPT_JUMP;
5320 cx->operationLimit = JSOW_SCRIPT_JUMP;
5321 cx->operationCallback = (JSOperationCallback) cb;
5322 } else {
5323 JS_ClearOperationCallback(cx);
5325 return oldcb;
5328 JS_PUBLIC_API(JSBool)
5329 JS_IsRunning(JSContext *cx)
5331 /* The use of cx->fp below is safe: if we're on trace, it is skipped. */
5332 VOUCH_DOES_NOT_REQUIRE_STACK();
5334 return JS_ON_TRACE(cx) || cx->fp != NULL;
5337 JS_PUBLIC_API(JSBool)
5338 JS_IsConstructing(JSContext *cx)
5340 JSStackFrame *fp;
5342 fp = js_GetTopStackFrame(cx);
5343 return fp && (fp->flags & JSFRAME_CONSTRUCTING);
5346 JS_FRIEND_API(JSBool)
5347 JS_IsAssigning(JSContext *cx)
5349 JSStackFrame *fp;
5351 fp = js_GetScriptedCaller(cx, NULL);
5352 if (!fp || !fp->regs)
5353 return JS_FALSE;
5354 return (js_CodeSpec[*fp->regs->pc].format & JOF_ASSIGNING) != 0;
5357 JS_PUBLIC_API(void)
5358 JS_SetCallReturnValue2(JSContext *cx, jsval v)
5360 #if JS_HAS_LVALUE_RETURN
5361 cx->rval2 = v;
5362 cx->rval2set = JS_TRUE;
5363 #endif
5366 JS_PUBLIC_API(JSStackFrame *)
5367 JS_SaveFrameChain(JSContext *cx)
5369 JSStackFrame *fp;
5371 fp = js_GetTopStackFrame(cx);
5372 if (!fp)
5373 return fp;
5375 JS_ASSERT(!fp->dormantNext);
5376 fp->dormantNext = cx->dormantFrameChain;
5377 cx->dormantFrameChain = fp;
5378 cx->fp = NULL;
5379 return fp;
5382 JS_PUBLIC_API(void)
5383 JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
5385 JS_ASSERT(!JS_ON_TRACE(cx));
5386 VOUCH_DOES_NOT_REQUIRE_STACK();
5387 JS_ASSERT(!cx->fp);
5388 if (!fp)
5389 return;
5391 JS_ASSERT(fp == cx->dormantFrameChain);
5392 cx->fp = fp;
5393 cx->dormantFrameChain = fp->dormantNext;
5394 fp->dormantNext = NULL;
5397 /************************************************************************/
5399 JS_PUBLIC_API(JSString *)
5400 JS_NewString(JSContext *cx, char *bytes, size_t nbytes)
5402 size_t length = nbytes;
5403 jschar *chars;
5404 JSString *str;
5406 CHECK_REQUEST(cx);
5408 /* Make a UTF-16 vector from the 8-bit char codes in bytes. */
5409 chars = js_InflateString(cx, bytes, &length);
5410 if (!chars)
5411 return NULL;
5413 /* Free chars (but not bytes, which caller frees on error) if we fail. */
5414 str = js_NewString(cx, chars, length);
5415 if (!str) {
5416 JS_free(cx, chars);
5417 return NULL;
5420 /* Hand off bytes to the deflated string cache, if possible. */
5421 if (!js_SetStringBytes(cx, str, bytes, nbytes))
5422 JS_free(cx, bytes);
5423 return str;
5426 JS_PUBLIC_API(JSString *)
5427 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
5429 jschar *js;
5430 JSString *str;
5432 CHECK_REQUEST(cx);
5433 js = js_InflateString(cx, s, &n);
5434 if (!js)
5435 return NULL;
5436 str = js_NewString(cx, js, n);
5437 if (!str)
5438 JS_free(cx, js);
5439 return str;
5442 JS_PUBLIC_API(JSString *)
5443 JS_NewStringCopyZ(JSContext *cx, const char *s)
5445 size_t n;
5446 jschar *js;
5447 JSString *str;
5449 CHECK_REQUEST(cx);
5450 if (!s)
5451 return cx->runtime->emptyString;
5452 n = strlen(s);
5453 js = js_InflateString(cx, s, &n);
5454 if (!js)
5455 return NULL;
5456 str = js_NewString(cx, js, n);
5457 if (!str)
5458 JS_free(cx, js);
5459 return str;
5462 JS_PUBLIC_API(JSString *)
5463 JS_InternString(JSContext *cx, const char *s)
5465 JSAtom *atom;
5467 CHECK_REQUEST(cx);
5468 atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
5469 if (!atom)
5470 return NULL;
5471 return ATOM_TO_STRING(atom);
5474 JS_PUBLIC_API(JSString *)
5475 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
5477 CHECK_REQUEST(cx);
5478 return js_NewString(cx, chars, length);
5481 JS_PUBLIC_API(JSString *)
5482 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
5484 CHECK_REQUEST(cx);
5485 return js_NewStringCopyN(cx, s, n);
5488 JS_PUBLIC_API(JSString *)
5489 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
5491 CHECK_REQUEST(cx);
5492 if (!s)
5493 return cx->runtime->emptyString;
5494 return js_NewStringCopyZ(cx, s);
5497 JS_PUBLIC_API(JSString *)
5498 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
5500 JSAtom *atom;
5502 CHECK_REQUEST(cx);
5503 atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
5504 if (!atom)
5505 return NULL;
5506 return ATOM_TO_STRING(atom);
5509 JS_PUBLIC_API(JSString *)
5510 JS_InternUCString(JSContext *cx, const jschar *s)
5512 return JS_InternUCStringN(cx, s, js_strlen(s));
5515 JS_PUBLIC_API(char *)
5516 JS_GetStringBytes(JSString *str)
5518 const char *bytes;
5520 bytes = js_GetStringBytes(NULL, str);
5521 return (char *)(bytes ? bytes : "");
5524 JS_PUBLIC_API(jschar *)
5525 JS_GetStringChars(JSString *str)
5527 size_t n, size;
5528 jschar *s;
5531 * API botch (again, shades of JS_GetStringBytes): we have no cx to report
5532 * out-of-memory when undepending strings, so we replace js_UndependString
5533 * with explicit malloc call and ignore its errors.
5535 * If we fail to convert a dependent string into an independent one, our
5536 * caller will not be guaranteed a \u0000 terminator as a backstop. This
5537 * may break some clients who already misbehave on embedded NULs.
5539 * The gain of dependent strings, which cure quadratic and cubic growth
5540 * rate bugs in string concatenation, is worth this slight loss in API
5541 * compatibility.
5543 if (JSSTRING_IS_DEPENDENT(str)) {
5544 n = JSSTRDEP_LENGTH(str);
5545 size = (n + 1) * sizeof(jschar);
5546 s = (jschar *) malloc(size);
5547 if (s) {
5548 memcpy(s, JSSTRDEP_CHARS(str), n * sizeof *s);
5549 s[n] = 0;
5550 JSFLATSTR_INIT(str, s, n);
5551 } else {
5552 s = JSSTRDEP_CHARS(str);
5554 } else {
5555 JSFLATSTR_CLEAR_MUTABLE(str);
5556 s = JSFLATSTR_CHARS(str);
5558 return s;
5561 JS_PUBLIC_API(size_t)
5562 JS_GetStringLength(JSString *str)
5564 return JSSTRING_LENGTH(str);
5567 JS_PUBLIC_API(intN)
5568 JS_CompareStrings(JSString *str1, JSString *str2)
5570 return js_CompareStrings(str1, str2);
5573 JS_PUBLIC_API(JSString *)
5574 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
5576 JSString *str;
5578 CHECK_REQUEST(cx);
5579 str = js_NewString(cx, chars, length);
5580 if (!str)
5581 return str;
5582 JSFLATSTR_SET_MUTABLE(str);
5583 return str;
5586 JS_PUBLIC_API(JSString *)
5587 JS_NewDependentString(JSContext *cx, JSString *str, size_t start,
5588 size_t length)
5590 CHECK_REQUEST(cx);
5591 return js_NewDependentString(cx, str, start, length);
5594 JS_PUBLIC_API(JSString *)
5595 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
5597 CHECK_REQUEST(cx);
5598 return js_ConcatStrings(cx, left, right);
5601 JS_PUBLIC_API(const jschar *)
5602 JS_UndependString(JSContext *cx, JSString *str)
5604 CHECK_REQUEST(cx);
5605 return js_UndependString(cx, str);
5608 JS_PUBLIC_API(JSBool)
5609 JS_MakeStringImmutable(JSContext *cx, JSString *str)
5611 CHECK_REQUEST(cx);
5612 return js_MakeStringImmutable(cx, str);
5615 JS_PUBLIC_API(JSBool)
5616 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst,
5617 size_t *dstlenp)
5619 size_t n;
5621 if (!dst) {
5622 n = js_GetDeflatedStringLength(cx, src, srclen);
5623 if (n == (size_t)-1) {
5624 *dstlenp = 0;
5625 return JS_FALSE;
5627 *dstlenp = n;
5628 return JS_TRUE;
5631 return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5634 JS_PUBLIC_API(JSBool)
5635 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst,
5636 size_t *dstlenp)
5638 return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5641 JS_PUBLIC_API(char *)
5642 JS_EncodeString(JSContext *cx, JSString *str)
5644 return js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
5647 JS_PUBLIC_API(JSBool)
5648 JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer,
5649 JSONWriteCallback callback, void *data)
5651 CHECK_REQUEST(cx);
5652 return js_Stringify(cx, vp, replacer, callback, data, 0);
5655 JS_PUBLIC_API(JSBool)
5656 JS_TryJSON(JSContext *cx, jsval *vp)
5658 CHECK_REQUEST(cx);
5659 return js_TryJSON(cx, vp);
5662 JS_PUBLIC_API(JSONParser *)
5663 JS_BeginJSONParse(JSContext *cx, jsval *vp)
5665 CHECK_REQUEST(cx);
5666 return js_BeginJSONParse(cx, vp);
5669 JS_PUBLIC_API(JSBool)
5670 JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len)
5672 CHECK_REQUEST(cx);
5673 return js_ConsumeJSONText(cx, jp, data, len);
5676 JS_PUBLIC_API(JSBool)
5677 JS_FinishJSONParse(JSContext *cx, JSONParser *jp)
5679 CHECK_REQUEST(cx);
5680 return js_FinishJSONParse(cx, jp);
5684 * The following determines whether C Strings are to be treated as UTF-8
5685 * or ISO-8859-1. For correct operation, it must be set prior to the
5686 * first call to JS_NewRuntime.
5688 #ifndef JS_C_STRINGS_ARE_UTF8
5689 JSBool js_CStringsAreUTF8 = JS_FALSE;
5690 #endif
5692 JS_PUBLIC_API(JSBool)
5693 JS_CStringsAreUTF8()
5695 return js_CStringsAreUTF8;
5698 JS_PUBLIC_API(void)
5699 JS_SetCStringsAreUTF8()
5701 JS_ASSERT(!js_NewRuntimeWasCalled);
5703 #ifndef JS_C_STRINGS_ARE_UTF8
5704 js_CStringsAreUTF8 = JS_TRUE;
5705 #endif
5708 /************************************************************************/
5710 JS_PUBLIC_API(void)
5711 JS_ReportError(JSContext *cx, const char *format, ...)
5713 va_list ap;
5715 va_start(ap, format);
5716 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
5717 va_end(ap);
5720 JS_PUBLIC_API(void)
5721 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
5722 void *userRef, const uintN errorNumber, ...)
5724 va_list ap;
5726 va_start(ap, errorNumber);
5727 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5728 errorNumber, JS_TRUE, ap);
5729 va_end(ap);
5732 JS_PUBLIC_API(void)
5733 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
5734 void *userRef, const uintN errorNumber, ...)
5736 va_list ap;
5738 va_start(ap, errorNumber);
5739 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5740 errorNumber, JS_FALSE, ap);
5741 va_end(ap);
5744 JS_PUBLIC_API(JSBool)
5745 JS_ReportWarning(JSContext *cx, const char *format, ...)
5747 va_list ap;
5748 JSBool ok;
5750 va_start(ap, format);
5751 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
5752 va_end(ap);
5753 return ok;
5756 JS_PUBLIC_API(JSBool)
5757 JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
5758 JSErrorCallback errorCallback, void *userRef,
5759 const uintN errorNumber, ...)
5761 va_list ap;
5762 JSBool ok;
5764 va_start(ap, errorNumber);
5765 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5766 errorNumber, JS_TRUE, ap);
5767 va_end(ap);
5768 return ok;
5771 JS_PUBLIC_API(JSBool)
5772 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
5773 JSErrorCallback errorCallback, void *userRef,
5774 const uintN errorNumber, ...)
5776 va_list ap;
5777 JSBool ok;
5779 va_start(ap, errorNumber);
5780 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5781 errorNumber, JS_FALSE, ap);
5782 va_end(ap);
5783 return ok;
5786 JS_PUBLIC_API(void)
5787 JS_ReportOutOfMemory(JSContext *cx)
5789 js_ReportOutOfMemory(cx);
5792 JS_PUBLIC_API(void)
5793 JS_ReportAllocationOverflow(JSContext *cx)
5795 js_ReportAllocationOverflow(cx);
5798 JS_PUBLIC_API(JSErrorReporter)
5799 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
5801 JSErrorReporter older;
5803 older = cx->errorReporter;
5804 cx->errorReporter = er;
5805 return older;
5808 /************************************************************************/
5811 * Regular Expressions.
5813 JS_PUBLIC_API(JSObject *)
5814 JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags)
5816 jschar *chars;
5817 JSObject *obj;
5819 CHECK_REQUEST(cx);
5820 chars = js_InflateString(cx, bytes, &length);
5821 if (!chars)
5822 return NULL;
5823 obj = js_NewRegExpObject(cx, NULL, chars, length, flags);
5824 JS_free(cx, chars);
5825 return obj;
5828 JS_PUBLIC_API(JSObject *)
5829 JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags)
5831 CHECK_REQUEST(cx);
5832 return js_NewRegExpObject(cx, NULL, chars, length, flags);
5835 JS_PUBLIC_API(void)
5836 JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline)
5838 JSRegExpStatics *res;
5840 CHECK_REQUEST(cx);
5841 /* No locking required, cx is thread-private and input must be live. */
5842 res = &cx->regExpStatics;
5843 res->input = input;
5844 res->multiline = multiline;
5845 cx->runtime->gcPoke = JS_TRUE;
5848 JS_PUBLIC_API(void)
5849 JS_ClearRegExpStatics(JSContext *cx)
5851 JSRegExpStatics *res;
5853 /* No locking required, cx is thread-private and input must be live. */
5854 res = &cx->regExpStatics;
5855 res->input = NULL;
5856 res->multiline = JS_FALSE;
5857 res->parenCount = 0;
5858 res->lastMatch = res->lastParen = js_EmptySubString;
5859 res->leftContext = res->rightContext = js_EmptySubString;
5860 cx->runtime->gcPoke = JS_TRUE;
5863 JS_PUBLIC_API(void)
5864 JS_ClearRegExpRoots(JSContext *cx)
5866 JSRegExpStatics *res;
5868 /* No locking required, cx is thread-private and input must be live. */
5869 res = &cx->regExpStatics;
5870 res->input = NULL;
5871 cx->runtime->gcPoke = JS_TRUE;
5874 /* TODO: compile, execute, get/set other statics... */
5876 /************************************************************************/
5878 JS_PUBLIC_API(void)
5879 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
5881 cx->localeCallbacks = callbacks;
5884 JS_PUBLIC_API(JSLocaleCallbacks *)
5885 JS_GetLocaleCallbacks(JSContext *cx)
5887 return cx->localeCallbacks;
5890 /************************************************************************/
5892 JS_PUBLIC_API(JSBool)
5893 JS_IsExceptionPending(JSContext *cx)
5895 return (JSBool) cx->throwing;
5898 JS_PUBLIC_API(JSBool)
5899 JS_GetPendingException(JSContext *cx, jsval *vp)
5901 CHECK_REQUEST(cx);
5902 if (!cx->throwing)
5903 return JS_FALSE;
5904 *vp = cx->exception;
5905 return JS_TRUE;
5908 JS_PUBLIC_API(void)
5909 JS_SetPendingException(JSContext *cx, jsval v)
5911 CHECK_REQUEST(cx);
5912 cx->throwing = JS_TRUE;
5913 cx->exception = v;
5916 JS_PUBLIC_API(void)
5917 JS_ClearPendingException(JSContext *cx)
5919 cx->throwing = JS_FALSE;
5920 cx->exception = JSVAL_VOID;
5923 JS_PUBLIC_API(JSBool)
5924 JS_ReportPendingException(JSContext *cx)
5926 JSBool save, ok;
5928 CHECK_REQUEST(cx);
5931 * Set cx->generatingError to suppress the standard error-to-exception
5932 * conversion done by all {js,JS}_Report* functions except for OOM. The
5933 * cx->generatingError flag was added to suppress recursive divergence
5934 * under js_ErrorToException, but it serves for our purposes here too.
5936 save = cx->generatingError;
5937 cx->generatingError = JS_TRUE;
5938 ok = js_ReportUncaughtException(cx);
5939 cx->generatingError = save;
5940 return ok;
5943 struct JSExceptionState {
5944 JSBool throwing;
5945 jsval exception;
5948 JS_PUBLIC_API(JSExceptionState *)
5949 JS_SaveExceptionState(JSContext *cx)
5951 JSExceptionState *state;
5953 CHECK_REQUEST(cx);
5954 state = (JSExceptionState *) JS_malloc(cx, sizeof(JSExceptionState));
5955 if (state) {
5956 state->throwing = JS_GetPendingException(cx, &state->exception);
5957 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
5958 js_AddRoot(cx, &state->exception, "JSExceptionState.exception");
5960 return state;
5963 JS_PUBLIC_API(void)
5964 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
5966 CHECK_REQUEST(cx);
5967 if (state) {
5968 if (state->throwing)
5969 JS_SetPendingException(cx, state->exception);
5970 else
5971 JS_ClearPendingException(cx);
5972 JS_DropExceptionState(cx, state);
5976 JS_PUBLIC_API(void)
5977 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
5979 CHECK_REQUEST(cx);
5980 if (state) {
5981 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
5982 JS_RemoveRoot(cx, &state->exception);
5983 JS_free(cx, state);
5987 JS_PUBLIC_API(JSErrorReport *)
5988 JS_ErrorFromException(JSContext *cx, jsval v)
5990 CHECK_REQUEST(cx);
5991 return js_ErrorFromException(cx, v);
5994 JS_PUBLIC_API(JSBool)
5995 JS_ThrowReportedError(JSContext *cx, const char *message,
5996 JSErrorReport *reportp)
5998 return JS_IsRunning(cx) && js_ErrorToException(cx, message, reportp);
6001 JS_PUBLIC_API(JSBool)
6002 JS_ThrowStopIteration(JSContext *cx)
6004 return js_ThrowStopIteration(cx);
6008 * Get the owning thread id of a context. Returns 0 if the context is not
6009 * owned by any thread.
6011 JS_PUBLIC_API(jsword)
6012 JS_GetContextThread(JSContext *cx)
6014 #ifdef JS_THREADSAFE
6015 return JS_THREAD_ID(cx);
6016 #else
6017 return 0;
6018 #endif
6022 * Set the current thread as the owning thread of a context. Returns the
6023 * old owning thread id, or -1 if the operation failed.
6025 JS_PUBLIC_API(jsword)
6026 JS_SetContextThread(JSContext *cx)
6028 #ifdef JS_THREADSAFE
6029 jsword old = JS_THREAD_ID(cx);
6030 if (!js_SetContextThread(cx))
6031 return -1;
6032 return old;
6033 #else
6034 return 0;
6035 #endif
6038 JS_PUBLIC_API(jsword)
6039 JS_ClearContextThread(JSContext *cx)
6041 #ifdef JS_THREADSAFE
6042 jsword old = JS_THREAD_ID(cx);
6043 js_ClearContextThread(cx);
6044 return old;
6045 #else
6046 return 0;
6047 #endif
6050 #ifdef JS_GC_ZEAL
6051 JS_PUBLIC_API(void)
6052 JS_SetGCZeal(JSContext *cx, uint8 zeal)
6054 cx->runtime->gcZeal = zeal;
6056 #endif
6058 /************************************************************************/
6060 #if !defined(STATIC_JS_API) && defined(XP_WIN) && !defined (WINCE)
6062 #include <windows.h>
6065 * Initialization routine for the JS DLL.
6067 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
6069 return TRUE;
6072 #endif