Bug 449522 - Context menu for HTML5 <video> elements. r=gavin, ui-r=boriss
[wine-gecko.git] / js / src / jsapi.cpp
blob29736ae76d20e189a74a426dc385504f61dba050
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 "prmjtime.h"
83 #include "jsstaticcheck.h"
85 #if !defined JS_THREADSAFE && defined JS_TRACER
86 #include "jstracer.h"
87 #endif
89 #if JS_HAS_FILE_OBJECT
90 #include "jsfile.h"
91 #endif
93 #if JS_HAS_XML_SUPPORT
94 #include "jsxml.h"
95 #endif
97 #ifdef HAVE_VA_LIST_AS_ARRAY
98 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
99 #else
100 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
101 #endif
103 #if defined(JS_THREADSAFE)
104 #define CHECK_REQUEST(cx) \
105 JS_ASSERT((cx)->requestDepth || (cx)->thread == (cx)->runtime->gcThread)
106 #else
107 #define CHECK_REQUEST(cx) ((void)0)
108 #endif
110 JS_PUBLIC_API(int64)
111 JS_Now()
113 return PRMJ_Now();
116 JS_PUBLIC_API(jsval)
117 JS_GetNaNValue(JSContext *cx)
119 return DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
122 JS_PUBLIC_API(jsval)
123 JS_GetNegativeInfinityValue(JSContext *cx)
125 return DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
128 JS_PUBLIC_API(jsval)
129 JS_GetPositiveInfinityValue(JSContext *cx)
131 return DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
134 JS_PUBLIC_API(jsval)
135 JS_GetEmptyStringValue(JSContext *cx)
137 return STRING_TO_JSVAL(cx->runtime->emptyString);
140 static JSBool
141 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS,
142 jsval **vpp, va_list *app)
144 const char *format;
145 JSArgumentFormatMap *map;
147 format = *formatp;
148 for (map = cx->argumentFormatMap; map; map = map->next) {
149 if (!strncmp(format, map->format, map->length)) {
150 *formatp = format + map->length;
151 return map->formatter(cx, format, fromJS, vpp, app);
154 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
155 return JS_FALSE;
158 JS_PUBLIC_API(JSBool)
159 JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
160 ...)
162 va_list ap;
163 JSBool ok;
165 va_start(ap, format);
166 ok = JS_ConvertArgumentsVA(cx, argc, argv, format, ap);
167 va_end(ap);
168 return ok;
171 JS_PUBLIC_API(JSBool)
172 JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
173 const char *format, va_list ap)
175 jsval *sp;
176 JSBool required;
177 char c;
178 JSFunction *fun;
179 jsdouble d;
180 JSString *str;
181 JSObject *obj;
183 CHECK_REQUEST(cx);
184 sp = argv;
185 required = JS_TRUE;
186 while ((c = *format++) != '\0') {
187 if (isspace(c))
188 continue;
189 if (c == '/') {
190 required = JS_FALSE;
191 continue;
193 if (sp == argv + argc) {
194 if (required) {
195 fun = js_ValueToFunction(cx, &argv[-2], 0);
196 if (fun) {
197 char numBuf[12];
198 JS_snprintf(numBuf, sizeof numBuf, "%u", argc);
199 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
200 JSMSG_MORE_ARGS_NEEDED,
201 JS_GetFunctionName(fun), numBuf,
202 (argc == 1) ? "" : "s");
204 return JS_FALSE;
206 break;
208 switch (c) {
209 case 'b':
210 *va_arg(ap, JSBool *) = js_ValueToBoolean(*sp);
211 break;
212 case 'c':
213 if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
214 return JS_FALSE;
215 break;
216 case 'i':
217 if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
218 return JS_FALSE;
219 break;
220 case 'u':
221 if (!JS_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
222 return JS_FALSE;
223 break;
224 case 'j':
225 if (!JS_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
226 return JS_FALSE;
227 break;
228 case 'd':
229 if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
230 return JS_FALSE;
231 break;
232 case 'I':
233 if (!JS_ValueToNumber(cx, *sp, &d))
234 return JS_FALSE;
235 *va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
236 break;
237 case 's':
238 case 'S':
239 case 'W':
240 str = js_ValueToString(cx, *sp);
241 if (!str)
242 return JS_FALSE;
243 *sp = STRING_TO_JSVAL(str);
244 if (c == 's') {
245 const char *bytes = js_GetStringBytes(cx, str);
246 if (!bytes)
247 return JS_FALSE;
248 *va_arg(ap, const char **) = bytes;
249 } else if (c == 'W') {
250 const jschar *chars = js_GetStringChars(cx, str);
251 if (!chars)
252 return JS_FALSE;
253 *va_arg(ap, const jschar **) = chars;
254 } else {
255 *va_arg(ap, JSString **) = str;
257 break;
258 case 'o':
259 if (!js_ValueToObject(cx, *sp, &obj))
260 return JS_FALSE;
261 *sp = OBJECT_TO_JSVAL(obj);
262 *va_arg(ap, JSObject **) = obj;
263 break;
264 case 'f':
265 obj = js_ValueToFunctionObject(cx, sp, 0);
266 if (!obj)
267 return JS_FALSE;
268 *sp = OBJECT_TO_JSVAL(obj);
269 *va_arg(ap, JSFunction **) = (JSFunction *) JS_GetPrivate(cx, obj);
270 break;
271 case 'v':
272 *va_arg(ap, jsval *) = *sp;
273 break;
274 case '*':
275 break;
276 default:
277 format--;
278 if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
279 JS_ADDRESSOF_VA_LIST(ap))) {
280 return JS_FALSE;
282 /* NB: the formatter already updated sp, so we continue here. */
283 continue;
285 sp++;
287 return JS_TRUE;
290 JS_PUBLIC_API(jsval *)
291 JS_PushArguments(JSContext *cx, void **markp, const char *format, ...)
293 va_list ap;
294 jsval *argv;
296 va_start(ap, format);
297 argv = JS_PushArgumentsVA(cx, markp, format, ap);
298 va_end(ap);
299 return argv;
302 JS_PUBLIC_API(jsval *)
303 JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap)
305 uintN argc;
306 jsval *argv, *sp;
307 char c;
308 const char *cp;
309 JSString *str;
310 JSFunction *fun;
311 JSStackHeader *sh;
313 CHECK_REQUEST(cx);
314 *markp = NULL;
315 argc = 0;
316 for (cp = format; (c = *cp) != '\0'; cp++) {
318 * Count non-space non-star characters as individual jsval arguments.
319 * This may over-allocate stack, but we'll fix below.
321 if (isspace(c) || c == '*')
322 continue;
323 argc++;
325 sp = js_AllocStack(cx, argc, markp);
326 if (!sp)
327 return NULL;
328 argv = sp;
329 while ((c = *format++) != '\0') {
330 if (isspace(c) || c == '*')
331 continue;
332 switch (c) {
333 case 'b':
334 *sp = BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int));
335 break;
336 case 'c':
337 *sp = INT_TO_JSVAL((uint16) va_arg(ap, unsigned int));
338 break;
339 case 'i':
340 case 'j':
342 * Use JS_New{Double,Number}Value here and in the next two cases,
343 * not js_New{Double,Number}InRootedValue, as sp may point to an
344 * unrooted location.
346 if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp))
347 goto bad;
348 break;
349 case 'u':
350 if (!JS_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp))
351 goto bad;
352 break;
353 case 'd':
354 case 'I':
355 if (!JS_NewDoubleValue(cx, va_arg(ap, jsdouble), sp))
356 goto bad;
357 break;
358 case 's':
359 str = JS_NewStringCopyZ(cx, va_arg(ap, char *));
360 if (!str)
361 goto bad;
362 *sp = STRING_TO_JSVAL(str);
363 break;
364 case 'W':
365 str = JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *));
366 if (!str)
367 goto bad;
368 *sp = STRING_TO_JSVAL(str);
369 break;
370 case 'S':
371 str = va_arg(ap, JSString *);
372 *sp = STRING_TO_JSVAL(str);
373 break;
374 case 'o':
375 *sp = OBJECT_TO_JSVAL(va_arg(ap, JSObject *));
376 break;
377 case 'f':
378 fun = va_arg(ap, JSFunction *);
379 *sp = fun ? OBJECT_TO_JSVAL(FUN_OBJECT(fun)) : JSVAL_NULL;
380 break;
381 case 'v':
382 *sp = va_arg(ap, jsval);
383 break;
384 default:
385 format--;
386 if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp,
387 JS_ADDRESSOF_VA_LIST(ap))) {
388 goto bad;
390 /* NB: the formatter already updated sp, so we continue here. */
391 continue;
393 sp++;
397 * We may have overallocated stack due to a multi-character format code
398 * handled by a JSArgumentFormatter. Give back that stack space!
400 JS_ASSERT(sp <= argv + argc);
401 if (sp < argv + argc) {
402 /* Return slots not pushed to the current stack arena. */
403 cx->stackPool.current->avail = (jsuword)sp;
405 /* Reduce the count of slots the GC will scan in this stack segment. */
406 sh = cx->stackHeaders;
407 JS_ASSERT(JS_STACK_SEGMENT(sh) + sh->nslots == argv + argc);
408 sh->nslots -= argc - (sp - argv);
410 return argv;
412 bad:
413 js_FreeStack(cx, *markp);
414 return NULL;
417 JS_PUBLIC_API(void)
418 JS_PopArguments(JSContext *cx, void *mark)
420 CHECK_REQUEST(cx);
421 js_FreeStack(cx, mark);
424 JS_PUBLIC_API(JSBool)
425 JS_AddArgumentFormatter(JSContext *cx, const char *format,
426 JSArgumentFormatter formatter)
428 size_t length;
429 JSArgumentFormatMap **mpp, *map;
431 length = strlen(format);
432 mpp = &cx->argumentFormatMap;
433 while ((map = *mpp) != NULL) {
434 /* Insert before any shorter string to match before prefixes. */
435 if (map->length < length)
436 break;
437 if (map->length == length && !strcmp(map->format, format))
438 goto out;
439 mpp = &map->next;
441 map = (JSArgumentFormatMap *) JS_malloc(cx, sizeof *map);
442 if (!map)
443 return JS_FALSE;
444 map->format = format;
445 map->length = length;
446 map->next = *mpp;
447 *mpp = map;
448 out:
449 map->formatter = formatter;
450 return JS_TRUE;
453 JS_PUBLIC_API(void)
454 JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
456 size_t length;
457 JSArgumentFormatMap **mpp, *map;
459 length = strlen(format);
460 mpp = &cx->argumentFormatMap;
461 while ((map = *mpp) != NULL) {
462 if (map->length == length && !strcmp(map->format, format)) {
463 *mpp = map->next;
464 JS_free(cx, map);
465 return;
467 mpp = &map->next;
471 JS_PUBLIC_API(JSBool)
472 JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
474 JSBool ok;
475 JSObject *obj;
476 JSString *str;
477 jsdouble d, *dp;
479 CHECK_REQUEST(cx);
480 switch (type) {
481 case JSTYPE_VOID:
482 *vp = JSVAL_VOID;
483 ok = JS_TRUE;
484 break;
485 case JSTYPE_OBJECT:
486 ok = js_ValueToObject(cx, v, &obj);
487 if (ok)
488 *vp = OBJECT_TO_JSVAL(obj);
489 break;
490 case JSTYPE_FUNCTION:
491 *vp = v;
492 obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK);
493 ok = (obj != NULL);
494 break;
495 case JSTYPE_STRING:
496 str = js_ValueToString(cx, v);
497 ok = (str != NULL);
498 if (ok)
499 *vp = STRING_TO_JSVAL(str);
500 break;
501 case JSTYPE_NUMBER:
502 ok = JS_ValueToNumber(cx, v, &d);
503 if (ok) {
504 dp = js_NewWeaklyRootedDouble(cx, d);
505 ok = (dp != NULL);
506 if (ok)
507 *vp = DOUBLE_TO_JSVAL(dp);
509 break;
510 case JSTYPE_BOOLEAN:
511 *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(v));
512 return JS_TRUE;
513 default: {
514 char numBuf[12];
515 JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
516 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
517 numBuf);
518 ok = JS_FALSE;
519 break;
522 return ok;
525 JS_PUBLIC_API(JSBool)
526 JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
528 CHECK_REQUEST(cx);
529 return js_ValueToObject(cx, v, objp);
532 JS_PUBLIC_API(JSFunction *)
533 JS_ValueToFunction(JSContext *cx, jsval v)
535 CHECK_REQUEST(cx);
536 return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
539 JS_PUBLIC_API(JSFunction *)
540 JS_ValueToConstructor(JSContext *cx, jsval v)
542 CHECK_REQUEST(cx);
543 return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
546 JS_PUBLIC_API(JSString *)
547 JS_ValueToString(JSContext *cx, jsval v)
549 CHECK_REQUEST(cx);
550 return js_ValueToString(cx, v);
553 JS_PUBLIC_API(JSBool)
554 JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
556 JSTempValueRooter tvr;
558 CHECK_REQUEST(cx);
559 JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
560 *dp = js_ValueToNumber(cx, &tvr.u.value);
561 JS_POP_TEMP_ROOT(cx, &tvr);
562 return !JSVAL_IS_NULL(tvr.u.value);
565 JS_PUBLIC_API(JSBool)
566 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
568 JSTempValueRooter tvr;
570 CHECK_REQUEST(cx);
571 JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
572 *ip = js_ValueToECMAInt32(cx, &tvr.u.value);
573 JS_POP_TEMP_ROOT(cx, &tvr);
574 return !JSVAL_IS_NULL(tvr.u.value);
577 JS_PUBLIC_API(JSBool)
578 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
580 JSTempValueRooter tvr;
582 CHECK_REQUEST(cx);
583 JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
584 *ip = js_ValueToECMAUint32(cx, &tvr.u.value);
585 JS_POP_TEMP_ROOT(cx, &tvr);
586 return !JSVAL_IS_NULL(tvr.u.value);
589 JS_PUBLIC_API(JSBool)
590 JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
592 JSTempValueRooter tvr;
594 CHECK_REQUEST(cx);
595 JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
596 *ip = js_ValueToInt32(cx, &tvr.u.value);
597 JS_POP_TEMP_ROOT(cx, &tvr);
598 return !JSVAL_IS_NULL(tvr.u.value);
601 JS_PUBLIC_API(JSBool)
602 JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
604 JSTempValueRooter tvr;
606 CHECK_REQUEST(cx);
607 JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
608 *ip = js_ValueToUint16(cx, &tvr.u.value);
609 JS_POP_TEMP_ROOT(cx, &tvr);
610 return !JSVAL_IS_NULL(tvr.u.value);
613 JS_PUBLIC_API(JSBool)
614 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
616 CHECK_REQUEST(cx);
617 *bp = js_ValueToBoolean(v);
618 return JS_TRUE;
621 JS_PUBLIC_API(JSType)
622 JS_TypeOfValue(JSContext *cx, jsval v)
624 JSType type;
625 JSObject *obj;
626 JSObjectOps *ops;
627 JSClass *clasp;
629 CHECK_REQUEST(cx);
630 if (JSVAL_IS_OBJECT(v)) {
631 type = JSTYPE_OBJECT; /* XXXbe JSTYPE_NULL for JS2 */
632 obj = JSVAL_TO_OBJECT(v);
633 if (obj) {
634 JSObject *wrapped;
636 wrapped = js_GetWrappedObject(cx, obj);
637 if (wrapped)
638 obj = wrapped;
640 ops = obj->map->ops;
641 #if JS_HAS_XML_SUPPORT
642 if (ops == &js_XMLObjectOps.base) {
643 type = JSTYPE_XML;
644 } else
645 #endif
648 * ECMA 262, 11.4.3 says that any native object that implements
649 * [[Call]] should be of type "function". Note that RegExp and
650 * Script are both of type "function" for compatibility with
651 * older SpiderMonkeys.
653 clasp = OBJ_GET_CLASS(cx, obj);
654 if ((ops == &js_ObjectOps)
655 ? (clasp->call
656 ? clasp == &js_ScriptClass
657 : clasp == &js_FunctionClass)
658 : ops->call != NULL) {
659 type = JSTYPE_FUNCTION;
660 } else {
661 #ifdef NARCISSUS
662 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
664 if (!OBJ_GET_PROPERTY(cx, obj,
665 ATOM_TO_JSID(cx->runtime->atomState
666 .callAtom),
667 &v)) {
668 JS_ClearPendingException(cx);
669 } else if (VALUE_IS_FUNCTION(cx, v)) {
670 type = JSTYPE_FUNCTION;
672 #endif
676 } else if (JSVAL_IS_NUMBER(v)) {
677 type = JSTYPE_NUMBER;
678 } else if (JSVAL_IS_STRING(v)) {
679 type = JSTYPE_STRING;
680 } else if (JSVAL_IS_BOOLEAN(v)) {
681 type = JSTYPE_BOOLEAN;
682 } else {
683 type = JSTYPE_VOID;
685 return type;
688 JS_PUBLIC_API(const char *)
689 JS_GetTypeName(JSContext *cx, JSType type)
691 if ((uintN)type >= (uintN)JSTYPE_LIMIT)
692 return NULL;
693 return JS_TYPE_STR(type);
696 /************************************************************************/
699 * Has a new runtime ever been created? This flag is used to detect unsafe
700 * changes to js_CStringsAreUTF8 after a runtime has been created, and to
701 * ensure that "first checks" on runtime creation are run only once.
703 #ifdef DEBUG
704 static JSBool js_NewRuntimeWasCalled = JS_FALSE;
705 #endif
707 JS_PUBLIC_API(JSRuntime *)
708 JS_NewRuntime(uint32 maxbytes)
710 JSRuntime *rt;
712 #ifdef DEBUG
713 if (!js_NewRuntimeWasCalled) {
715 * This code asserts that the numbers associated with the error names
716 * in jsmsg.def are monotonically increasing. It uses values for the
717 * error names enumerated in jscntxt.c. It's not a compile-time check
718 * but it's better than nothing.
720 int errorNumber = 0;
721 #define MSG_DEF(name, number, count, exception, format) \
722 JS_ASSERT(name == errorNumber++);
723 #include "js.msg"
724 #undef MSG_DEF
726 #define MSG_DEF(name, number, count, exception, format) \
727 JS_BEGIN_MACRO \
728 uintN numfmtspecs = 0; \
729 const char *fmt; \
730 for (fmt = format; *fmt != '\0'; fmt++) { \
731 if (*fmt == '{' && isdigit(fmt[1])) \
732 ++numfmtspecs; \
734 JS_ASSERT(count == numfmtspecs); \
735 JS_END_MACRO;
736 #include "js.msg"
737 #undef MSG_DEF
739 js_NewRuntimeWasCalled = JS_TRUE;
741 #endif /* DEBUG */
743 rt = (JSRuntime *) malloc(sizeof(JSRuntime));
744 if (!rt)
745 return NULL;
747 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
748 memset(rt, 0, sizeof(JSRuntime));
749 JS_INIT_CLIST(&rt->contextList);
750 JS_INIT_CLIST(&rt->trapList);
751 JS_INIT_CLIST(&rt->watchPointList);
753 if (!js_InitDtoa())
754 goto bad;
755 if (!js_InitGC(rt, maxbytes))
756 goto bad;
757 if (!js_InitAtomState(rt))
758 goto bad;
759 if (!js_InitDeflatedStringCache(rt))
760 goto bad;
761 #ifdef JS_THREADSAFE
762 if (!js_InitThreadPrivateIndex(js_ThreadDestructorCB))
763 goto bad;
764 rt->gcLock = JS_NEW_LOCK();
765 if (!rt->gcLock)
766 goto bad;
767 rt->gcDone = JS_NEW_CONDVAR(rt->gcLock);
768 if (!rt->gcDone)
769 goto bad;
770 rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
771 if (!rt->requestDone)
772 goto bad;
773 /* this is asymmetric with JS_ShutDown: */
774 if (!js_SetupLocks(8, 16))
775 goto bad;
776 rt->rtLock = JS_NEW_LOCK();
777 if (!rt->rtLock)
778 goto bad;
779 rt->stateChange = JS_NEW_CONDVAR(rt->gcLock);
780 if (!rt->stateChange)
781 goto bad;
782 rt->titleSharingDone = JS_NEW_CONDVAR(rt->gcLock);
783 if (!rt->titleSharingDone)
784 goto bad;
785 rt->titleSharingTodo = NO_TITLE_SHARING_TODO;
786 rt->debuggerLock = JS_NEW_LOCK();
787 if (!rt->debuggerLock)
788 goto bad;
789 #endif
790 if (!js_InitPropertyTree(rt))
791 goto bad;
793 #if !defined JS_THREADSAFE && defined JS_TRACER
794 js_InitJIT(&rt->traceMonitor);
795 #endif
797 return rt;
799 bad:
800 JS_DestroyRuntime(rt);
801 return NULL;
804 JS_PUBLIC_API(void)
805 JS_DestroyRuntime(JSRuntime *rt)
807 #ifdef DEBUG
808 /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
809 if (!JS_CLIST_IS_EMPTY(&rt->contextList)) {
810 JSContext *cx, *iter = NULL;
811 uintN cxcount = 0;
812 while ((cx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL) {
813 fprintf(stderr,
814 "JS API usage error: found live context at %p\n",
815 cx);
816 cxcount++;
818 fprintf(stderr,
819 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
820 cxcount, (cxcount == 1) ? "" : "s");
822 #endif
824 #if !defined JS_THREADSAFE && defined JS_TRACER
825 js_FinishJIT(&rt->traceMonitor);
826 #endif
828 js_FreeRuntimeScriptState(rt);
829 js_FinishAtomState(rt);
832 * Free unit string storage only after all strings have been finalized, so
833 * that js_FinalizeString can detect unit strings and avoid calling free
834 * on their chars storage.
836 js_FinishUnitStrings(rt);
839 * Finish the deflated string cache after the last GC and after
840 * calling js_FinishAtomState, which finalizes strings.
842 js_FinishDeflatedStringCache(rt);
843 js_FinishGC(rt);
844 #ifdef JS_THREADSAFE
845 if (rt->gcLock)
846 JS_DESTROY_LOCK(rt->gcLock);
847 if (rt->gcDone)
848 JS_DESTROY_CONDVAR(rt->gcDone);
849 if (rt->requestDone)
850 JS_DESTROY_CONDVAR(rt->requestDone);
851 if (rt->rtLock)
852 JS_DESTROY_LOCK(rt->rtLock);
853 if (rt->stateChange)
854 JS_DESTROY_CONDVAR(rt->stateChange);
855 if (rt->titleSharingDone)
856 JS_DESTROY_CONDVAR(rt->titleSharingDone);
857 if (rt->debuggerLock)
858 JS_DESTROY_LOCK(rt->debuggerLock);
859 #else
860 GSN_CACHE_CLEAR(&rt->gsnCache);
861 #endif
862 js_FinishPropertyTree(rt);
863 free(rt);
866 JS_PUBLIC_API(void)
867 JS_ShutDown(void)
869 #ifdef JS_OPMETER
870 extern void js_DumpOpMeters();
872 js_DumpOpMeters();
873 #endif
875 js_FinishDtoa();
876 #ifdef JS_THREADSAFE
877 js_CleanupLocks();
878 #endif
879 PRMJ_NowShutdown();
882 JS_PUBLIC_API(void *)
883 JS_GetRuntimePrivate(JSRuntime *rt)
885 return rt->data;
888 JS_PUBLIC_API(void)
889 JS_SetRuntimePrivate(JSRuntime *rt, void *data)
891 rt->data = data;
894 JS_PUBLIC_API(void)
895 JS_BeginRequest(JSContext *cx)
897 #ifdef JS_THREADSAFE
898 JSRuntime *rt;
900 JS_ASSERT(cx->thread->id == js_CurrentThreadId());
901 if (!cx->requestDepth) {
902 JS_ASSERT(cx->gcLocalFreeLists == &js_GCEmptyFreeListSet);
904 /* Wait until the GC is finished. */
905 rt = cx->runtime;
906 JS_LOCK_GC(rt);
908 /* NB: we use cx->thread here, not js_GetCurrentThread(). */
909 if (rt->gcThread != cx->thread) {
910 while (rt->gcLevel > 0)
911 JS_AWAIT_GC_DONE(rt);
914 /* Indicate that a request is running. */
915 rt->requestCount++;
916 cx->requestDepth = 1;
917 cx->outstandingRequests++;
918 JS_UNLOCK_GC(rt);
919 return;
921 cx->requestDepth++;
922 cx->outstandingRequests++;
923 #endif
926 JS_PUBLIC_API(void)
927 JS_EndRequest(JSContext *cx)
929 #ifdef JS_THREADSAFE
930 JSRuntime *rt;
931 JSTitle *title, **todop;
932 JSBool shared;
934 CHECK_REQUEST(cx);
935 JS_ASSERT(cx->requestDepth > 0);
936 JS_ASSERT(cx->outstandingRequests > 0);
937 if (cx->requestDepth == 1) {
938 /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
939 rt = cx->runtime;
940 JS_LOCK_GC(rt);
941 cx->requestDepth = 0;
942 cx->outstandingRequests--;
944 /* See whether cx has any single-threaded titles to start sharing. */
945 todop = &rt->titleSharingTodo;
946 shared = JS_FALSE;
947 while ((title = *todop) != NO_TITLE_SHARING_TODO) {
948 if (title->ownercx != cx) {
949 todop = &title->u.link;
950 continue;
952 *todop = title->u.link;
953 title->u.link = NULL; /* null u.link for sanity ASAP */
956 * If js_DropObjectMap returns null, we held the last ref to scope.
957 * The waiting thread(s) must have been killed, after which the GC
958 * collected the object that held this scope. Unlikely, because it
959 * requires that the GC ran (e.g., from an operation callback)
960 * during this request, but possible.
962 if (js_DropObjectMap(cx, TITLE_TO_MAP(title), NULL)) {
963 js_InitLock(&title->lock);
964 title->u.count = 0; /* NULL may not pun as 0 */
965 js_FinishSharingTitle(cx, title); /* set ownercx = NULL */
966 shared = JS_TRUE;
969 if (shared)
970 JS_NOTIFY_ALL_CONDVAR(rt->titleSharingDone);
972 js_RevokeGCLocalFreeLists(cx);
974 /* Give the GC a chance to run if this was the last request running. */
975 JS_ASSERT(rt->requestCount > 0);
976 rt->requestCount--;
977 if (rt->requestCount == 0)
978 JS_NOTIFY_REQUEST_DONE(rt);
980 JS_UNLOCK_GC(rt);
981 return;
984 cx->requestDepth--;
985 cx->outstandingRequests--;
986 #endif
989 /* Yield to pending GC operations, regardless of request depth */
990 JS_PUBLIC_API(void)
991 JS_YieldRequest(JSContext *cx)
993 #ifdef JS_THREADSAFE
994 JS_ASSERT(cx->thread);
995 CHECK_REQUEST(cx);
996 JS_ResumeRequest(cx, JS_SuspendRequest(cx));
997 #endif
1000 JS_PUBLIC_API(jsrefcount)
1001 JS_SuspendRequest(JSContext *cx)
1003 #ifdef JS_THREADSAFE
1004 jsrefcount saveDepth = cx->requestDepth;
1006 while (cx->requestDepth) {
1007 cx->outstandingRequests++; /* compensate for JS_EndRequest */
1008 JS_EndRequest(cx);
1010 return saveDepth;
1011 #else
1012 return 0;
1013 #endif
1016 JS_PUBLIC_API(void)
1017 JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
1019 #ifdef JS_THREADSAFE
1020 JS_ASSERT(!cx->requestDepth);
1021 while (--saveDepth >= 0) {
1022 JS_BeginRequest(cx);
1023 cx->outstandingRequests--; /* compensate for JS_BeginRequest */
1025 #endif
1028 JS_PUBLIC_API(void)
1029 JS_Lock(JSRuntime *rt)
1031 JS_LOCK_RUNTIME(rt);
1034 JS_PUBLIC_API(void)
1035 JS_Unlock(JSRuntime *rt)
1037 JS_UNLOCK_RUNTIME(rt);
1040 JS_PUBLIC_API(JSContextCallback)
1041 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
1043 JSContextCallback old;
1045 old = rt->cxCallback;
1046 rt->cxCallback = cxCallback;
1047 return old;
1050 JS_PUBLIC_API(JSContext *)
1051 JS_NewContext(JSRuntime *rt, size_t stackChunkSize)
1053 return js_NewContext(rt, stackChunkSize);
1056 JS_PUBLIC_API(void)
1057 JS_DestroyContext(JSContext *cx)
1059 js_DestroyContext(cx, JSDCM_FORCE_GC);
1062 JS_PUBLIC_API(void)
1063 JS_DestroyContextNoGC(JSContext *cx)
1065 js_DestroyContext(cx, JSDCM_NO_GC);
1068 JS_PUBLIC_API(void)
1069 JS_DestroyContextMaybeGC(JSContext *cx)
1071 js_DestroyContext(cx, JSDCM_MAYBE_GC);
1074 JS_PUBLIC_API(void *)
1075 JS_GetContextPrivate(JSContext *cx)
1077 return cx->data;
1080 JS_PUBLIC_API(void)
1081 JS_SetContextPrivate(JSContext *cx, void *data)
1083 cx->data = data;
1086 JS_PUBLIC_API(JSRuntime *)
1087 JS_GetRuntime(JSContext *cx)
1089 return cx->runtime;
1092 JS_PUBLIC_API(JSContext *)
1093 JS_ContextIterator(JSRuntime *rt, JSContext **iterp)
1095 return js_ContextIterator(rt, JS_TRUE, iterp);
1098 JS_PUBLIC_API(JSVersion)
1099 JS_GetVersion(JSContext *cx)
1101 return JSVERSION_NUMBER(cx);
1104 JS_PUBLIC_API(JSVersion)
1105 JS_SetVersion(JSContext *cx, JSVersion version)
1107 JSVersion oldVersion;
1109 JS_ASSERT(version != JSVERSION_UNKNOWN);
1110 JS_ASSERT((version & ~JSVERSION_MASK) == 0);
1112 oldVersion = JSVERSION_NUMBER(cx);
1113 if (version == oldVersion)
1114 return oldVersion;
1116 /* We no longer support 1.4 or below. */
1117 if (version != JSVERSION_DEFAULT && version <= JSVERSION_1_4)
1118 return oldVersion;
1120 cx->version = (cx->version & ~JSVERSION_MASK) | version;
1121 js_OnVersionChange(cx);
1122 return oldVersion;
1125 static struct v2smap {
1126 JSVersion version;
1127 const char *string;
1128 } v2smap[] = {
1129 {JSVERSION_1_0, "1.0"},
1130 {JSVERSION_1_1, "1.1"},
1131 {JSVERSION_1_2, "1.2"},
1132 {JSVERSION_1_3, "1.3"},
1133 {JSVERSION_1_4, "1.4"},
1134 {JSVERSION_ECMA_3, "ECMAv3"},
1135 {JSVERSION_1_5, "1.5"},
1136 {JSVERSION_1_6, "1.6"},
1137 {JSVERSION_1_7, "1.7"},
1138 {JSVERSION_1_8, "1.8"},
1139 {JSVERSION_DEFAULT, js_default_str},
1140 {JSVERSION_UNKNOWN, NULL}, /* must be last, NULL is sentinel */
1143 JS_PUBLIC_API(const char *)
1144 JS_VersionToString(JSVersion version)
1146 int i;
1148 for (i = 0; v2smap[i].string; i++)
1149 if (v2smap[i].version == version)
1150 return v2smap[i].string;
1151 return "unknown";
1154 JS_PUBLIC_API(JSVersion)
1155 JS_StringToVersion(const char *string)
1157 int i;
1159 for (i = 0; v2smap[i].string; i++)
1160 if (strcmp(v2smap[i].string, string) == 0)
1161 return v2smap[i].version;
1162 return JSVERSION_UNKNOWN;
1165 JS_PUBLIC_API(uint32)
1166 JS_GetOptions(JSContext *cx)
1168 return cx->options;
1171 #define SYNC_OPTIONS_TO_VERSION(cx) \
1172 JS_BEGIN_MACRO \
1173 if ((cx)->options & JSOPTION_XML) \
1174 (cx)->version |= JSVERSION_HAS_XML; \
1175 else \
1176 (cx)->version &= ~JSVERSION_HAS_XML; \
1177 JS_END_MACRO
1179 JS_PUBLIC_API(uint32)
1180 JS_SetOptions(JSContext *cx, uint32 options)
1182 uint32 oldopts = cx->options;
1183 cx->options = options;
1184 SYNC_OPTIONS_TO_VERSION(cx);
1185 return oldopts;
1188 JS_PUBLIC_API(uint32)
1189 JS_ToggleOptions(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(const char *)
1198 JS_GetImplementationVersion(void)
1200 return "JavaScript-C 1.8.0 pre-release 1 2007-10-03";
1204 JS_PUBLIC_API(JSObject *)
1205 JS_GetGlobalObject(JSContext *cx)
1207 return cx->globalObject;
1210 JS_PUBLIC_API(void)
1211 JS_SetGlobalObject(JSContext *cx, JSObject *obj)
1213 cx->globalObject = obj;
1215 #if JS_HAS_XML_SUPPORT
1216 cx->xmlSettingFlags = 0;
1217 #endif
1220 JS_BEGIN_EXTERN_C
1222 JSObject *
1223 js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj)
1225 JSDHashTable *table;
1226 JSBool resolving;
1227 JSRuntime *rt;
1228 JSResolvingKey key;
1229 JSResolvingEntry *entry;
1230 JSObject *fun_proto, *obj_proto;
1232 /* If cx has no global object, use obj so prototypes can be found. */
1233 if (!cx->globalObject)
1234 JS_SetGlobalObject(cx, obj);
1236 /* Record Function and Object in cx->resolvingTable, if we are resolving. */
1237 table = cx->resolvingTable;
1238 resolving = (table && table->entryCount);
1239 rt = cx->runtime;
1240 key.obj = obj;
1241 if (resolving) {
1242 key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]);
1243 entry = (JSResolvingEntry *)
1244 JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1245 if (entry && entry->key.obj && (entry->flags & JSRESFLAG_LOOKUP)) {
1246 /* Already resolving Function, record Object too. */
1247 JS_ASSERT(entry->key.obj == obj);
1248 key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1249 entry = (JSResolvingEntry *)
1250 JS_DHashTableOperate(table, &key, JS_DHASH_ADD);
1252 if (!entry) {
1253 JS_ReportOutOfMemory(cx);
1254 return NULL;
1256 JS_ASSERT(!entry->key.obj && entry->flags == 0);
1257 entry->key = key;
1258 entry->flags = JSRESFLAG_LOOKUP;
1259 } else {
1260 key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1261 if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry))
1262 return NULL;
1264 key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]);
1265 if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) {
1266 key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1267 JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1268 return NULL;
1271 table = cx->resolvingTable;
1274 /* Initialize the function class first so constructors can be made. */
1275 if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Function),
1276 &fun_proto)) {
1277 fun_proto = NULL;
1278 goto out;
1280 if (!fun_proto) {
1281 fun_proto = js_InitFunctionClass(cx, obj);
1282 if (!fun_proto)
1283 goto out;
1284 } else {
1285 JSObject *ctor;
1287 ctor = JS_GetConstructor(cx, fun_proto);
1288 if (!ctor) {
1289 fun_proto = NULL;
1290 goto out;
1292 OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
1293 OBJECT_TO_JSVAL(ctor), 0, 0, 0, NULL);
1296 /* Initialize the object class next so Object.prototype works. */
1297 if (!js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object),
1298 &obj_proto)) {
1299 fun_proto = NULL;
1300 goto out;
1302 if (!obj_proto)
1303 obj_proto = js_InitObjectClass(cx, obj);
1304 if (!obj_proto) {
1305 fun_proto = NULL;
1306 goto out;
1309 /* Function.prototype and the global object delegate to Object.prototype. */
1310 OBJ_SET_PROTO(cx, fun_proto, obj_proto);
1311 if (!OBJ_GET_PROTO(cx, obj))
1312 OBJ_SET_PROTO(cx, obj, obj_proto);
1314 out:
1315 /* If resolving, remove the other entry (Object or Function) from table. */
1316 JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1317 if (!resolving) {
1318 /* If not resolving, remove the first entry added above, for Object. */
1319 JS_ASSERT(key.id == \
1320 ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]));
1321 key.id = ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Object]);
1322 JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
1324 return fun_proto;
1327 JS_END_EXTERN_C
1329 JS_PUBLIC_API(JSBool)
1330 JS_InitStandardClasses(JSContext *cx, JSObject *obj)
1332 JSAtom *atom;
1334 CHECK_REQUEST(cx);
1336 /* Define a top-level property 'undefined' with the undefined value. */
1337 atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
1338 if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1339 NULL, NULL, JSPROP_PERMANENT, NULL)) {
1340 return JS_FALSE;
1343 /* Function and Object require cooperative bootstrapping magic. */
1344 if (!js_InitFunctionAndObjectClasses(cx, obj))
1345 return JS_FALSE;
1347 /* Initialize the rest of the standard objects and functions. */
1348 return js_InitArrayClass(cx, obj) &&
1349 js_InitBlockClass(cx, obj) &&
1350 js_InitBooleanClass(cx, obj) &&
1351 js_InitCallClass(cx, obj) &&
1352 js_InitExceptionClasses(cx, obj) &&
1353 js_InitMathClass(cx, obj) &&
1354 js_InitNumberClass(cx, obj) &&
1355 js_InitJSONClass(cx, obj) &&
1356 js_InitRegExpClass(cx, obj) &&
1357 js_InitStringClass(cx, obj) &&
1358 js_InitEval(cx, obj) &&
1359 #if JS_HAS_SCRIPT_OBJECT
1360 js_InitScriptClass(cx, obj) &&
1361 #endif
1362 #if JS_HAS_XML_SUPPORT
1363 js_InitXMLClasses(cx, obj) &&
1364 #endif
1365 #if JS_HAS_FILE_OBJECT
1366 js_InitFileClass(cx, obj) &&
1367 #endif
1368 #if JS_HAS_GENERATORS
1369 js_InitIteratorClasses(cx, obj) &&
1370 #endif
1371 js_InitDateClass(cx, obj);
1374 #define CLASP(name) (&js_##name##Class)
1375 #define EXT_CLASP(name) (&js_##name##Class.base)
1376 #define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
1377 #define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
1378 #define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
1379 #define EAGER_ATOM_AND_EXT_CLASP(name) EAGER_CLASS_ATOM(name), EXT_CLASP(name)
1380 #define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
1382 typedef struct JSStdName {
1383 JSObjectOp init;
1384 size_t atomOffset; /* offset of atom pointer in JSAtomState */
1385 const char *name; /* null if atom is pre-pinned, else name */
1386 JSClass *clasp;
1387 } JSStdName;
1389 static JSAtom *
1390 StdNameToAtom(JSContext *cx, JSStdName *stdn)
1392 size_t offset;
1393 JSAtom *atom;
1394 const char *name;
1396 offset = stdn->atomOffset;
1397 atom = OFFSET_TO_ATOM(cx->runtime, offset);
1398 if (!atom) {
1399 name = stdn->name;
1400 if (name) {
1401 atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
1402 OFFSET_TO_ATOM(cx->runtime, offset) = atom;
1405 return atom;
1409 * Table of class initializers and their atom offsets in rt->atomState.
1410 * If you add a "standard" class, remember to update this table.
1412 static JSStdName standard_class_atoms[] = {
1413 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Function)},
1414 {js_InitFunctionAndObjectClasses, EAGER_ATOM_AND_CLASP(Object)},
1415 {js_InitArrayClass, EAGER_ATOM_AND_CLASP(Array)},
1416 {js_InitBlockClass, EAGER_ATOM_AND_CLASP(Block)},
1417 {js_InitBooleanClass, EAGER_ATOM_AND_CLASP(Boolean)},
1418 {js_InitDateClass, EAGER_ATOM_AND_CLASP(Date)},
1419 {js_InitMathClass, EAGER_ATOM_AND_CLASP(Math)},
1420 {js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)},
1421 {js_InitStringClass, EAGER_ATOM_AND_CLASP(String)},
1422 {js_InitCallClass, EAGER_ATOM_AND_CLASP(Call)},
1423 {js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)},
1424 {js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)},
1425 #if JS_HAS_SCRIPT_OBJECT
1426 {js_InitScriptClass, EAGER_ATOM_AND_CLASP(Script)},
1427 #endif
1428 #if JS_HAS_XML_SUPPORT
1429 {js_InitXMLClass, EAGER_ATOM_AND_CLASP(XML)},
1430 {js_InitNamespaceClass, EAGER_ATOM_AND_EXT_CLASP(Namespace)},
1431 {js_InitQNameClass, EAGER_ATOM_AND_EXT_CLASP(QName)},
1432 #endif
1433 #if JS_HAS_FILE_OBJECT
1434 {js_InitFileClass, EAGER_ATOM_AND_CLASP(File)},
1435 #endif
1436 #if JS_HAS_GENERATORS
1437 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
1438 #endif
1439 {js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
1440 {NULL, 0, NULL, NULL}
1444 * Table of top-level function and constant names and their init functions.
1445 * If you add a "standard" global function or property, remember to update
1446 * this table.
1448 static JSStdName standard_class_names[] = {
1449 /* ECMA requires that eval be a direct property of the global object. */
1450 {js_InitEval, EAGER_ATOM(eval), NULL},
1452 /* Global properties and functions defined by the Number class. */
1453 {js_InitNumberClass, LAZY_ATOM(NaN), NULL},
1454 {js_InitNumberClass, LAZY_ATOM(Infinity), NULL},
1455 {js_InitNumberClass, LAZY_ATOM(isNaN), NULL},
1456 {js_InitNumberClass, LAZY_ATOM(isFinite), NULL},
1457 {js_InitNumberClass, LAZY_ATOM(parseFloat), NULL},
1458 {js_InitNumberClass, LAZY_ATOM(parseInt), NULL},
1460 /* String global functions. */
1461 {js_InitStringClass, LAZY_ATOM(escape), NULL},
1462 {js_InitStringClass, LAZY_ATOM(unescape), NULL},
1463 {js_InitStringClass, LAZY_ATOM(decodeURI), NULL},
1464 {js_InitStringClass, LAZY_ATOM(encodeURI), NULL},
1465 {js_InitStringClass, LAZY_ATOM(decodeURIComponent), NULL},
1466 {js_InitStringClass, LAZY_ATOM(encodeURIComponent), NULL},
1467 #if JS_HAS_UNEVAL
1468 {js_InitStringClass, LAZY_ATOM(uneval), NULL},
1469 #endif
1471 /* Exception constructors. */
1472 {js_InitExceptionClasses, EAGER_CLASS_ATOM(Error), CLASP(Error)},
1473 {js_InitExceptionClasses, EAGER_CLASS_ATOM(InternalError), CLASP(Error)},
1474 {js_InitExceptionClasses, EAGER_CLASS_ATOM(EvalError), CLASP(Error)},
1475 {js_InitExceptionClasses, EAGER_CLASS_ATOM(RangeError), CLASP(Error)},
1476 {js_InitExceptionClasses, EAGER_CLASS_ATOM(ReferenceError), CLASP(Error)},
1477 {js_InitExceptionClasses, EAGER_CLASS_ATOM(SyntaxError), CLASP(Error)},
1478 {js_InitExceptionClasses, EAGER_CLASS_ATOM(TypeError), CLASP(Error)},
1479 {js_InitExceptionClasses, EAGER_CLASS_ATOM(URIError), CLASP(Error)},
1481 #if JS_HAS_XML_SUPPORT
1482 {js_InitAnyNameClass, EAGER_ATOM_AND_CLASP(AnyName)},
1483 {js_InitAttributeNameClass, EAGER_ATOM_AND_CLASP(AttributeName)},
1484 {js_InitXMLClass, LAZY_ATOM(XMLList), &js_XMLClass},
1485 {js_InitXMLClass, LAZY_ATOM(isXMLName), NULL},
1486 #endif
1488 #if JS_HAS_GENERATORS
1489 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)},
1490 {js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Generator)},
1491 #endif
1493 {NULL, 0, NULL, NULL}
1496 static JSStdName object_prototype_names[] = {
1497 /* Object.prototype properties (global delegates to Object.prototype). */
1498 {js_InitObjectClass, EAGER_ATOM(proto), NULL},
1499 {js_InitObjectClass, EAGER_ATOM(parent), NULL},
1500 {js_InitObjectClass, EAGER_ATOM(count), NULL},
1501 #if JS_HAS_TOSOURCE
1502 {js_InitObjectClass, EAGER_ATOM(toSource), NULL},
1503 #endif
1504 {js_InitObjectClass, EAGER_ATOM(toString), NULL},
1505 {js_InitObjectClass, EAGER_ATOM(toLocaleString), NULL},
1506 {js_InitObjectClass, EAGER_ATOM(valueOf), NULL},
1507 #if JS_HAS_OBJ_WATCHPOINT
1508 {js_InitObjectClass, LAZY_ATOM(watch), NULL},
1509 {js_InitObjectClass, LAZY_ATOM(unwatch), NULL},
1510 #endif
1511 {js_InitObjectClass, LAZY_ATOM(hasOwnProperty), NULL},
1512 {js_InitObjectClass, LAZY_ATOM(isPrototypeOf), NULL},
1513 {js_InitObjectClass, LAZY_ATOM(propertyIsEnumerable), NULL},
1514 #if JS_HAS_GETTER_SETTER
1515 {js_InitObjectClass, LAZY_ATOM(defineGetter), NULL},
1516 {js_InitObjectClass, LAZY_ATOM(defineSetter), NULL},
1517 {js_InitObjectClass, LAZY_ATOM(lookupGetter), NULL},
1518 {js_InitObjectClass, LAZY_ATOM(lookupSetter), NULL},
1519 #endif
1521 {NULL, 0, NULL, NULL}
1524 JS_PUBLIC_API(JSBool)
1525 JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id,
1526 JSBool *resolved)
1528 JSString *idstr;
1529 JSRuntime *rt;
1530 JSAtom *atom;
1531 JSStdName *stdnm;
1532 uintN i;
1534 CHECK_REQUEST(cx);
1535 *resolved = JS_FALSE;
1537 rt = cx->runtime;
1538 JS_ASSERT(rt->state != JSRTS_DOWN);
1539 if (rt->state == JSRTS_LANDING || !JSVAL_IS_STRING(id))
1540 return JS_TRUE;
1542 idstr = JSVAL_TO_STRING(id);
1544 /* Check whether we're resolving 'undefined', and define it if so. */
1545 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1546 if (idstr == ATOM_TO_STRING(atom)) {
1547 *resolved = JS_TRUE;
1548 return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1549 NULL, NULL, JSPROP_PERMANENT, NULL);
1552 /* Try for class constructors/prototypes named by well-known atoms. */
1553 stdnm = NULL;
1554 for (i = 0; standard_class_atoms[i].init; i++) {
1555 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1556 if (idstr == ATOM_TO_STRING(atom)) {
1557 stdnm = &standard_class_atoms[i];
1558 break;
1562 if (!stdnm) {
1563 /* Try less frequently used top-level functions and constants. */
1564 for (i = 0; standard_class_names[i].init; i++) {
1565 atom = StdNameToAtom(cx, &standard_class_names[i]);
1566 if (!atom)
1567 return JS_FALSE;
1568 if (idstr == ATOM_TO_STRING(atom)) {
1569 stdnm = &standard_class_names[i];
1570 break;
1574 if (!stdnm && !OBJ_GET_PROTO(cx, obj)) {
1576 * Try even less frequently used names delegated from the global
1577 * object to Object.prototype, but only if the Object class hasn't
1578 * yet been initialized.
1580 for (i = 0; object_prototype_names[i].init; i++) {
1581 atom = StdNameToAtom(cx, &object_prototype_names[i]);
1582 if (!atom)
1583 return JS_FALSE;
1584 if (idstr == ATOM_TO_STRING(atom)) {
1585 stdnm = &standard_class_names[i];
1586 break;
1592 if (stdnm) {
1594 * If this standard class is anonymous and obj advertises itself as a
1595 * global object (in order to reserve slots for standard class object
1596 * pointers), then we don't want to resolve by name.
1598 * If inversely, either id does not name a class, or id does not name
1599 * an anonymous class, or the global does not reserve slots for class
1600 * objects, then we must call the init hook here.
1602 if (stdnm->clasp &&
1603 (stdnm->clasp->flags & JSCLASS_IS_ANONYMOUS) &&
1604 (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL)) {
1605 return JS_TRUE;
1608 if (!stdnm->init(cx, obj))
1609 return JS_FALSE;
1610 *resolved = JS_TRUE;
1612 return JS_TRUE;
1615 static JSBool
1616 AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom)
1618 JSScopeProperty *sprop;
1619 JSScope *scope;
1621 JS_ASSERT(OBJ_IS_NATIVE(obj));
1622 JS_LOCK_OBJ(cx, obj);
1623 scope = OBJ_SCOPE(obj);
1624 sprop = SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom));
1625 JS_UNLOCK_SCOPE(cx, scope);
1626 return sprop != NULL;
1629 JS_PUBLIC_API(JSBool)
1630 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
1632 JSRuntime *rt;
1633 JSAtom *atom;
1634 uintN i;
1636 CHECK_REQUEST(cx);
1637 rt = cx->runtime;
1639 /* Check whether we need to bind 'undefined' and define it if so. */
1640 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1641 if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1642 !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
1643 NULL, NULL, JSPROP_PERMANENT, NULL)) {
1644 return JS_FALSE;
1647 /* Initialize any classes that have not been resolved yet. */
1648 for (i = 0; standard_class_atoms[i].init; i++) {
1649 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
1650 if (!AlreadyHasOwnProperty(cx, obj, atom) &&
1651 !standard_class_atoms[i].init(cx, obj)) {
1652 return JS_FALSE;
1656 return JS_TRUE;
1659 static JSIdArray *
1660 NewIdArray(JSContext *cx, jsint length)
1662 JSIdArray *ida;
1664 ida = (JSIdArray *)
1665 JS_malloc(cx, offsetof(JSIdArray, vector) + length * sizeof(jsval));
1666 if (ida)
1667 ida->length = length;
1668 return ida;
1672 * Unlike realloc(3), this function frees ida on failure.
1674 static JSIdArray *
1675 SetIdArrayLength(JSContext *cx, JSIdArray *ida, jsint length)
1677 JSIdArray *rida;
1679 rida = (JSIdArray *)
1680 JS_realloc(cx, ida,
1681 offsetof(JSIdArray, vector) + length * sizeof(jsval));
1682 if (!rida)
1683 JS_DestroyIdArray(cx, ida);
1684 else
1685 rida->length = length;
1686 return rida;
1689 static JSIdArray *
1690 AddAtomToArray(JSContext *cx, JSAtom *atom, JSIdArray *ida, jsint *ip)
1692 jsint i, length;
1694 i = *ip;
1695 length = ida->length;
1696 if (i >= length) {
1697 ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
1698 if (!ida)
1699 return NULL;
1700 JS_ASSERT(i < ida->length);
1702 ida->vector[i] = ATOM_TO_JSID(atom);
1703 *ip = i + 1;
1704 return ida;
1707 static JSIdArray *
1708 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
1709 jsint *ip, JSBool *foundp)
1711 *foundp = AlreadyHasOwnProperty(cx, obj, atom);
1712 if (*foundp)
1713 ida = AddAtomToArray(cx, atom, ida, ip);
1714 return ida;
1717 JS_PUBLIC_API(JSIdArray *)
1718 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
1719 JSIdArray *ida)
1721 JSRuntime *rt;
1722 jsint i, j, k;
1723 JSAtom *atom;
1724 JSBool found;
1725 JSObjectOp init;
1727 CHECK_REQUEST(cx);
1728 rt = cx->runtime;
1729 if (ida) {
1730 i = ida->length;
1731 } else {
1732 ida = NewIdArray(cx, 8);
1733 if (!ida)
1734 return NULL;
1735 i = 0;
1738 /* Check whether 'undefined' has been resolved and enumerate it if so. */
1739 atom = rt->atomState.typeAtoms[JSTYPE_VOID];
1740 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1741 if (!ida)
1742 return NULL;
1744 /* Enumerate only classes that *have* been resolved. */
1745 for (j = 0; standard_class_atoms[j].init; j++) {
1746 atom = OFFSET_TO_ATOM(rt, standard_class_atoms[j].atomOffset);
1747 ida = EnumerateIfResolved(cx, obj, atom, ida, &i, &found);
1748 if (!ida)
1749 return NULL;
1751 if (found) {
1752 init = standard_class_atoms[j].init;
1754 for (k = 0; standard_class_names[k].init; k++) {
1755 if (standard_class_names[k].init == init) {
1756 atom = StdNameToAtom(cx, &standard_class_names[k]);
1757 ida = AddAtomToArray(cx, atom, ida, &i);
1758 if (!ida)
1759 return NULL;
1763 if (init == js_InitObjectClass) {
1764 for (k = 0; object_prototype_names[k].init; k++) {
1765 atom = StdNameToAtom(cx, &object_prototype_names[k]);
1766 ida = AddAtomToArray(cx, atom, ida, &i);
1767 if (!ida)
1768 return NULL;
1774 /* Trim to exact length. */
1775 return SetIdArrayLength(cx, ida, i);
1778 #undef CLASP
1779 #undef EAGER_ATOM
1780 #undef EAGER_CLASS_ATOM
1781 #undef EAGER_ATOM_CLASP
1782 #undef LAZY_ATOM
1784 JS_PUBLIC_API(JSBool)
1785 JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
1786 JSObject **objp)
1788 CHECK_REQUEST(cx);
1789 return js_GetClassObject(cx, obj, key, objp);
1792 JS_PUBLIC_API(JSObject *)
1793 JS_GetScopeChain(JSContext *cx)
1795 JSStackFrame *fp;
1797 CHECK_REQUEST(cx);
1798 fp = cx->fp;
1799 if (!fp) {
1801 * There is no code active on this context. In place of an actual
1802 * scope chain, use the context's global object, which is set in
1803 * js_InitFunctionAndObjectClasses, and which represents the default
1804 * scope chain for the embedding. See also js_FindClassObject.
1806 * For embeddings that use the inner and outer object hooks, the inner
1807 * object represents the ultimate global object, with the outer object
1808 * acting as a stand-in.
1810 JSObject *obj = cx->globalObject;
1811 if (!obj) {
1812 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
1813 return NULL;
1816 OBJ_TO_INNER_OBJECT(cx, obj);
1817 return obj;
1819 return js_GetScopeChain(cx, fp);
1822 JS_PUBLIC_API(JSObject *)
1823 JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
1825 JSObject *parent;
1827 while ((parent = OBJ_GET_PARENT(cx, obj)) != NULL)
1828 obj = parent;
1829 return obj;
1832 JS_PUBLIC_API(jsval)
1833 JS_ComputeThis(JSContext *cx, jsval *vp)
1835 if (!js_ComputeThis(cx, JS_FALSE, vp + 2))
1836 return JSVAL_NULL;
1837 return vp[1];
1840 JS_PUBLIC_API(void *)
1841 JS_malloc(JSContext *cx, size_t nbytes)
1843 void *p;
1845 JS_ASSERT(nbytes != 0);
1846 JS_COUNT_OPERATION(cx, JSOW_ALLOCATION);
1847 if (nbytes == 0)
1848 nbytes = 1;
1850 p = malloc(nbytes);
1851 if (!p) {
1852 JS_ReportOutOfMemory(cx);
1853 return NULL;
1855 js_UpdateMallocCounter(cx, nbytes);
1857 return p;
1860 JS_PUBLIC_API(void *)
1861 JS_realloc(JSContext *cx, void *p, size_t nbytes)
1863 JS_COUNT_OPERATION(cx, JSOW_ALLOCATION);
1864 p = realloc(p, nbytes);
1865 if (!p)
1866 JS_ReportOutOfMemory(cx);
1867 return p;
1870 JS_PUBLIC_API(void)
1871 JS_free(JSContext *cx, void *p)
1873 if (p)
1874 free(p);
1877 JS_PUBLIC_API(char *)
1878 JS_strdup(JSContext *cx, const char *s)
1880 size_t n;
1881 void *p;
1883 n = strlen(s) + 1;
1884 p = JS_malloc(cx, n);
1885 if (!p)
1886 return NULL;
1887 return (char *)memcpy(p, s, n);
1890 JS_PUBLIC_API(jsdouble *)
1891 JS_NewDouble(JSContext *cx, jsdouble d)
1893 CHECK_REQUEST(cx);
1894 return js_NewWeaklyRootedDouble(cx, d);
1897 JS_PUBLIC_API(JSBool)
1898 JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
1900 jsdouble *dp;
1902 CHECK_REQUEST(cx);
1903 dp = js_NewWeaklyRootedDouble(cx, d);
1904 if (!dp)
1905 return JS_FALSE;
1906 *rval = DOUBLE_TO_JSVAL(dp);
1907 return JS_TRUE;
1910 JS_PUBLIC_API(JSBool)
1911 JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
1913 jsint i;
1915 CHECK_REQUEST(cx);
1916 if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
1917 *rval = INT_TO_JSVAL(i);
1918 return JS_TRUE;
1920 return JS_NewDoubleValue(cx, d, rval);
1923 #undef JS_AddRoot
1924 JS_PUBLIC_API(JSBool)
1925 JS_AddRoot(JSContext *cx, void *rp)
1927 CHECK_REQUEST(cx);
1928 return js_AddRoot(cx, rp, NULL);
1931 JS_PUBLIC_API(JSBool)
1932 JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name)
1934 return js_AddRootRT(rt, rp, name);
1937 JS_PUBLIC_API(JSBool)
1938 JS_RemoveRoot(JSContext *cx, void *rp)
1940 CHECK_REQUEST(cx);
1941 return js_RemoveRoot(cx->runtime, rp);
1944 JS_PUBLIC_API(JSBool)
1945 JS_RemoveRootRT(JSRuntime *rt, void *rp)
1947 return js_RemoveRoot(rt, rp);
1950 JS_PUBLIC_API(JSBool)
1951 JS_AddNamedRoot(JSContext *cx, void *rp, const char *name)
1953 CHECK_REQUEST(cx);
1954 return js_AddRoot(cx, rp, name);
1957 JS_PUBLIC_API(void)
1958 JS_ClearNewbornRoots(JSContext *cx)
1960 JS_CLEAR_WEAK_ROOTS(&cx->weakRoots);
1963 JS_PUBLIC_API(JSBool)
1964 JS_EnterLocalRootScope(JSContext *cx)
1966 CHECK_REQUEST(cx);
1967 return js_EnterLocalRootScope(cx);
1970 JS_PUBLIC_API(void)
1971 JS_LeaveLocalRootScope(JSContext *cx)
1973 CHECK_REQUEST(cx);
1974 js_LeaveLocalRootScope(cx);
1977 JS_PUBLIC_API(void)
1978 JS_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval)
1980 CHECK_REQUEST(cx);
1981 js_LeaveLocalRootScopeWithResult(cx, rval);
1984 JS_PUBLIC_API(void)
1985 JS_ForgetLocalRoot(JSContext *cx, void *thing)
1987 CHECK_REQUEST(cx);
1988 js_ForgetLocalRoot(cx, (jsval) thing);
1991 #ifdef DEBUG
1993 JS_PUBLIC_API(void)
1994 JS_DumpNamedRoots(JSRuntime *rt,
1995 void (*dump)(const char *name, void *rp, void *data),
1996 void *data)
1998 js_DumpNamedRoots(rt, dump, data);
2001 #endif /* DEBUG */
2003 JS_PUBLIC_API(uint32)
2004 JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
2006 return js_MapGCRoots(rt, map, data);
2009 JS_PUBLIC_API(JSBool)
2010 JS_LockGCThing(JSContext *cx, void *thing)
2012 JSBool ok;
2014 CHECK_REQUEST(cx);
2015 ok = js_LockGCThingRT(cx->runtime, thing);
2016 if (!ok)
2017 JS_ReportOutOfMemory(cx);
2018 return ok;
2021 JS_PUBLIC_API(JSBool)
2022 JS_LockGCThingRT(JSRuntime *rt, void *thing)
2024 return js_LockGCThingRT(rt, thing);
2027 JS_PUBLIC_API(JSBool)
2028 JS_UnlockGCThing(JSContext *cx, void *thing)
2030 JSBool ok;
2032 CHECK_REQUEST(cx);
2033 ok = js_UnlockGCThingRT(cx->runtime, thing);
2034 if (!ok)
2035 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_UNLOCK);
2036 return ok;
2039 JS_PUBLIC_API(JSBool)
2040 JS_UnlockGCThingRT(JSRuntime *rt, void *thing)
2042 return js_UnlockGCThingRT(rt, thing);
2045 JS_PUBLIC_API(void)
2046 JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
2048 rt->gcExtraRootsTraceOp = traceOp;
2049 rt->gcExtraRootsData = data;
2052 JS_PUBLIC_API(void)
2053 JS_TraceRuntime(JSTracer *trc)
2055 JSBool allAtoms = trc->context->runtime->gcKeepAtoms != 0;
2057 js_TraceRuntime(trc, allAtoms);
2060 #ifdef DEBUG
2062 #ifdef HAVE_XPCONNECT
2063 #include "dump_xpc.h"
2064 #endif
2066 JS_PUBLIC_API(void)
2067 JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc,
2068 void *thing, uint32 kind, JSBool details)
2070 const char *name;
2071 size_t n;
2073 if (bufsize == 0)
2074 return;
2076 switch (kind) {
2077 case JSTRACE_OBJECT:
2079 JSObject *obj = (JSObject *)thing;
2080 JSClass *clasp = STOBJ_GET_CLASS(obj);
2082 name = clasp->name;
2083 #ifdef HAVE_XPCONNECT
2084 if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
2085 jsval privateValue = STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
2087 JS_ASSERT(clasp->flags & JSCLASS_HAS_PRIVATE);
2088 if (!JSVAL_IS_VOID(privateValue)) {
2089 void *privateThing = JSVAL_TO_PRIVATE(privateValue);
2090 const char *xpcClassName = GetXPCObjectClassName(privateThing);
2092 if (xpcClassName)
2093 name = xpcClassName;
2096 #endif
2097 break;
2100 case JSTRACE_STRING:
2101 name = JSSTRING_IS_DEPENDENT((JSString *)thing)
2102 ? "substring"
2103 : "string";
2104 break;
2106 case JSTRACE_DOUBLE:
2107 name = "double";
2108 break;
2110 #if JS_HAS_XML_SUPPORT
2111 case JSTRACE_XML:
2112 name = "xml";
2113 break;
2114 #endif
2115 default:
2116 JS_ASSERT(0);
2117 return;
2118 break;
2121 n = strlen(name);
2122 if (n > bufsize - 1)
2123 n = bufsize - 1;
2124 memcpy(buf, name, n + 1);
2125 buf += n;
2126 bufsize -= n;
2128 if (details && bufsize > 2) {
2129 *buf++ = ' ';
2130 bufsize--;
2132 switch (kind) {
2133 case JSTRACE_OBJECT:
2135 JSObject *obj = (JSObject *)thing;
2136 JSClass *clasp = STOBJ_GET_CLASS(obj);
2137 if (clasp == &js_FunctionClass) {
2138 JSFunction *fun = (JSFunction *)
2139 JS_GetPrivate(trc->context, obj);
2141 if (!fun) {
2142 JS_snprintf(buf, bufsize, "<newborn>");
2143 } else if (FUN_OBJECT(fun) != obj) {
2144 JS_snprintf(buf, bufsize, "%p", fun);
2145 } else {
2146 if (fun->atom && ATOM_IS_STRING(fun->atom))
2147 js_PutEscapedString(buf, bufsize,
2148 ATOM_TO_STRING(fun->atom), 0);
2150 } else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
2151 jsval privateValue = STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
2152 void *privateThing = JSVAL_IS_VOID(privateValue)
2153 ? NULL
2154 : JSVAL_TO_PRIVATE(privateValue);
2156 JS_snprintf(buf, bufsize, "%p", privateThing);
2157 } else {
2158 JS_snprintf(buf, bufsize, "<no private>");
2160 break;
2163 case JSTRACE_STRING:
2164 js_PutEscapedString(buf, bufsize, (JSString *)thing, 0);
2165 break;
2167 case JSTRACE_DOUBLE:
2168 JS_snprintf(buf, bufsize, "%g", *(jsdouble *)thing);
2169 break;
2171 #if JS_HAS_XML_SUPPORT
2172 case JSTRACE_XML:
2174 extern const char *js_xml_class_str[];
2175 JSXML *xml = (JSXML *)thing;
2177 JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]);
2178 break;
2180 #endif
2181 default:
2182 JS_ASSERT(0);
2183 break;
2186 buf[bufsize - 1] = '\0';
2189 typedef struct JSHeapDumpNode JSHeapDumpNode;
2191 struct JSHeapDumpNode {
2192 void *thing;
2193 uint32 kind;
2194 JSHeapDumpNode *next; /* next sibling */
2195 JSHeapDumpNode *parent; /* node with the thing that refer to thing
2196 from this node */
2197 char edgeName[1]; /* name of the edge from parent->thing
2198 into thing */
2201 typedef struct JSDumpingTracer {
2202 JSTracer base;
2203 JSDHashTable visited;
2204 JSBool ok;
2205 void *startThing;
2206 void *thingToFind;
2207 void *thingToIgnore;
2208 JSHeapDumpNode *parentNode;
2209 JSHeapDumpNode **lastNodep;
2210 char buffer[200];
2211 } JSDumpingTracer;
2213 static void
2214 DumpNotify(JSTracer *trc, void *thing, uint32 kind)
2216 JSDumpingTracer *dtrc;
2217 JSContext *cx;
2218 JSDHashEntryStub *entry;
2219 JSHeapDumpNode *node;
2220 const char *edgeName;
2221 size_t edgeNameSize;
2223 JS_ASSERT(trc->callback == DumpNotify);
2224 dtrc = (JSDumpingTracer *)trc;
2226 if (!dtrc->ok || thing == dtrc->thingToIgnore)
2227 return;
2229 cx = trc->context;
2232 * Check if we have already seen thing unless it is thingToFind to include
2233 * it to the graph each time we reach it and print all live things that
2234 * refer to thingToFind.
2236 * This does not print all possible paths leading to thingToFind since
2237 * when a thing A refers directly or indirectly to thingToFind and A is
2238 * present several times in the graph, we will print only the first path
2239 * leading to A and thingToFind, other ways to reach A will be ignored.
2241 if (dtrc->thingToFind != thing) {
2243 * The startThing check allows to avoid putting startThing into the
2244 * hash table before tracing startThing in JS_DumpHeap.
2246 if (thing == dtrc->startThing)
2247 return;
2248 entry = (JSDHashEntryStub *)
2249 JS_DHashTableOperate(&dtrc->visited, thing, JS_DHASH_ADD);
2250 if (!entry) {
2251 JS_ReportOutOfMemory(cx);
2252 dtrc->ok = JS_FALSE;
2253 return;
2255 if (entry->key)
2256 return;
2257 entry->key = thing;
2260 if (dtrc->base.debugPrinter) {
2261 dtrc->base.debugPrinter(trc, dtrc->buffer, sizeof(dtrc->buffer));
2262 edgeName = dtrc->buffer;
2263 } else if (dtrc->base.debugPrintIndex != (size_t)-1) {
2264 JS_snprintf(dtrc->buffer, sizeof(dtrc->buffer), "%s[%lu]",
2265 (const char *)dtrc->base.debugPrintArg,
2266 dtrc->base.debugPrintIndex);
2267 edgeName = dtrc->buffer;
2268 } else {
2269 edgeName = (const char*)dtrc->base.debugPrintArg;
2272 edgeNameSize = strlen(edgeName) + 1;
2273 node = (JSHeapDumpNode *)
2274 JS_malloc(cx, offsetof(JSHeapDumpNode, edgeName) + edgeNameSize);
2275 if (!node) {
2276 dtrc->ok = JS_FALSE;
2277 return;
2280 node->thing = thing;
2281 node->kind = kind;
2282 node->next = NULL;
2283 node->parent = dtrc->parentNode;
2284 memcpy(node->edgeName, edgeName, edgeNameSize);
2286 JS_ASSERT(!*dtrc->lastNodep);
2287 *dtrc->lastNodep = node;
2288 dtrc->lastNodep = &node->next;
2291 /* Dump node and the chain that leads to thing it contains. */
2292 static JSBool
2293 DumpNode(JSDumpingTracer *dtrc, FILE* fp, JSHeapDumpNode *node)
2295 JSHeapDumpNode *prev, *following;
2296 size_t chainLimit;
2297 JSBool ok;
2298 enum { MAX_PARENTS_TO_PRINT = 10 };
2300 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2301 &dtrc->base, node->thing, node->kind, JS_TRUE);
2302 if (fprintf(fp, "%p %-22s via ", node->thing, dtrc->buffer) < 0)
2303 return JS_FALSE;
2306 * We need to print the parent chain in the reverse order. To do it in
2307 * O(N) time where N is the chain length we first reverse the chain while
2308 * searching for the top and then print each node while restoring the
2309 * chain order.
2311 chainLimit = MAX_PARENTS_TO_PRINT;
2312 prev = NULL;
2313 for (;;) {
2314 following = node->parent;
2315 node->parent = prev;
2316 prev = node;
2317 node = following;
2318 if (!node)
2319 break;
2320 if (chainLimit == 0) {
2321 if (fputs("...", fp) < 0)
2322 return JS_FALSE;
2323 break;
2325 --chainLimit;
2328 node = prev;
2329 prev = following;
2330 ok = JS_TRUE;
2331 do {
2332 /* Loop must continue even when !ok to restore the parent chain. */
2333 if (ok) {
2334 if (!prev) {
2335 /* Print edge from some runtime root or startThing. */
2336 if (fputs(node->edgeName, fp) < 0)
2337 ok = JS_FALSE;
2338 } else {
2339 JS_PrintTraceThingInfo(dtrc->buffer, sizeof dtrc->buffer,
2340 &dtrc->base, prev->thing, prev->kind,
2341 JS_FALSE);
2342 if (fprintf(fp, "(%p %s).%s",
2343 prev->thing, dtrc->buffer, node->edgeName) < 0) {
2344 ok = JS_FALSE;
2348 following = node->parent;
2349 node->parent = prev;
2350 prev = node;
2351 node = following;
2352 } while (node);
2354 return ok && putc('\n', fp) >= 0;
2357 JS_PUBLIC_API(JSBool)
2358 JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind,
2359 void *thingToFind, size_t maxDepth, void *thingToIgnore)
2361 JSDumpingTracer dtrc;
2362 JSHeapDumpNode *node, *children, *next, *parent;
2363 size_t depth;
2364 JSBool thingToFindWasTraced;
2366 if (maxDepth == 0)
2367 return JS_TRUE;
2369 JS_TRACER_INIT(&dtrc.base, cx, DumpNotify);
2370 if (!JS_DHashTableInit(&dtrc.visited, JS_DHashGetStubOps(),
2371 NULL, sizeof(JSDHashEntryStub),
2372 JS_DHASH_DEFAULT_CAPACITY(100))) {
2373 JS_ReportOutOfMemory(cx);
2374 return JS_FALSE;
2376 dtrc.ok = JS_TRUE;
2377 dtrc.startThing = startThing;
2378 dtrc.thingToFind = thingToFind;
2379 dtrc.thingToIgnore = thingToIgnore;
2380 dtrc.parentNode = NULL;
2381 node = NULL;
2382 dtrc.lastNodep = &node;
2383 if (!startThing) {
2384 JS_ASSERT(startKind == 0);
2385 JS_TraceRuntime(&dtrc.base);
2386 } else {
2387 JS_TraceChildren(&dtrc.base, startThing, startKind);
2390 depth = 1;
2391 if (!node)
2392 goto dump_out;
2394 thingToFindWasTraced = thingToFind && thingToFind == startThing;
2395 for (;;) {
2397 * Loop must continue even when !dtrc.ok to free all nodes allocated
2398 * so far.
2400 if (dtrc.ok) {
2401 if (thingToFind == NULL || thingToFind == node->thing)
2402 dtrc.ok = DumpNode(&dtrc, fp, node);
2404 /* Descend into children. */
2405 if (dtrc.ok &&
2406 depth < maxDepth &&
2407 (thingToFind != node->thing || !thingToFindWasTraced)) {
2408 dtrc.parentNode = node;
2409 children = NULL;
2410 dtrc.lastNodep = &children;
2411 JS_TraceChildren(&dtrc.base, node->thing, node->kind);
2412 if (thingToFind == node->thing)
2413 thingToFindWasTraced = JS_TRUE;
2414 if (children != NULL) {
2415 ++depth;
2416 node = children;
2417 continue;
2422 /* Move to next or parents next and free the node. */
2423 for (;;) {
2424 next = node->next;
2425 parent = node->parent;
2426 JS_free(cx, node);
2427 node = next;
2428 if (node)
2429 break;
2430 if (!parent)
2431 goto dump_out;
2432 JS_ASSERT(depth > 1);
2433 --depth;
2434 node = parent;
2438 dump_out:
2439 JS_ASSERT(depth == 1);
2440 JS_DHashTableFinish(&dtrc.visited);
2441 return dtrc.ok;
2444 #endif /* DEBUG */
2446 JS_PUBLIC_API(void)
2447 JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg)
2449 JSTracer *trc;
2451 trc = (JSTracer *)arg;
2452 if (!trc)
2453 trc = cx->runtime->gcMarkingTracer;
2454 else
2455 JS_ASSERT(trc == cx->runtime->gcMarkingTracer);
2457 #ifdef JS_THREADSAFE
2458 JS_ASSERT(cx->runtime->gcThread == trc->context->thread);
2459 #endif
2460 JS_SET_TRACING_NAME(trc, name ? name : "unknown");
2461 js_CallValueTracerIfGCThing(trc, (jsval)thing);
2464 extern JS_PUBLIC_API(JSBool)
2465 JS_IsGCMarkingTracer(JSTracer *trc)
2467 return IS_GC_MARKING_TRACER(trc);
2470 JS_PUBLIC_API(void)
2471 JS_GC(JSContext *cx)
2473 /* Don't nuke active arenas if executing or compiling. */
2474 if (cx->stackPool.current == &cx->stackPool.first)
2475 JS_FinishArenaPool(&cx->stackPool);
2476 if (cx->tempPool.current == &cx->tempPool.first)
2477 JS_FinishArenaPool(&cx->tempPool);
2478 js_GC(cx, GC_NORMAL);
2481 JS_PUBLIC_API(void)
2482 JS_MaybeGC(JSContext *cx)
2484 JSRuntime *rt;
2485 uint32 bytes, lastBytes;
2487 rt = cx->runtime;
2489 #ifdef JS_GC_ZEAL
2490 if (rt->gcZeal > 0) {
2491 JS_GC(cx);
2492 return;
2494 #endif
2496 bytes = rt->gcBytes;
2497 lastBytes = rt->gcLastBytes;
2500 * We run the GC if we used all available free GC cells and had to
2501 * allocate extra 1/3 of GC arenas since the last run of GC, or if
2502 * we have malloc'd more bytes through JS_malloc than we were told
2503 * to allocate by JS_NewRuntime.
2505 * The reason for
2506 * bytes > 4/3 lastBytes
2507 * condition is the following. Bug 312238 changed bytes and lastBytes
2508 * to mean the total amount of memory that the GC uses now and right
2509 * after the last GC.
2511 * Before the bug the variables meant the size of allocated GC things
2512 * now and right after the last GC. That size did not include the
2513 * memory taken by free GC cells and the condition was
2514 * bytes > 3/2 lastBytes.
2515 * That is, we run the GC if we have half again as many bytes of
2516 * GC-things as the last time we GC'd. To be compatible we need to
2517 * express that condition through the new meaning of bytes and
2518 * lastBytes.
2520 * We write the original condition as
2521 * B*(1-F) > 3/2 Bl*(1-Fl)
2522 * where B is the total memory size allocated by GC and F is the free
2523 * cell density currently and Sl and Fl are the size and the density
2524 * right after GC. The density by definition is memory taken by free
2525 * cells divided by total amount of memory. In other words, B and Bl
2526 * are bytes and lastBytes with the new meaning and B*(1-F) and
2527 * Bl*(1-Fl) are bytes and lastBytes with the original meaning.
2529 * Our task is to exclude F and Fl from the last statement. According
2530 * to the stats from bug 331966 comment 23, Fl is about 10-25% for a
2531 * typical run of the browser. It means that the original condition
2532 * implied that we did not run GC unless we exhausted the pool of
2533 * free cells. Indeed if we still have free cells, then B == Bl since
2534 * we did not yet allocated any new arenas and the condition means
2535 * 1 - F > 3/2 (1-Fl) or 3/2Fl > 1/2 + F
2536 * That implies 3/2 Fl > 1/2 or Fl > 1/3. That can not be fulfilled
2537 * for the state described by the stats. So we can write the original
2538 * condition as:
2539 * F == 0 && B > 3/2 Bl(1-Fl)
2540 * Again using the stats we see that Fl is about 11% when the browser
2541 * starts up and when we are far from hitting rt->gcMaxBytes. With
2542 * this F we have
2543 * F == 0 && B > 3/2 Bl(1-0.11)
2544 * or approximately F == 0 && B > 4/3 Bl.
2546 if ((bytes > 8192 && bytes > lastBytes + lastBytes / 3) ||
2547 rt->gcMallocBytes >= rt->gcMaxMallocBytes) {
2548 JS_GC(cx);
2552 JS_PUBLIC_API(JSGCCallback)
2553 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
2555 CHECK_REQUEST(cx);
2556 return JS_SetGCCallbackRT(cx->runtime, cb);
2559 JS_PUBLIC_API(JSGCCallback)
2560 JS_SetGCCallbackRT(JSRuntime *rt, JSGCCallback cb)
2562 JSGCCallback oldcb;
2564 oldcb = rt->gcCallback;
2565 rt->gcCallback = cb;
2566 return oldcb;
2569 JS_PUBLIC_API(JSBool)
2570 JS_IsAboutToBeFinalized(JSContext *cx, void *thing)
2572 JS_ASSERT(thing);
2573 return js_IsAboutToBeFinalized(cx, thing);
2576 JS_PUBLIC_API(void)
2577 JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32 value)
2579 switch (key) {
2580 case JSGC_MAX_BYTES:
2581 rt->gcMaxBytes = value;
2582 break;
2583 case JSGC_MAX_MALLOC_BYTES:
2584 rt->gcMaxMallocBytes = value;
2585 break;
2586 case JSGC_STACKPOOL_LIFESPAN:
2587 rt->gcEmptyArenaPoolLifespan = value;
2588 break;
2592 JS_PUBLIC_API(intN)
2593 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer)
2595 return js_ChangeExternalStringFinalizer(NULL, finalizer);
2598 JS_PUBLIC_API(intN)
2599 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer)
2601 return js_ChangeExternalStringFinalizer(finalizer, NULL);
2604 JS_PUBLIC_API(JSString *)
2605 JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
2607 JSString *str;
2609 CHECK_REQUEST(cx);
2610 JS_ASSERT((uintN) type < (uintN) (GCX_NTYPES - GCX_EXTERNAL_STRING));
2612 str = (JSString *) js_NewGCThing(cx, (uintN) type + GCX_EXTERNAL_STRING,
2613 sizeof(JSString));
2614 if (!str)
2615 return NULL;
2616 JSFLATSTR_INIT(str, chars, length);
2617 return str;
2620 JS_PUBLIC_API(intN)
2621 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
2623 return js_GetExternalStringGCType(str);
2626 JS_PUBLIC_API(void)
2627 JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
2629 #if JS_STACK_GROWTH_DIRECTION > 0
2630 if (limitAddr == 0)
2631 limitAddr = (jsuword)-1;
2632 #endif
2633 cx->stackLimit = limitAddr;
2636 JS_PUBLIC_API(void)
2637 JS_SetScriptStackQuota(JSContext *cx, size_t quota)
2639 cx->scriptStackQuota = quota;
2642 /************************************************************************/
2644 JS_PUBLIC_API(void)
2645 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
2647 JS_free(cx, ida);
2650 JS_PUBLIC_API(JSBool)
2651 JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
2653 CHECK_REQUEST(cx);
2654 if (JSVAL_IS_INT(v))
2655 *idp = INT_JSVAL_TO_JSID(v);
2656 #if JS_HAS_XML_SUPPORT
2657 else if (!JSVAL_IS_PRIMITIVE(v))
2658 *idp = OBJECT_JSVAL_TO_JSID(v);
2659 #endif
2660 else
2661 return js_ValueToStringId(cx, v, idp);
2662 return JS_TRUE;
2665 JS_PUBLIC_API(JSBool)
2666 JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
2668 CHECK_REQUEST(cx);
2669 *vp = ID_TO_VALUE(id);
2670 return JS_TRUE;
2673 JS_PUBLIC_API(JSBool)
2674 JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
2676 return JS_TRUE;
2679 JS_PUBLIC_API(JSBool)
2680 JS_EnumerateStub(JSContext *cx, JSObject *obj)
2682 return JS_TRUE;
2685 JS_PUBLIC_API(JSBool)
2686 JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id)
2688 return JS_TRUE;
2691 JS_PUBLIC_API(JSBool)
2692 JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
2694 return js_TryValueOf(cx, obj, type, vp);
2697 JS_PUBLIC_API(void)
2698 JS_FinalizeStub(JSContext *cx, JSObject *obj)
2702 JS_PUBLIC_API(JSObject *)
2703 JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
2704 JSClass *clasp, JSNative constructor, uintN nargs,
2705 JSPropertySpec *ps, JSFunctionSpec *fs,
2706 JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
2708 JSAtom *atom;
2709 JSProtoKey key;
2710 JSObject *proto, *ctor;
2711 JSTempValueRooter tvr;
2712 jsval cval, rval;
2713 JSBool named;
2714 JSFunction *fun;
2716 CHECK_REQUEST(cx);
2717 atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
2718 if (!atom)
2719 return NULL;
2722 * When initializing a standard class, if no parent_proto (grand-proto of
2723 * instances of the class, parent-proto of the class's prototype object)
2724 * is given, we must use Object.prototype if it is available. Otherwise,
2725 * we could look up the wrong binding for a class name in obj. Example:
2727 * String = Array;
2728 * print("hi there".join);
2730 * should print undefined, not Array.prototype.join. This is required by
2731 * ECMA-262, alas. It might have been better to make String readonly and
2732 * permanent in the global object, instead -- but that's too big a change
2733 * to swallow at this point.
2735 key = JSCLASS_CACHED_PROTO_KEY(clasp);
2736 if (key != JSProto_Null &&
2737 !parent_proto &&
2738 !js_GetClassPrototype(cx, obj, INT_TO_JSID(JSProto_Object),
2739 &parent_proto)) {
2740 return NULL;
2743 /* Create a prototype object for this class. */
2744 proto = js_NewObject(cx, clasp, parent_proto, obj, 0);
2745 if (!proto)
2746 return NULL;
2748 /* After this point, control must exit via label bad or out. */
2749 JS_PUSH_TEMP_ROOT_OBJECT(cx, proto, &tvr);
2751 if (!constructor) {
2753 * Lacking a constructor, name the prototype (e.g., Math) unless this
2754 * class (a) is anonymous, i.e. for internal use only; (b) the class
2755 * of obj (the global object) is has a reserved slot indexed by key;
2756 * and (c) key is not the null key.
2758 if ((clasp->flags & JSCLASS_IS_ANONYMOUS) &&
2759 (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL) &&
2760 key != JSProto_Null) {
2761 named = JS_FALSE;
2762 } else {
2763 named = OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
2764 OBJECT_TO_JSVAL(proto),
2765 JS_PropertyStub, JS_PropertyStub,
2766 (clasp->flags & JSCLASS_IS_ANONYMOUS)
2767 ? JSPROP_READONLY | JSPROP_PERMANENT
2768 : 0,
2769 NULL);
2770 if (!named)
2771 goto bad;
2774 ctor = proto;
2775 } else {
2776 /* Define the constructor function in obj's scope. */
2777 fun = js_DefineFunction(cx, obj, atom, constructor, nargs,
2778 JSFUN_STUB_GSOPS);
2779 named = (fun != NULL);
2780 if (!fun)
2781 goto bad;
2784 * Remember the class this function is a constructor for so that
2785 * we know to create an object of this class when we call the
2786 * constructor.
2788 FUN_CLASP(fun) = clasp;
2791 * Optionally construct the prototype object, before the class has
2792 * been fully initialized. Allow the ctor to replace proto with a
2793 * different object, as is done for operator new -- and as at least
2794 * XML support requires.
2796 ctor = FUN_OBJECT(fun);
2797 if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) {
2798 cval = OBJECT_TO_JSVAL(ctor);
2799 if (!js_InternalConstruct(cx, proto, cval, 0, NULL, &rval))
2800 goto bad;
2801 if (!JSVAL_IS_PRIMITIVE(rval) && JSVAL_TO_OBJECT(rval) != proto)
2802 proto = JSVAL_TO_OBJECT(rval);
2805 /* Connect constructor and prototype by named properties. */
2806 if (!js_SetClassPrototype(cx, ctor, proto,
2807 JSPROP_READONLY | JSPROP_PERMANENT)) {
2808 goto bad;
2811 /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
2812 if (OBJ_GET_CLASS(cx, ctor) == clasp) {
2813 OBJ_SET_PROTO(cx, ctor, proto);
2817 /* Add properties and methods to the prototype and the constructor. */
2818 if ((ps && !JS_DefineProperties(cx, proto, ps)) ||
2819 (fs && !JS_DefineFunctions(cx, proto, fs)) ||
2820 (static_ps && !JS_DefineProperties(cx, ctor, static_ps)) ||
2821 (static_fs && !JS_DefineFunctions(cx, ctor, static_fs))) {
2822 goto bad;
2825 /* If this is a standard class, cache its prototype. */
2826 if (key != JSProto_Null && !js_SetClassObject(cx, obj, key, ctor))
2827 goto bad;
2829 out:
2830 JS_POP_TEMP_ROOT(cx, &tvr);
2831 return proto;
2833 bad:
2834 if (named)
2835 (void) OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &rval);
2836 proto = NULL;
2837 goto out;
2840 #ifdef JS_THREADSAFE
2841 JS_PUBLIC_API(JSClass *)
2842 JS_GetClass(JSContext *cx, JSObject *obj)
2844 return OBJ_GET_CLASS(cx, obj);
2846 #else
2847 JS_PUBLIC_API(JSClass *)
2848 JS_GetClass(JSObject *obj)
2850 return LOCKED_OBJ_GET_CLASS(obj);
2852 #endif
2854 JS_PUBLIC_API(JSBool)
2855 JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv)
2857 JSFunction *fun;
2859 CHECK_REQUEST(cx);
2860 if (obj && OBJ_GET_CLASS(cx, obj) == clasp)
2861 return JS_TRUE;
2862 if (argv) {
2863 fun = js_ValueToFunction(cx, &argv[-2], 0);
2864 if (fun) {
2865 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2866 JSMSG_INCOMPATIBLE_PROTO,
2867 clasp->name, JS_GetFunctionName(fun),
2869 ? OBJ_GET_CLASS(cx, obj)->name
2870 : js_null_str);
2873 return JS_FALSE;
2876 JS_PUBLIC_API(JSBool)
2877 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
2879 return js_HasInstance(cx, obj, v, bp);
2882 JS_PUBLIC_API(void *)
2883 JS_GetPrivate(JSContext *cx, JSObject *obj)
2885 jsval v;
2887 JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2888 v = obj->fslots[JSSLOT_PRIVATE];
2889 if (!JSVAL_IS_INT(v))
2890 return NULL;
2891 return JSVAL_TO_PRIVATE(v);
2894 JS_PUBLIC_API(JSBool)
2895 JS_SetPrivate(JSContext *cx, JSObject *obj, void *data)
2897 JS_ASSERT(OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_HAS_PRIVATE);
2898 obj->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(data);
2899 return JS_TRUE;
2902 JS_PUBLIC_API(void *)
2903 JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp,
2904 jsval *argv)
2906 if (!JS_InstanceOf(cx, obj, clasp, argv))
2907 return NULL;
2908 return JS_GetPrivate(cx, obj);
2911 JS_PUBLIC_API(JSObject *)
2912 JS_GetPrototype(JSContext *cx, JSObject *obj)
2914 JSObject *proto;
2916 CHECK_REQUEST(cx);
2917 proto = OBJ_GET_PROTO(cx, obj);
2919 /* Beware ref to dead object (we may be called from obj's finalizer). */
2920 return proto && proto->map ? proto : NULL;
2923 JS_PUBLIC_API(JSBool)
2924 JS_SetPrototype(JSContext *cx, JSObject *obj, JSObject *proto)
2926 CHECK_REQUEST(cx);
2927 JS_ASSERT(obj != proto);
2928 #ifdef DEBUG
2930 * FIXME: bug 408416. The cycle-detection required for script-writeable
2931 * __proto__ lives in js_SetProtoOrParent over in jsobj.c, also known as
2932 * js_ObjectOps.setProto. This hook must detect cycles, to prevent scripts
2933 * from ilooping SpiderMonkey trivially. But the overhead of detecting
2934 * cycles is high enough, and the threat from JS-API-calling C++ code is
2935 * low enough, that it's not worth burdening the non-DEBUG callers. Same
2936 * goes for JS_SetParent, below.
2938 if (obj->map->ops->setProto)
2939 return obj->map->ops->setProto(cx, obj, JSSLOT_PROTO, proto);
2940 #else
2941 if (OBJ_IS_NATIVE(obj)) {
2942 JS_LOCK_OBJ(cx, obj);
2943 if (!js_GetMutableScope(cx, obj)) {
2944 JS_UNLOCK_OBJ(cx, obj);
2945 return JS_FALSE;
2947 LOCKED_OBJ_SET_PROTO(obj, proto);
2948 JS_UNLOCK_OBJ(cx, obj);
2949 return JS_TRUE;
2951 #endif
2952 OBJ_SET_PROTO(cx, obj, proto);
2953 return JS_TRUE;
2956 JS_PUBLIC_API(JSObject *)
2957 JS_GetParent(JSContext *cx, JSObject *obj)
2959 JSObject *parent;
2961 parent = OBJ_GET_PARENT(cx, obj);
2963 /* Beware ref to dead object (we may be called from obj's finalizer). */
2964 return parent && parent->map ? parent : NULL;
2967 JS_PUBLIC_API(JSBool)
2968 JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
2970 CHECK_REQUEST(cx);
2971 JS_ASSERT(obj != parent);
2972 #ifdef DEBUG
2973 /* FIXME: bug 408416, see JS_SetPrototype just above. */
2974 if (obj->map->ops->setParent)
2975 return obj->map->ops->setParent(cx, obj, JSSLOT_PARENT, parent);
2976 #endif
2977 OBJ_SET_PARENT(cx, obj, parent);
2978 return JS_TRUE;
2981 JS_PUBLIC_API(JSObject *)
2982 JS_GetConstructor(JSContext *cx, JSObject *proto)
2984 jsval cval;
2986 CHECK_REQUEST(cx);
2988 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
2990 if (!OBJ_GET_PROPERTY(cx, proto,
2991 ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
2992 &cval)) {
2993 return NULL;
2996 if (!VALUE_IS_FUNCTION(cx, cval)) {
2997 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
2998 OBJ_GET_CLASS(cx, proto)->name);
2999 return NULL;
3001 return JSVAL_TO_OBJECT(cval);
3004 JS_PUBLIC_API(JSBool)
3005 JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
3007 JS_ASSERT(JSID_IS_OBJECT(obj));
3008 *idp = OBJECT_TO_JSID(obj);
3009 return JS_TRUE;
3012 JS_PUBLIC_API(JSObject *)
3013 JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
3015 CHECK_REQUEST(cx);
3016 if (!clasp)
3017 clasp = &js_ObjectClass; /* default class is Object */
3018 return js_NewObject(cx, clasp, proto, parent, 0);
3021 JS_PUBLIC_API(JSObject *)
3022 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
3023 JSObject *parent)
3025 CHECK_REQUEST(cx);
3026 if (!clasp)
3027 clasp = &js_ObjectClass; /* default class is Object */
3028 return js_NewObjectWithGivenProto(cx, clasp, proto, parent, 0);
3031 JS_PUBLIC_API(JSBool)
3032 JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
3034 JSScope *scope;
3035 JSIdArray *ida;
3036 uint32 nslots, i;
3037 jsval v;
3039 if (!OBJ_IS_NATIVE(obj)) {
3040 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
3041 JSMSG_CANT_SEAL_OBJECT,
3042 OBJ_GET_CLASS(cx, obj)->name);
3043 return JS_FALSE;
3046 scope = OBJ_SCOPE(obj);
3048 #if defined JS_THREADSAFE && defined DEBUG
3049 /* Insist on scope being used exclusively by cx's thread. */
3050 if (scope->title.ownercx != cx) {
3051 JS_LOCK_OBJ(cx, obj);
3052 JS_ASSERT(OBJ_SCOPE(obj) == scope);
3053 JS_ASSERT(scope->title.ownercx == cx);
3054 JS_UNLOCK_SCOPE(cx, scope);
3056 #endif
3058 /* Nothing to do if obj's scope is already sealed. */
3059 if (SCOPE_IS_SEALED(scope))
3060 return JS_TRUE;
3062 /* XXX Enumerate lazy properties now, as they can't be added later. */
3063 ida = JS_Enumerate(cx, obj);
3064 if (!ida)
3065 return JS_FALSE;
3066 JS_DestroyIdArray(cx, ida);
3068 /* Ensure that obj has its own, mutable scope, and seal that scope. */
3069 JS_LOCK_OBJ(cx, obj);
3070 scope = js_GetMutableScope(cx, obj);
3071 if (scope) {
3072 SCOPE_SET_SEALED(scope);
3073 SCOPE_MAKE_UNIQUE_SHAPE(cx, scope);
3075 JS_UNLOCK_OBJ(cx, obj);
3076 if (!scope)
3077 return JS_FALSE;
3079 /* If we are not sealing an entire object graph, we're done. */
3080 if (!deep)
3081 return JS_TRUE;
3083 /* Walk slots in obj and if any value is a non-null object, seal it. */
3084 nslots = scope->map.freeslot;
3085 for (i = 0; i != nslots; ++i) {
3086 v = STOBJ_GET_SLOT(obj, i);
3087 if (JSVAL_IS_PRIMITIVE(v))
3088 continue;
3089 if (!JS_SealObject(cx, JSVAL_TO_OBJECT(v), deep))
3090 return JS_FALSE;
3092 return JS_TRUE;
3095 JS_PUBLIC_API(JSObject *)
3096 JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
3097 JSObject *parent)
3099 CHECK_REQUEST(cx);
3100 if (!clasp)
3101 clasp = &js_ObjectClass; /* default class is Object */
3102 return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
3105 JS_PUBLIC_API(JSObject *)
3106 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto,
3107 JSObject *parent, uintN argc, jsval *argv)
3109 CHECK_REQUEST(cx);
3110 if (!clasp)
3111 clasp = &js_ObjectClass; /* default class is Object */
3112 return js_ConstructObject(cx, clasp, proto, parent, argc, argv);
3115 static JSBool
3116 DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
3117 JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
3118 uintN flags, intN tinyid)
3120 jsid id;
3121 JSAtom *atom;
3123 if (attrs & JSPROP_INDEX) {
3124 id = INT_TO_JSID(JS_PTR_TO_INT32(name));
3125 atom = NULL;
3126 attrs &= ~JSPROP_INDEX;
3127 } else {
3128 atom = js_Atomize(cx, name, strlen(name), 0);
3129 if (!atom)
3130 return JS_FALSE;
3131 id = ATOM_TO_JSID(atom);
3133 if (flags != 0 && OBJ_IS_NATIVE(obj)) {
3134 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
3135 return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
3136 attrs, flags, tinyid, NULL);
3138 return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs,
3139 NULL);
3142 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
3144 static JSBool
3145 DefineUCProperty(JSContext *cx, JSObject *obj,
3146 const jschar *name, size_t namelen, jsval value,
3147 JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
3148 uintN flags, intN tinyid)
3150 JSAtom *atom;
3152 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3153 if (!atom)
3154 return JS_FALSE;
3155 if (flags != 0 && OBJ_IS_NATIVE(obj)) {
3156 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
3157 return js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
3158 getter, setter, attrs, flags, tinyid,
3159 NULL);
3161 return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), value,
3162 getter, setter, attrs, NULL);
3165 JS_PUBLIC_API(JSObject *)
3166 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
3167 JSObject *proto, uintN attrs)
3169 JSObject *nobj;
3171 CHECK_REQUEST(cx);
3172 if (!clasp)
3173 clasp = &js_ObjectClass; /* default class is Object */
3174 nobj = js_NewObject(cx, clasp, proto, obj, 0);
3175 if (!nobj)
3176 return NULL;
3177 if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs,
3178 0, 0)) {
3179 cx->weakRoots.newborn[GCX_OBJECT] = NULL;
3180 return NULL;
3182 return nobj;
3185 JS_PUBLIC_API(JSBool)
3186 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
3188 JSBool ok;
3189 jsval value;
3190 uintN attrs;
3192 CHECK_REQUEST(cx);
3193 for (ok = JS_TRUE; cds->name; cds++) {
3194 ok = js_NewNumberInRootedValue(cx, cds->dval, &value);
3195 if (!ok)
3196 break;
3197 attrs = cds->flags;
3198 if (!attrs)
3199 attrs = JSPROP_READONLY | JSPROP_PERMANENT;
3200 ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
3201 if (!ok)
3202 break;
3204 return ok;
3207 JS_PUBLIC_API(JSBool)
3208 JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
3210 JSBool ok;
3212 CHECK_REQUEST(cx);
3213 for (ok = JS_TRUE; ps->name; ps++) {
3214 ok = DefineProperty(cx, obj, ps->name, JSVAL_VOID,
3215 ps->getter, ps->setter, ps->flags,
3216 SPROP_HAS_SHORTID, ps->tinyid);
3217 if (!ok)
3218 break;
3220 return ok;
3223 JS_PUBLIC_API(JSBool)
3224 JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
3225 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3227 CHECK_REQUEST(cx);
3228 return DefineProperty(cx, obj, name, value, getter, setter, attrs, 0, 0);
3231 JS_PUBLIC_API(JSBool)
3232 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
3233 int8 tinyid, jsval value,
3234 JSPropertyOp getter, JSPropertyOp setter,
3235 uintN attrs)
3237 CHECK_REQUEST(cx);
3238 return DefineProperty(cx, obj, name, value, getter, setter, attrs,
3239 SPROP_HAS_SHORTID, tinyid);
3242 static JSBool
3243 LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
3244 JSObject **objp, JSProperty **propp)
3246 JSAutoResolveFlags rf(cx, flags);
3247 return OBJ_LOOKUP_PROPERTY(cx, obj, id, objp, propp);
3250 static JSBool
3251 LookupProperty(JSContext *cx, JSObject *obj, const char *name, uintN flags,
3252 JSObject **objp, JSProperty **propp)
3254 JSAtom *atom;
3256 atom = js_Atomize(cx, name, strlen(name), 0);
3257 if (!atom)
3258 return JS_FALSE;
3259 return LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), flags, objp, propp);
3262 static JSBool
3263 LookupUCProperty(JSContext *cx, JSObject *obj,
3264 const jschar *name, size_t namelen, uintN flags,
3265 JSObject **objp, JSProperty **propp)
3267 JSAtom *atom;
3269 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3270 if (!atom)
3271 return JS_FALSE;
3272 return LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), flags, objp, propp);
3275 JS_PUBLIC_API(JSBool)
3276 JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
3277 const char *alias)
3279 JSObject *obj2;
3280 JSProperty *prop;
3281 JSAtom *atom;
3282 JSBool ok;
3283 JSScopeProperty *sprop;
3285 CHECK_REQUEST(cx);
3286 if (!LookupProperty(cx, obj, name, JSRESOLVE_QUALIFIED, &obj2, &prop))
3287 return JS_FALSE;
3288 if (!prop) {
3289 js_ReportIsNotDefined(cx, name);
3290 return JS_FALSE;
3292 if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
3293 OBJ_DROP_PROPERTY(cx, obj2, prop);
3294 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3295 alias, name, OBJ_GET_CLASS(cx, obj2)->name);
3296 return JS_FALSE;
3298 atom = js_Atomize(cx, alias, strlen(alias), 0);
3299 if (!atom) {
3300 ok = JS_FALSE;
3301 } else {
3302 sprop = (JSScopeProperty *)prop;
3303 ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
3304 sprop->getter, sprop->setter, sprop->slot,
3305 sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
3306 sprop->shortid)
3307 != NULL);
3309 OBJ_DROP_PROPERTY(cx, obj, prop);
3310 return ok;
3313 static jsval
3314 LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop)
3316 JSScopeProperty *sprop;
3317 jsval rval;
3319 if (!prop) {
3320 /* XXX bad API: no way to tell "not defined" from "void value" */
3321 return JSVAL_VOID;
3323 if (OBJ_IS_NATIVE(obj2)) {
3324 /* Peek at the native property's slot value, without doing a Get. */
3325 sprop = (JSScopeProperty *)prop;
3326 rval = SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2))
3327 ? LOCKED_OBJ_GET_SLOT(obj2, sprop->slot)
3328 : JSVAL_TRUE;
3329 } else {
3330 /* XXX bad API: no way to return "defined but value unknown" */
3331 rval = JSVAL_TRUE;
3333 OBJ_DROP_PROPERTY(cx, obj2, prop);
3334 return rval;
3337 static JSBool
3338 GetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
3339 uintN *attrsp, JSBool *foundp,
3340 JSPropertyOp *getterp, JSPropertyOp *setterp)
3342 JSObject *obj2;
3343 JSProperty *prop;
3344 JSBool ok;
3346 if (!atom)
3347 return JS_FALSE;
3348 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED,
3349 &obj2, &prop)) {
3350 return JS_FALSE;
3353 if (!prop || obj != obj2) {
3354 *attrsp = 0;
3355 *foundp = JS_FALSE;
3356 if (getterp)
3357 *getterp = NULL;
3358 if (setterp)
3359 *setterp = NULL;
3360 if (prop)
3361 OBJ_DROP_PROPERTY(cx, obj2, prop);
3362 return JS_TRUE;
3365 *foundp = JS_TRUE;
3366 ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, attrsp);
3367 if (ok && OBJ_IS_NATIVE(obj)) {
3368 JSScopeProperty *sprop = (JSScopeProperty *) prop;
3370 if (getterp)
3371 *getterp = sprop->getter;
3372 if (setterp)
3373 *setterp = sprop->setter;
3375 OBJ_DROP_PROPERTY(cx, obj, prop);
3376 return ok;
3379 static JSBool
3380 SetPropertyAttributes(JSContext *cx, JSObject *obj, JSAtom *atom,
3381 uintN attrs, JSBool *foundp)
3383 JSObject *obj2;
3384 JSProperty *prop;
3385 JSBool ok;
3387 if (!atom)
3388 return JS_FALSE;
3389 if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED,
3390 &obj2, &prop)) {
3391 return JS_FALSE;
3393 if (!prop || obj != obj2) {
3394 *foundp = JS_FALSE;
3395 if (prop)
3396 OBJ_DROP_PROPERTY(cx, obj2, prop);
3397 return JS_TRUE;
3400 *foundp = JS_TRUE;
3401 ok = OBJ_SET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs);
3402 OBJ_DROP_PROPERTY(cx, obj, prop);
3403 return ok;
3406 JS_PUBLIC_API(JSBool)
3407 JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3408 uintN *attrsp, JSBool *foundp)
3410 CHECK_REQUEST(cx);
3411 return GetPropertyAttributes(cx, obj,
3412 js_Atomize(cx, name, strlen(name), 0),
3413 attrsp, foundp, NULL, NULL);
3416 JS_PUBLIC_API(JSBool)
3417 JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
3418 const char *name,
3419 uintN *attrsp, JSBool *foundp,
3420 JSPropertyOp *getterp,
3421 JSPropertyOp *setterp)
3423 CHECK_REQUEST(cx);
3424 return GetPropertyAttributes(cx, obj,
3425 js_Atomize(cx, name, strlen(name), 0),
3426 attrsp, foundp, getterp, setterp);
3429 JS_PUBLIC_API(JSBool)
3430 JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
3431 uintN attrs, JSBool *foundp)
3433 CHECK_REQUEST(cx);
3434 return SetPropertyAttributes(cx, obj,
3435 js_Atomize(cx, name, strlen(name), 0),
3436 attrs, foundp);
3439 static JSBool
3440 AlreadyHasOwnPropertyHelper(JSContext *cx, JSObject *obj, jsid id,
3441 JSBool *foundp)
3443 JSScope *scope;
3445 if (!OBJ_IS_NATIVE(obj)) {
3446 JSObject *obj2;
3447 JSProperty *prop;
3449 if (!LookupPropertyById(cx, obj, id,
3450 JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3451 &obj2, &prop)) {
3452 return JS_FALSE;
3454 *foundp = (obj == obj2);
3455 if (prop)
3456 OBJ_DROP_PROPERTY(cx, obj2, prop);
3457 return JS_TRUE;
3460 JS_LOCK_OBJ(cx, obj);
3461 scope = OBJ_SCOPE(obj);
3462 *foundp = (scope->object == obj && SCOPE_GET_PROPERTY(scope, id));
3463 JS_UNLOCK_SCOPE(cx, scope);
3464 return JS_TRUE;
3467 JS_PUBLIC_API(JSBool)
3468 JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name,
3469 JSBool *foundp)
3471 JSAtom *atom;
3473 CHECK_REQUEST(cx);
3474 atom = js_Atomize(cx, name, strlen(name), 0);
3475 if (!atom)
3476 return JS_FALSE;
3477 return AlreadyHasOwnPropertyHelper(cx, obj, ATOM_TO_JSID(atom), foundp);
3480 JS_PUBLIC_API(JSBool)
3481 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
3483 JSBool ok;
3484 JSObject *obj2;
3485 JSProperty *prop;
3487 CHECK_REQUEST(cx);
3488 ok = LookupProperty(cx, obj, name,
3489 JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3490 &obj2, &prop);
3491 if (ok) {
3492 *foundp = (prop != NULL);
3493 if (prop)
3494 OBJ_DROP_PROPERTY(cx, obj2, prop);
3496 return ok;
3499 JS_PUBLIC_API(JSBool)
3500 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3502 JSBool ok;
3503 JSObject *obj2;
3504 JSProperty *prop;
3506 CHECK_REQUEST(cx);
3507 ok = LookupProperty(cx, obj, name, JSRESOLVE_QUALIFIED, &obj2, &prop);
3508 if (ok)
3509 *vp = LookupResult(cx, obj, obj2, prop);
3510 return ok;
3513 JS_PUBLIC_API(JSBool)
3514 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name,
3515 uintN flags, jsval *vp)
3517 JSAtom *atom;
3518 JSObject *obj2;
3520 atom = js_Atomize(cx, name, strlen(name), 0);
3521 return atom &&
3522 JS_LookupPropertyByIdWithFlags(cx, obj, ATOM_TO_JSID(atom), flags,
3523 &obj2, vp);
3526 JS_PUBLIC_API(JSBool)
3527 JS_LookupPropertyByIdWithFlags(JSContext *cx, JSObject *obj, jsid id,
3528 uintN flags, JSObject **objp, jsval *vp)
3530 JSBool ok;
3531 JSProperty *prop;
3533 CHECK_REQUEST(cx);
3534 ok = OBJ_IS_NATIVE(obj)
3535 ? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0
3536 : OBJ_LOOKUP_PROPERTY(cx, obj, id, objp, &prop);
3537 if (ok)
3538 *vp = LookupResult(cx, obj, *objp, prop);
3539 return ok;
3542 JS_PUBLIC_API(JSBool)
3543 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3545 JSAtom *atom;
3547 CHECK_REQUEST(cx);
3548 atom = js_Atomize(cx, name, strlen(name), 0);
3549 if (!atom)
3550 return JS_FALSE;
3552 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3553 return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
3556 JS_PUBLIC_API(JSBool)
3557 JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
3558 jsval *vp)
3560 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3562 CHECK_REQUEST(cx);
3563 #if JS_HAS_XML_SUPPORT
3564 if (OBJECT_IS_XML(cx, obj)) {
3565 JSXMLObjectOps *ops;
3567 ops = (JSXMLObjectOps *) obj->map->ops;
3568 obj = ops->getMethod(cx, obj, id, vp);
3569 if (!obj)
3570 return JS_FALSE;
3571 } else
3572 #endif
3574 if (!OBJ_GET_PROPERTY(cx, obj, id, vp))
3575 return JS_FALSE;
3578 *objp = obj;
3579 return JS_TRUE;
3582 JS_PUBLIC_API(JSBool)
3583 JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
3584 jsval *vp)
3586 JSAtom *atom;
3588 atom = js_Atomize(cx, name, strlen(name), 0);
3589 if (!atom)
3590 return JS_FALSE;
3591 return JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), objp, vp);
3594 JS_PUBLIC_API(JSBool)
3595 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
3597 JSAtom *atom;
3599 CHECK_REQUEST(cx);
3600 atom = js_Atomize(cx, name, strlen(name), 0);
3601 if (!atom)
3602 return JS_FALSE;
3604 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
3605 return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
3608 JS_PUBLIC_API(JSBool)
3609 JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
3611 jsval junk;
3613 CHECK_REQUEST(cx);
3614 return JS_DeleteProperty2(cx, obj, name, &junk);
3617 JS_PUBLIC_API(JSBool)
3618 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name,
3619 jsval *rval)
3621 JSAtom *atom;
3623 CHECK_REQUEST(cx);
3624 atom = js_Atomize(cx, name, strlen(name), 0);
3625 if (!atom)
3626 return JS_FALSE;
3628 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3629 return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
3632 JS_PUBLIC_API(JSBool)
3633 JS_DefineUCProperty(JSContext *cx, JSObject *obj,
3634 const jschar *name, size_t namelen, jsval value,
3635 JSPropertyOp getter, JSPropertyOp setter,
3636 uintN attrs)
3638 CHECK_REQUEST(cx);
3639 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
3640 attrs, 0, 0);
3643 JS_PUBLIC_API(JSBool)
3644 JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj,
3645 const jschar *name, size_t namelen,
3646 uintN *attrsp, JSBool *foundp)
3648 CHECK_REQUEST(cx);
3649 return GetPropertyAttributes(cx, obj,
3650 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
3651 attrsp, foundp, NULL, NULL);
3654 JS_PUBLIC_API(JSBool)
3655 JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
3656 const jschar *name, size_t namelen,
3657 uintN *attrsp, JSBool *foundp,
3658 JSPropertyOp *getterp,
3659 JSPropertyOp *setterp)
3661 CHECK_REQUEST(cx);
3662 return GetPropertyAttributes(cx, obj,
3663 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
3664 attrsp, foundp, getterp, setterp);
3667 JS_PUBLIC_API(JSBool)
3668 JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj,
3669 const jschar *name, size_t namelen,
3670 uintN attrs, JSBool *foundp)
3672 CHECK_REQUEST(cx);
3673 return SetPropertyAttributes(cx, obj,
3674 js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0),
3675 attrs, foundp);
3678 JS_PUBLIC_API(JSBool)
3679 JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
3680 const jschar *name, size_t namelen,
3681 int8 tinyid, jsval value,
3682 JSPropertyOp getter, JSPropertyOp setter,
3683 uintN attrs)
3685 CHECK_REQUEST(cx);
3686 return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
3687 attrs, SPROP_HAS_SHORTID, tinyid);
3690 JS_PUBLIC_API(JSBool)
3691 JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj,
3692 const jschar *name, size_t namelen,
3693 JSBool *foundp)
3695 JSAtom *atom;
3697 CHECK_REQUEST(cx);
3698 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3699 if (!atom)
3700 return JS_FALSE;
3701 return AlreadyHasOwnPropertyHelper(cx, obj, ATOM_TO_JSID(atom), foundp);
3704 JS_PUBLIC_API(JSBool)
3705 JS_HasUCProperty(JSContext *cx, JSObject *obj,
3706 const jschar *name, size_t namelen,
3707 JSBool *vp)
3709 JSBool ok;
3710 JSObject *obj2;
3711 JSProperty *prop;
3713 CHECK_REQUEST(cx);
3714 ok = LookupUCProperty(cx, obj, name, namelen,
3715 JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3716 &obj2, &prop);
3717 if (ok) {
3718 *vp = (prop != NULL);
3719 if (prop)
3720 OBJ_DROP_PROPERTY(cx, obj2, prop);
3722 return ok;
3725 JS_PUBLIC_API(JSBool)
3726 JS_LookupUCProperty(JSContext *cx, JSObject *obj,
3727 const jschar *name, size_t namelen,
3728 jsval *vp)
3730 JSBool ok;
3731 JSObject *obj2;
3732 JSProperty *prop;
3734 CHECK_REQUEST(cx);
3735 ok = LookupUCProperty(cx, obj, name, namelen, JSRESOLVE_QUALIFIED,
3736 &obj2, &prop);
3737 if (ok)
3738 *vp = LookupResult(cx, obj, obj2, prop);
3739 return ok;
3742 JS_PUBLIC_API(JSBool)
3743 JS_GetUCProperty(JSContext *cx, JSObject *obj,
3744 const jschar *name, size_t namelen,
3745 jsval *vp)
3747 JSAtom *atom;
3749 CHECK_REQUEST(cx);
3750 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3751 if (!atom)
3752 return JS_FALSE;
3754 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3755 return OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
3758 JS_PUBLIC_API(JSBool)
3759 JS_SetUCProperty(JSContext *cx, JSObject *obj,
3760 const jschar *name, size_t namelen,
3761 jsval *vp)
3763 JSAtom *atom;
3765 CHECK_REQUEST(cx);
3766 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3767 if (!atom)
3768 return JS_FALSE;
3770 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
3771 return OBJ_SET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp);
3774 JS_PUBLIC_API(JSBool)
3775 JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
3776 const jschar *name, size_t namelen,
3777 jsval *rval)
3779 JSAtom *atom;
3781 CHECK_REQUEST(cx);
3782 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
3783 if (!atom)
3784 return JS_FALSE;
3786 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3787 return OBJ_DELETE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), rval);
3790 JS_PUBLIC_API(JSObject *)
3791 JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
3793 CHECK_REQUEST(cx);
3794 /* NB: jsuint cast does ToUint32. */
3795 return js_NewArrayObject(cx, (jsuint)length, vector);
3798 JS_PUBLIC_API(JSBool)
3799 JS_IsArrayObject(JSContext *cx, JSObject *obj)
3801 return OBJ_IS_ARRAY(cx, obj);
3804 JS_PUBLIC_API(JSBool)
3805 JS_GetArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
3807 CHECK_REQUEST(cx);
3808 return js_GetLengthProperty(cx, obj, lengthp);
3811 JS_PUBLIC_API(JSBool)
3812 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length)
3814 CHECK_REQUEST(cx);
3815 return js_SetLengthProperty(cx, obj, length);
3818 JS_PUBLIC_API(JSBool)
3819 JS_HasArrayLength(JSContext *cx, JSObject *obj, jsuint *lengthp)
3821 CHECK_REQUEST(cx);
3822 return js_HasLengthProperty(cx, obj, lengthp);
3825 JS_PUBLIC_API(JSBool)
3826 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
3827 JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
3829 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
3831 CHECK_REQUEST(cx);
3832 return OBJ_DEFINE_PROPERTY(cx, obj, INT_TO_JSID(index), value,
3833 getter, setter, attrs, NULL);
3836 JS_PUBLIC_API(JSBool)
3837 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
3839 JSObject *obj2;
3840 JSProperty *prop;
3841 JSScopeProperty *sprop;
3842 JSBool ok;
3844 CHECK_REQUEST(cx);
3845 if (!LookupProperty(cx, obj, name, JSRESOLVE_QUALIFIED, &obj2, &prop))
3846 return JS_FALSE;
3847 if (!prop) {
3848 js_ReportIsNotDefined(cx, name);
3849 return JS_FALSE;
3851 if (obj2 != obj || !OBJ_IS_NATIVE(obj)) {
3852 char numBuf[12];
3853 OBJ_DROP_PROPERTY(cx, obj2, prop);
3854 JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
3855 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
3856 numBuf, name, OBJ_GET_CLASS(cx, obj2)->name);
3857 return JS_FALSE;
3859 sprop = (JSScopeProperty *)prop;
3860 ok = (js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
3861 sprop->getter, sprop->setter, sprop->slot,
3862 sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
3863 sprop->shortid)
3864 != NULL);
3865 OBJ_DROP_PROPERTY(cx, obj, prop);
3866 return ok;
3869 JS_PUBLIC_API(JSBool)
3870 JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index,
3871 JSBool *foundp)
3873 return AlreadyHasOwnPropertyHelper(cx, obj, INT_TO_JSID(index), foundp);
3876 JS_PUBLIC_API(JSBool)
3877 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
3879 JSBool ok;
3880 JSObject *obj2;
3881 JSProperty *prop;
3883 CHECK_REQUEST(cx);
3884 ok = LookupPropertyById(cx, obj, INT_TO_JSID(index),
3885 JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
3886 &obj2, &prop);
3887 if (ok) {
3888 *foundp = (prop != NULL);
3889 if (prop)
3890 OBJ_DROP_PROPERTY(cx, obj2, prop);
3892 return ok;
3895 JS_PUBLIC_API(JSBool)
3896 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3898 JSBool ok;
3899 JSObject *obj2;
3900 JSProperty *prop;
3902 CHECK_REQUEST(cx);
3903 ok = LookupPropertyById(cx, obj, INT_TO_JSID(index), JSRESOLVE_QUALIFIED,
3904 &obj2, &prop);
3905 if (ok)
3906 *vp = LookupResult(cx, obj, obj2, prop);
3907 return ok;
3910 JS_PUBLIC_API(JSBool)
3911 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3913 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3915 CHECK_REQUEST(cx);
3916 return OBJ_GET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
3919 JS_PUBLIC_API(JSBool)
3920 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
3922 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
3924 CHECK_REQUEST(cx);
3925 return OBJ_SET_PROPERTY(cx, obj, INT_TO_JSID(index), vp);
3928 JS_PUBLIC_API(JSBool)
3929 JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
3931 jsval junk;
3933 return JS_DeleteElement2(cx, obj, index, &junk);
3936 JS_PUBLIC_API(JSBool)
3937 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
3939 JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
3941 CHECK_REQUEST(cx);
3942 return OBJ_DELETE_PROPERTY(cx, obj, INT_TO_JSID(index), rval);
3945 JS_PUBLIC_API(void)
3946 JS_ClearScope(JSContext *cx, JSObject *obj)
3948 CHECK_REQUEST(cx);
3950 if (obj->map->ops->clear)
3951 obj->map->ops->clear(cx, obj);
3953 /* Clear cached class objects on the global object. */
3954 if (OBJ_GET_CLASS(cx, obj)->flags & JSCLASS_IS_GLOBAL) {
3955 int key;
3957 for (key = JSProto_Null; key < JSProto_LIMIT; key++)
3958 JS_SetReservedSlot(cx, obj, key, JSVAL_VOID);
3962 JS_PUBLIC_API(JSIdArray *)
3963 JS_Enumerate(JSContext *cx, JSObject *obj)
3965 jsint i, n;
3966 jsval iter_state, num_properties;
3967 jsid id;
3968 JSIdArray *ida;
3969 jsval *vector;
3971 CHECK_REQUEST(cx);
3973 ida = NULL;
3974 iter_state = JSVAL_NULL;
3976 /* Get the number of properties to enumerate. */
3977 if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, &num_properties))
3978 goto error;
3979 if (!JSVAL_IS_INT(num_properties)) {
3980 JS_ASSERT(0);
3981 goto error;
3984 /* Grow as needed if we don't know the exact amount ahead of time. */
3985 n = JSVAL_TO_INT(num_properties);
3986 if (n <= 0)
3987 n = 8;
3989 /* Create an array of jsids large enough to hold all the properties */
3990 ida = NewIdArray(cx, n);
3991 if (!ida)
3992 goto error;
3994 i = 0;
3995 vector = &ida->vector[0];
3996 for (;;) {
3997 if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &id))
3998 goto error;
4000 /* No more jsid's to enumerate ? */
4001 if (iter_state == JSVAL_NULL)
4002 break;
4004 if (i == ida->length) {
4005 ida = SetIdArrayLength(cx, ida, ida->length * 2);
4006 if (!ida)
4007 goto error;
4008 vector = &ida->vector[0];
4010 vector[i++] = id;
4012 return SetIdArrayLength(cx, ida, i);
4014 error:
4015 if (iter_state != JSVAL_NULL)
4016 OBJ_ENUMERATE(cx, obj, JSENUMERATE_DESTROY, &iter_state, 0);
4017 if (ida)
4018 JS_DestroyIdArray(cx, ida);
4019 return NULL;
4023 * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
4024 * prop_iterator_class somehow...
4025 * + preserve the OBJ_ENUMERATE API while optimizing the native object case
4026 * + native case here uses a JSScopeProperty *, but that iterates in reverse!
4027 * + so we make non-native match, by reverse-iterating after JS_Enumerating
4029 #define JSSLOT_ITER_INDEX (JSSLOT_PRIVATE + 1)
4031 #if JSSLOT_ITER_INDEX >= JS_INITIAL_NSLOTS
4032 # error "JSSLOT_ITER_INDEX botch!"
4033 #endif
4035 static void
4036 prop_iter_finalize(JSContext *cx, JSObject *obj)
4038 jsval v;
4039 jsint i;
4040 JSIdArray *ida;
4042 v = obj->fslots[JSSLOT_ITER_INDEX];
4043 if (JSVAL_IS_VOID(v))
4044 return;
4046 i = JSVAL_TO_INT(v);
4047 if (i >= 0) {
4048 /* Non-native case: destroy the ida enumerated when obj was created. */
4049 ida = (JSIdArray *) JS_GetPrivate(cx, obj);
4050 if (ida)
4051 JS_DestroyIdArray(cx, ida);
4055 static void
4056 prop_iter_trace(JSTracer *trc, JSObject *obj)
4058 jsval v;
4059 jsint i, n;
4060 JSScopeProperty *sprop;
4061 JSIdArray *ida;
4062 jsid id;
4064 v = obj->fslots[JSSLOT_PRIVATE];
4065 JS_ASSERT(!JSVAL_IS_VOID(v));
4067 i = JSVAL_TO_INT(obj->fslots[JSSLOT_ITER_INDEX]);
4068 if (i < 0) {
4069 /* Native case: just mark the next property to visit. */
4070 sprop = (JSScopeProperty *) JSVAL_TO_PRIVATE(v);
4071 if (sprop)
4072 TRACE_SCOPE_PROPERTY(trc, sprop);
4073 } else {
4074 /* Non-native case: mark each id in the JSIdArray private. */
4075 ida = (JSIdArray *) JSVAL_TO_PRIVATE(v);
4076 for (i = 0, n = ida->length; i < n; i++) {
4077 id = ida->vector[i];
4078 TRACE_ID(trc, id);
4083 static JSClass prop_iter_class = {
4084 "PropertyIterator",
4085 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
4086 JSCLASS_MARK_IS_TRACE,
4087 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
4088 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, prop_iter_finalize,
4089 NULL, NULL, NULL, NULL,
4090 NULL, NULL, JS_CLASS_TRACE(prop_iter_trace), NULL
4093 JS_PUBLIC_API(JSObject *)
4094 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
4096 JSObject *iterobj;
4097 JSScope *scope;
4098 void *pdata;
4099 jsint index;
4100 JSIdArray *ida;
4102 CHECK_REQUEST(cx);
4103 iterobj = js_NewObject(cx, &prop_iter_class, NULL, obj, 0);
4104 if (!iterobj)
4105 return NULL;
4107 if (OBJ_IS_NATIVE(obj)) {
4108 /* Native case: start with the last property in obj's own scope. */
4109 scope = OBJ_SCOPE(obj);
4110 pdata = (scope->object == obj) ? scope->lastProp : NULL;
4111 index = -1;
4112 } else {
4113 JSTempValueRooter tvr;
4116 * Non-native case: enumerate a JSIdArray and keep it via private.
4118 * Note: we have to make sure that we root obj around the call to
4119 * JS_Enumerate to protect against multiple allocations under it.
4121 JS_PUSH_SINGLE_TEMP_ROOT(cx, OBJECT_TO_JSVAL(iterobj), &tvr);
4122 ida = JS_Enumerate(cx, obj);
4123 JS_POP_TEMP_ROOT(cx, &tvr);
4124 if (!ida)
4125 goto bad;
4126 pdata = ida;
4127 index = ida->length;
4130 /* iterobj can not escape to other threads here. */
4131 STOBJ_SET_SLOT(iterobj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(pdata));
4132 STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(index));
4133 return iterobj;
4135 bad:
4136 cx->weakRoots.newborn[GCX_OBJECT] = NULL;
4137 return NULL;
4140 JS_PUBLIC_API(JSBool)
4141 JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
4143 jsint i;
4144 JSObject *obj;
4145 JSScope *scope;
4146 JSScopeProperty *sprop;
4147 JSIdArray *ida;
4149 CHECK_REQUEST(cx);
4150 i = JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_INDEX));
4151 if (i < 0) {
4152 /* Native case: private data is a property tree node pointer. */
4153 obj = OBJ_GET_PARENT(cx, iterobj);
4154 JS_ASSERT(OBJ_IS_NATIVE(obj));
4155 scope = OBJ_SCOPE(obj);
4156 JS_ASSERT(scope->object == obj);
4157 sprop = (JSScopeProperty *) JS_GetPrivate(cx, iterobj);
4160 * If the next property mapped by scope in the property tree ancestor
4161 * line is not enumerable, or it's an alias, or one or more properties
4162 * were deleted from the "middle" of the scope-mapped ancestor line
4163 * and the next property was among those deleted, skip it and keep on
4164 * trying to find an enumerable property that is still in scope.
4166 while (sprop &&
4167 (!(sprop->attrs & JSPROP_ENUMERATE) ||
4168 (sprop->flags & SPROP_IS_ALIAS) ||
4169 (SCOPE_HAD_MIDDLE_DELETE(scope) &&
4170 !SCOPE_HAS_PROPERTY(scope, sprop)))) {
4171 sprop = sprop->parent;
4174 if (!sprop) {
4175 *idp = JSVAL_VOID;
4176 } else {
4177 if (!JS_SetPrivate(cx, iterobj, sprop->parent))
4178 return JS_FALSE;
4179 *idp = sprop->id;
4181 } else {
4182 /* Non-native case: use the ida enumerated when iterobj was created. */
4183 ida = (JSIdArray *) JS_GetPrivate(cx, iterobj);
4184 JS_ASSERT(i <= ida->length);
4185 if (i == 0) {
4186 *idp = JSVAL_VOID;
4187 } else {
4188 *idp = ida->vector[--i];
4189 STOBJ_SET_SLOT(iterobj, JSSLOT_ITER_INDEX, INT_TO_JSVAL(i));
4192 return JS_TRUE;
4195 JS_PUBLIC_API(JSBool)
4196 JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
4197 jsval *vp, uintN *attrsp)
4199 CHECK_REQUEST(cx);
4200 return OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, attrsp);
4203 static JSBool
4204 ReservedSlotIndexOK(JSContext *cx, JSObject *obj, JSClass *clasp,
4205 uint32 index, uint32 limit)
4207 /* Check the computed, possibly per-instance, upper bound. */
4208 if (clasp->reserveSlots)
4209 JS_LOCK_OBJ_VOID(cx, obj, limit += clasp->reserveSlots(cx, obj));
4210 if (index >= limit) {
4211 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
4212 JSMSG_RESERVED_SLOT_RANGE);
4213 return JS_FALSE;
4215 return JS_TRUE;
4218 JS_PUBLIC_API(JSBool)
4219 JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
4221 JSClass *clasp;
4222 uint32 limit, slot;
4224 CHECK_REQUEST(cx);
4225 clasp = OBJ_GET_CLASS(cx, obj);
4226 limit = JSCLASS_RESERVED_SLOTS(clasp);
4227 if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
4228 return JS_FALSE;
4229 slot = JSSLOT_START(clasp) + index;
4230 *vp = OBJ_GET_REQUIRED_SLOT(cx, obj, slot);
4231 return JS_TRUE;
4234 JS_PUBLIC_API(JSBool)
4235 JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
4237 JSClass *clasp;
4238 uint32 limit, slot;
4240 CHECK_REQUEST(cx);
4241 clasp = OBJ_GET_CLASS(cx, obj);
4242 limit = JSCLASS_RESERVED_SLOTS(clasp);
4243 if (index >= limit && !ReservedSlotIndexOK(cx, obj, clasp, index, limit))
4244 return JS_FALSE;
4245 slot = JSSLOT_START(clasp) + index;
4246 return OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v);
4249 #ifdef JS_THREADSAFE
4250 JS_PUBLIC_API(jsrefcount)
4251 JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
4253 return JS_ATOMIC_INCREMENT(&principals->refcount);
4256 JS_PUBLIC_API(jsrefcount)
4257 JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
4259 jsrefcount rc = JS_ATOMIC_DECREMENT(&principals->refcount);
4260 if (rc == 0)
4261 principals->destroy(cx, principals);
4262 return rc;
4264 #endif
4266 JS_PUBLIC_API(JSSecurityCallbacks *)
4267 JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks)
4269 JSSecurityCallbacks *oldcallbacks;
4271 oldcallbacks = rt->securityCallbacks;
4272 rt->securityCallbacks = callbacks;
4273 return oldcallbacks;
4276 JS_PUBLIC_API(JSSecurityCallbacks *)
4277 JS_GetRuntimeSecurityCallbacks(JSRuntime *rt)
4279 return rt->securityCallbacks;
4282 JS_PUBLIC_API(JSSecurityCallbacks *)
4283 JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks)
4285 JSSecurityCallbacks *oldcallbacks;
4287 oldcallbacks = cx->securityCallbacks;
4288 cx->securityCallbacks = callbacks;
4289 return oldcallbacks;
4292 JS_PUBLIC_API(JSSecurityCallbacks *)
4293 JS_GetSecurityCallbacks(JSContext *cx)
4295 return cx->securityCallbacks
4296 ? cx->securityCallbacks
4297 : cx->runtime->securityCallbacks;
4300 JS_PUBLIC_API(JSFunction *)
4301 JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
4302 JSObject *parent, const char *name)
4304 JSAtom *atom;
4306 CHECK_REQUEST(cx);
4308 if (!name) {
4309 atom = NULL;
4310 } else {
4311 atom = js_Atomize(cx, name, strlen(name), 0);
4312 if (!atom)
4313 return NULL;
4315 return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom);
4318 JS_PUBLIC_API(JSObject *)
4319 JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
4321 CHECK_REQUEST(cx);
4322 if (OBJ_GET_CLASS(cx, funobj) != &js_FunctionClass) {
4323 /* Indicate we cannot clone this object. */
4324 return funobj;
4326 return js_CloneFunctionObject(cx, GET_FUNCTION_PRIVATE(cx, funobj), parent);
4329 JS_PUBLIC_API(JSObject *)
4330 JS_GetFunctionObject(JSFunction *fun)
4332 return FUN_OBJECT(fun);
4335 JS_PUBLIC_API(const char *)
4336 JS_GetFunctionName(JSFunction *fun)
4338 return fun->atom
4339 ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom))
4340 : js_anonymous_str;
4343 JS_PUBLIC_API(JSString *)
4344 JS_GetFunctionId(JSFunction *fun)
4346 return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
4349 JS_PUBLIC_API(uintN)
4350 JS_GetFunctionFlags(JSFunction *fun)
4352 #ifdef MOZILLA_1_8_BRANCH
4353 uintN flags = fun->flags;
4355 return JSFUN_DISJOINT_FLAGS(flags) |
4356 (JSFUN_GETTER_TEST(flags) ? JSFUN_GETTER : 0) |
4357 (JSFUN_SETTER_TEST(flags) ? JSFUN_SETTER : 0) |
4358 (JSFUN_BOUND_METHOD_TEST(flags) ? JSFUN_BOUND_METHOD : 0) |
4359 (JSFUN_HEAVYWEIGHT_TEST(flags) ? JSFUN_HEAVYWEIGHT : 0);
4360 #else
4361 return fun->flags;
4362 #endif
4365 JS_PUBLIC_API(uint16)
4366 JS_GetFunctionArity(JSFunction *fun)
4368 return fun->nargs;
4371 JS_PUBLIC_API(JSBool)
4372 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
4374 return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass;
4377 JS_BEGIN_EXTERN_C
4378 static JSBool
4379 js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, jsval *vp)
4381 jsval fsv;
4382 JSFunctionSpec *fs;
4383 JSObject *tmp;
4384 JSFastNative native;
4386 if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(*vp), 0, &fsv))
4387 return JS_FALSE;
4388 fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv);
4389 JS_ASSERT((~fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) == 0);
4392 * We know that vp[2] is valid because JS_DefineFunctions, which is our
4393 * only (indirect) referrer, defined us as requiring at least one argument
4394 * (notice how it passes fs->nargs + 1 as the next-to-last argument to
4395 * JS_DefineFunction).
4397 if (JSVAL_IS_PRIMITIVE(vp[2])) {
4399 * Make sure that this is an object or null, as required by the generic
4400 * functions.
4402 if (!js_ValueToObject(cx, vp[2], &tmp))
4403 return JS_FALSE;
4404 vp[2] = OBJECT_TO_JSVAL(tmp);
4408 * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
4409 * which is almost always the class constructor object, e.g. Array. Then
4410 * call the corresponding prototype native method with our first argument
4411 * passed as |this|.
4413 memmove(vp + 1, vp + 2, argc * sizeof(jsval));
4416 * Follow Function.prototype.apply and .call by using the global object as
4417 * the 'this' param if no args.
4419 if (!js_ComputeThis(cx, JS_FALSE, vp + 2))
4420 return JS_FALSE;
4422 * Protect against argc underflowing. By calling js_ComputeThis, we made
4423 * it as if the static was called with one parameter, the explicit |this|
4424 * object.
4426 if (argc != 0)
4427 --argc;
4429 native =
4430 #ifdef JS_TRACER
4431 (fs->flags & JSFUN_TRACEABLE)
4432 ? ((JSTraceableNative *) fs->call)->native
4434 #endif
4435 (JSFastNative) fs->call;
4436 return native(cx, argc, vp);
4439 static JSBool
4440 js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj,
4441 uintN argc, jsval *argv, jsval *rval)
4443 jsval fsv;
4444 JSFunctionSpec *fs;
4445 JSObject *tmp;
4447 if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &fsv))
4448 return JS_FALSE;
4449 fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv);
4450 JS_ASSERT((fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) ==
4451 JSFUN_GENERIC_NATIVE);
4454 * We know that argv[0] is valid because JS_DefineFunctions, which is our
4455 * only (indirect) referrer, defined us as requiring at least one argument
4456 * (notice how it passes fs->nargs + 1 as the next-to-last argument to
4457 * JS_DefineFunction).
4459 if (JSVAL_IS_PRIMITIVE(argv[0])) {
4461 * Make sure that this is an object or null, as required by the generic
4462 * functions.
4464 if (!js_ValueToObject(cx, argv[0], &tmp))
4465 return JS_FALSE;
4466 argv[0] = OBJECT_TO_JSVAL(tmp);
4470 * Copy all actual (argc) arguments down over our |this| parameter,
4471 * argv[-1], which is almost always the class constructor object, e.g.
4472 * Array. Then call the corresponding prototype native method with our
4473 * first argument passed as |this|.
4475 memmove(argv - 1, argv, argc * sizeof(jsval));
4478 * Follow Function.prototype.apply and .call by using the global object as
4479 * the 'this' param if no args.
4481 JS_ASSERT(cx->fp->argv == argv);
4482 if (!js_ComputeThis(cx, JS_TRUE, argv))
4483 return JS_FALSE;
4484 cx->fp->thisp = JSVAL_TO_OBJECT(argv[-1]);
4487 * Protect against argc underflowing. By calling js_ComputeThis, we made
4488 * it as if the static was called with one parameter, the explicit |this|
4489 * object.
4491 if (argc != 0)
4492 --argc;
4494 return fs->call(cx, JSVAL_TO_OBJECT(argv[-1]), argc, argv, rval);
4496 JS_END_EXTERN_C
4498 JS_PUBLIC_API(JSBool)
4499 JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
4501 uintN flags;
4502 JSObject *ctor;
4503 JSFunction *fun;
4505 CHECK_REQUEST(cx);
4506 ctor = NULL;
4507 for (; fs->name; fs++) {
4508 flags = fs->flags;
4511 * Define a generic arity N+1 static method for the arity N prototype
4512 * method if flags contains JSFUN_GENERIC_NATIVE.
4514 if (flags & JSFUN_GENERIC_NATIVE) {
4515 if (!ctor) {
4516 ctor = JS_GetConstructor(cx, obj);
4517 if (!ctor)
4518 return JS_FALSE;
4521 flags &= ~JSFUN_GENERIC_NATIVE;
4522 fun = JS_DefineFunction(cx, ctor, fs->name,
4523 (flags & JSFUN_FAST_NATIVE)
4524 ? (JSNative)
4525 js_generic_fast_native_method_dispatcher
4526 : js_generic_native_method_dispatcher,
4527 fs->nargs + 1,
4528 flags & ~JSFUN_TRACEABLE);
4529 if (!fun)
4530 return JS_FALSE;
4531 fun->u.n.extra = (uint16)fs->extra;
4534 * As jsapi.h notes, fs must point to storage that lives as long
4535 * as fun->object lives.
4537 if (!JS_SetReservedSlot(cx, FUN_OBJECT(fun), 0, PRIVATE_TO_JSVAL(fs)))
4538 return JS_FALSE;
4541 JS_ASSERT(!(flags & JSFUN_FAST_NATIVE) ||
4542 (uint16)(fs->extra >> 16) <= fs->nargs);
4543 fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
4544 if (!fun)
4545 return JS_FALSE;
4546 fun->u.n.extra = (uint16)fs->extra;
4548 return JS_TRUE;
4551 JS_PUBLIC_API(JSFunction *)
4552 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
4553 uintN nargs, uintN attrs)
4555 JSAtom *atom;
4557 CHECK_REQUEST(cx);
4558 atom = js_Atomize(cx, name, strlen(name), 0);
4559 if (!atom)
4560 return NULL;
4561 return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
4564 JS_PUBLIC_API(JSFunction *)
4565 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
4566 const jschar *name, size_t namelen, JSNative call,
4567 uintN nargs, uintN attrs)
4569 JSAtom *atom;
4571 atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
4572 if (!atom)
4573 return NULL;
4574 return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
4577 JS_PUBLIC_API(JSScript *)
4578 JS_CompileScript(JSContext *cx, JSObject *obj,
4579 const char *bytes, size_t length,
4580 const char *filename, uintN lineno)
4582 jschar *chars;
4583 JSScript *script;
4585 CHECK_REQUEST(cx);
4586 chars = js_InflateString(cx, bytes, &length);
4587 if (!chars)
4588 return NULL;
4589 script = JS_CompileUCScript(cx, obj, chars, length, filename, lineno);
4590 JS_free(cx, chars);
4591 return script;
4594 JS_PUBLIC_API(JSScript *)
4595 JS_CompileScriptForPrincipals(JSContext *cx, JSObject *obj,
4596 JSPrincipals *principals,
4597 const char *bytes, size_t length,
4598 const char *filename, uintN lineno)
4600 jschar *chars;
4601 JSScript *script;
4603 CHECK_REQUEST(cx);
4604 chars = js_InflateString(cx, bytes, &length);
4605 if (!chars)
4606 return NULL;
4607 script = JS_CompileUCScriptForPrincipals(cx, obj, principals,
4608 chars, length, filename, lineno);
4609 JS_free(cx, chars);
4610 return script;
4613 JS_PUBLIC_API(JSScript *)
4614 JS_CompileUCScript(JSContext *cx, JSObject *obj,
4615 const jschar *chars, size_t length,
4616 const char *filename, uintN lineno)
4618 CHECK_REQUEST(cx);
4619 return JS_CompileUCScriptForPrincipals(cx, obj, NULL, chars, length,
4620 filename, lineno);
4623 #define LAST_FRAME_EXCEPTION_CHECK(cx,result) \
4624 JS_BEGIN_MACRO \
4625 if (!(result) && !((cx)->options & JSOPTION_DONT_REPORT_UNCAUGHT)) \
4626 js_ReportUncaughtException(cx); \
4627 JS_END_MACRO
4629 #define LAST_FRAME_CHECKS(cx,result) \
4630 JS_BEGIN_MACRO \
4631 if (!(cx)->fp) { \
4632 (cx)->weakRoots.lastInternalResult = JSVAL_NULL; \
4633 LAST_FRAME_EXCEPTION_CHECK(cx, result); \
4635 JS_END_MACRO
4637 #define JS_OPTIONS_TO_TCFLAGS(cx) \
4638 ((((cx)->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) | \
4639 (((cx)->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0))
4641 JS_PUBLIC_API(JSScript *)
4642 JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
4643 JSPrincipals *principals,
4644 const jschar *chars, size_t length,
4645 const char *filename, uintN lineno)
4647 uint32 tcflags;
4648 JSScript *script;
4650 CHECK_REQUEST(cx);
4651 tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
4652 script = js_CompileScript(cx, obj, NULL, principals, tcflags,
4653 chars, length, NULL, filename, lineno);
4654 LAST_FRAME_CHECKS(cx, script);
4655 return script;
4658 JS_PUBLIC_API(JSBool)
4659 JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj,
4660 const char *bytes, size_t length)
4662 jschar *chars;
4663 JSBool result;
4664 JSExceptionState *exnState;
4665 JSParseContext pc;
4666 JSErrorReporter older;
4668 CHECK_REQUEST(cx);
4669 chars = js_InflateString(cx, bytes, &length);
4670 if (!chars)
4671 return JS_TRUE;
4674 * Return true on any out-of-memory error, so our caller doesn't try to
4675 * collect more buffered source.
4677 result = JS_TRUE;
4678 exnState = JS_SaveExceptionState(cx);
4679 if (js_InitParseContext(cx, &pc, NULL, NULL, chars, length, NULL, NULL,
4680 1)) {
4681 older = JS_SetErrorReporter(cx, NULL);
4682 if (!js_ParseScript(cx, obj, &pc) &&
4683 (pc.tokenStream.flags & TSF_UNEXPECTED_EOF)) {
4685 * We ran into an error. If it was because we ran out of source,
4686 * we return false, so our caller will know to try to collect more
4687 * buffered source.
4689 result = JS_FALSE;
4691 JS_SetErrorReporter(cx, older);
4692 js_FinishParseContext(cx, &pc);
4694 JS_free(cx, chars);
4695 JS_RestoreExceptionState(cx, exnState);
4696 return result;
4699 JS_PUBLIC_API(JSScript *)
4700 JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
4702 FILE *fp;
4703 uint32 tcflags;
4704 JSScript *script;
4706 CHECK_REQUEST(cx);
4707 if (!filename || strcmp(filename, "-") == 0) {
4708 fp = stdin;
4709 } else {
4710 fp = fopen(filename, "r");
4711 if (!fp) {
4712 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
4713 filename, "No such file or directory");
4714 return NULL;
4718 tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
4719 script = js_CompileScript(cx, obj, NULL, NULL, tcflags,
4720 NULL, 0, fp, filename, 1);
4721 if (fp != stdin)
4722 fclose(fp);
4723 LAST_FRAME_CHECKS(cx, script);
4724 return script;
4727 JS_PUBLIC_API(JSScript *)
4728 JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename,
4729 FILE *file)
4731 return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
4734 JS_PUBLIC_API(JSScript *)
4735 JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
4736 const char *filename, FILE *file,
4737 JSPrincipals *principals)
4739 uint32 tcflags;
4740 JSScript *script;
4742 CHECK_REQUEST(cx);
4743 tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
4744 script = js_CompileScript(cx, obj, NULL, principals, tcflags,
4745 NULL, 0, file, filename, 1);
4746 LAST_FRAME_CHECKS(cx, script);
4747 return script;
4750 JS_PUBLIC_API(JSObject *)
4751 JS_NewScriptObject(JSContext *cx, JSScript *script)
4753 JSTempValueRooter tvr;
4754 JSObject *obj;
4756 CHECK_REQUEST(cx);
4757 if (!script)
4758 return js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0);
4760 JS_ASSERT(!script->u.object);
4762 JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr);
4763 obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL, 0);
4764 if (obj) {
4765 JS_SetPrivate(cx, obj, script);
4766 script->u.object = obj;
4767 #ifdef CHECK_SCRIPT_OWNER
4768 script->owner = NULL;
4769 #endif
4771 JS_POP_TEMP_ROOT(cx, &tvr);
4772 return obj;
4775 JS_PUBLIC_API(JSObject *)
4776 JS_GetScriptObject(JSScript *script)
4778 return script->u.object;
4781 JS_PUBLIC_API(void)
4782 JS_DestroyScript(JSContext *cx, JSScript *script)
4784 CHECK_REQUEST(cx);
4785 js_DestroyScript(cx, script);
4788 JS_PUBLIC_API(JSFunction *)
4789 JS_CompileFunction(JSContext *cx, JSObject *obj, const char *name,
4790 uintN nargs, const char **argnames,
4791 const char *bytes, size_t length,
4792 const char *filename, uintN lineno)
4794 jschar *chars;
4795 JSFunction *fun;
4797 CHECK_REQUEST(cx);
4798 chars = js_InflateString(cx, bytes, &length);
4799 if (!chars)
4800 return NULL;
4801 fun = JS_CompileUCFunction(cx, obj, name, nargs, argnames, chars, length,
4802 filename, lineno);
4803 JS_free(cx, chars);
4804 return fun;
4807 JS_PUBLIC_API(JSFunction *)
4808 JS_CompileFunctionForPrincipals(JSContext *cx, JSObject *obj,
4809 JSPrincipals *principals, const char *name,
4810 uintN nargs, const char **argnames,
4811 const char *bytes, size_t length,
4812 const char *filename, uintN lineno)
4814 jschar *chars;
4815 JSFunction *fun;
4817 CHECK_REQUEST(cx);
4818 chars = js_InflateString(cx, bytes, &length);
4819 if (!chars)
4820 return NULL;
4821 fun = JS_CompileUCFunctionForPrincipals(cx, obj, principals, name,
4822 nargs, argnames, chars, length,
4823 filename, lineno);
4824 JS_free(cx, chars);
4825 return fun;
4828 JS_PUBLIC_API(JSFunction *)
4829 JS_CompileUCFunction(JSContext *cx, JSObject *obj, const char *name,
4830 uintN nargs, const char **argnames,
4831 const jschar *chars, size_t length,
4832 const char *filename, uintN lineno)
4834 CHECK_REQUEST(cx);
4835 return JS_CompileUCFunctionForPrincipals(cx, obj, NULL, name,
4836 nargs, argnames,
4837 chars, length,
4838 filename, lineno);
4841 JS_PUBLIC_API(JSFunction *)
4842 JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
4843 JSPrincipals *principals, const char *name,
4844 uintN nargs, const char **argnames,
4845 const jschar *chars, size_t length,
4846 const char *filename, uintN lineno)
4848 JSFunction *fun;
4849 JSTempValueRooter tvr;
4850 JSAtom *funAtom, *argAtom;
4851 uintN i;
4853 CHECK_REQUEST(cx);
4854 if (!name) {
4855 funAtom = NULL;
4856 } else {
4857 funAtom = js_Atomize(cx, name, strlen(name), 0);
4858 if (!funAtom) {
4859 fun = NULL;
4860 goto out2;
4863 fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
4864 if (!fun)
4865 goto out2;
4867 MUST_FLOW_THROUGH("out");
4868 JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr);
4869 for (i = 0; i < nargs; i++) {
4870 argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
4871 if (!argAtom) {
4872 fun = NULL;
4873 goto out;
4875 if (!js_AddLocal(cx, fun, argAtom, JSLOCAL_ARG)) {
4876 fun = NULL;
4877 goto out;
4881 if (!js_CompileFunctionBody(cx, fun, principals, chars, length,
4882 filename, lineno)) {
4883 fun = NULL;
4884 goto out;
4887 if (obj &&
4888 funAtom &&
4889 !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(funAtom),
4890 OBJECT_TO_JSVAL(FUN_OBJECT(fun)),
4891 NULL, NULL, JSPROP_ENUMERATE, NULL)) {
4892 fun = NULL;
4895 #ifdef JS_SCOPE_DEPTH_METER
4896 if (fun && obj) {
4897 JSObject *pobj = obj;
4898 uintN depth = 1;
4900 while ((pobj = OBJ_GET_PARENT(cx, pobj)) != NULL)
4901 ++depth;
4902 JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
4904 #endif
4906 out:
4907 cx->weakRoots.newborn[JSTRACE_OBJECT] = FUN_OBJECT(fun);
4908 JS_POP_TEMP_ROOT(cx, &tvr);
4910 out2:
4911 LAST_FRAME_CHECKS(cx, fun);
4912 return fun;
4915 JS_PUBLIC_API(JSString *)
4916 JS_DecompileScript(JSContext *cx, JSScript *script, const char *name,
4917 uintN indent)
4919 JSPrinter *jp;
4920 JSString *str;
4922 CHECK_REQUEST(cx);
4923 jp = JS_NEW_PRINTER(cx, name, NULL,
4924 indent & ~JS_DONT_PRETTY_PRINT,
4925 !(indent & JS_DONT_PRETTY_PRINT));
4926 if (!jp)
4927 return NULL;
4928 if (js_DecompileScript(jp, script))
4929 str = js_GetPrinterOutput(jp);
4930 else
4931 str = NULL;
4932 js_DestroyPrinter(jp);
4933 return str;
4936 JS_PUBLIC_API(JSString *)
4937 JS_DecompileFunction(JSContext *cx, JSFunction *fun, uintN indent)
4939 JSPrinter *jp;
4940 JSString *str;
4942 CHECK_REQUEST(cx);
4943 jp = JS_NEW_PRINTER(cx, "JS_DecompileFunction", fun,
4944 indent & ~JS_DONT_PRETTY_PRINT,
4945 !(indent & JS_DONT_PRETTY_PRINT));
4946 if (!jp)
4947 return NULL;
4948 if (js_DecompileFunction(jp))
4949 str = js_GetPrinterOutput(jp);
4950 else
4951 str = NULL;
4952 js_DestroyPrinter(jp);
4953 return str;
4956 JS_PUBLIC_API(JSString *)
4957 JS_DecompileFunctionBody(JSContext *cx, JSFunction *fun, uintN indent)
4959 JSPrinter *jp;
4960 JSString *str;
4962 CHECK_REQUEST(cx);
4963 jp = JS_NEW_PRINTER(cx, "JS_DecompileFunctionBody", fun,
4964 indent & ~JS_DONT_PRETTY_PRINT,
4965 !(indent & JS_DONT_PRETTY_PRINT));
4966 if (!jp)
4967 return NULL;
4968 if (js_DecompileFunctionBody(jp))
4969 str = js_GetPrinterOutput(jp);
4970 else
4971 str = NULL;
4972 js_DestroyPrinter(jp);
4973 return str;
4976 JS_PUBLIC_API(JSBool)
4977 JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
4979 JSBool ok;
4981 CHECK_REQUEST(cx);
4982 ok = js_Execute(cx, obj, script, NULL, 0, rval);
4983 LAST_FRAME_CHECKS(cx, ok);
4984 return ok;
4987 JS_PUBLIC_API(JSBool)
4988 JS_ExecuteScriptPart(JSContext *cx, JSObject *obj, JSScript *script,
4989 JSExecPart part, jsval *rval)
4991 JSScript tmp;
4992 JSDebugHooks *hooks;
4993 JSBool ok;
4995 /* Make a temporary copy of the JSScript structure and farble it a bit. */
4996 tmp = *script;
4997 if (part == JSEXEC_PROLOG) {
4998 tmp.length = PTRDIFF(tmp.main, tmp.code, jsbytecode);
4999 } else {
5000 tmp.length -= PTRDIFF(tmp.main, tmp.code, jsbytecode);
5001 tmp.code = tmp.main;
5004 /* Tell the debugger about our temporary copy of the script structure. */
5005 hooks = cx->debugHooks;
5006 if (hooks->newScriptHook) {
5007 hooks->newScriptHook(cx, tmp.filename, tmp.lineno, &tmp, NULL,
5008 hooks->newScriptHookData);
5011 /* Execute the farbled struct and tell the debugger to forget about it. */
5012 ok = JS_ExecuteScript(cx, obj, &tmp, rval);
5013 if (hooks->destroyScriptHook)
5014 hooks->destroyScriptHook(cx, &tmp, hooks->destroyScriptHookData);
5015 return ok;
5018 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
5019 JS_PUBLIC_API(JSBool)
5020 JS_EvaluateScript(JSContext *cx, JSObject *obj,
5021 const char *bytes, uintN nbytes,
5022 const char *filename, uintN lineno,
5023 jsval *rval)
5025 size_t length = nbytes;
5026 jschar *chars;
5027 JSBool ok;
5029 CHECK_REQUEST(cx);
5030 chars = js_InflateString(cx, bytes, &length);
5031 if (!chars)
5032 return JS_FALSE;
5033 ok = JS_EvaluateUCScript(cx, obj, chars, length, filename, lineno, rval);
5034 JS_free(cx, chars);
5035 return ok;
5038 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
5039 JS_PUBLIC_API(JSBool)
5040 JS_EvaluateScriptForPrincipals(JSContext *cx, JSObject *obj,
5041 JSPrincipals *principals,
5042 const char *bytes, uintN nbytes,
5043 const char *filename, uintN lineno,
5044 jsval *rval)
5046 size_t length = nbytes;
5047 jschar *chars;
5048 JSBool ok;
5050 CHECK_REQUEST(cx);
5051 chars = js_InflateString(cx, bytes, &length);
5052 if (!chars)
5053 return JS_FALSE;
5054 ok = JS_EvaluateUCScriptForPrincipals(cx, obj, principals, chars, length,
5055 filename, lineno, rval);
5056 JS_free(cx, chars);
5057 return ok;
5060 JS_PUBLIC_API(JSBool)
5061 JS_EvaluateUCScript(JSContext *cx, JSObject *obj,
5062 const jschar *chars, uintN length,
5063 const char *filename, uintN lineno,
5064 jsval *rval)
5066 CHECK_REQUEST(cx);
5067 return JS_EvaluateUCScriptForPrincipals(cx, obj, NULL, chars, length,
5068 filename, lineno, rval);
5071 JS_PUBLIC_API(JSBool)
5072 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
5073 JSPrincipals *principals,
5074 const jschar *chars, uintN length,
5075 const char *filename, uintN lineno,
5076 jsval *rval)
5078 JSScript *script;
5079 JSBool ok;
5081 CHECK_REQUEST(cx);
5082 script = js_CompileScript(cx, obj, NULL, principals,
5083 !rval
5084 ? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
5085 : TCF_COMPILE_N_GO,
5086 chars, length, NULL, filename, lineno);
5087 if (!script) {
5088 LAST_FRAME_CHECKS(cx, script);
5089 return JS_FALSE;
5091 ok = js_Execute(cx, obj, script, NULL, 0, rval);
5092 LAST_FRAME_CHECKS(cx, ok);
5093 JS_DestroyScript(cx, script);
5094 return ok;
5097 JS_PUBLIC_API(JSBool)
5098 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc,
5099 jsval *argv, jsval *rval)
5101 JSBool ok;
5103 CHECK_REQUEST(cx);
5104 ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(FUN_OBJECT(fun)), argc, argv,
5105 rval);
5106 LAST_FRAME_CHECKS(cx, ok);
5107 return ok;
5110 JS_PUBLIC_API(JSBool)
5111 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
5112 jsval *argv, jsval *rval)
5114 JSBool ok;
5115 jsval fval;
5117 CHECK_REQUEST(cx);
5118 #if JS_HAS_XML_SUPPORT
5119 if (OBJECT_IS_XML(cx, obj)) {
5120 JSXMLObjectOps *ops;
5121 JSAtom *atom;
5123 ops = (JSXMLObjectOps *) obj->map->ops;
5124 atom = js_Atomize(cx, name, strlen(name), 0);
5125 if (!atom)
5126 return JS_FALSE;
5127 obj = ops->getMethod(cx, obj, ATOM_TO_JSID(atom), &fval);
5128 if (!obj)
5129 return JS_FALSE;
5130 } else
5131 #endif
5132 if (!JS_GetProperty(cx, obj, name, &fval))
5133 return JS_FALSE;
5134 ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
5135 LAST_FRAME_CHECKS(cx, ok);
5136 return ok;
5139 JS_PUBLIC_API(JSBool)
5140 JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
5141 jsval *argv, jsval *rval)
5143 JSBool ok;
5145 CHECK_REQUEST(cx);
5146 ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
5147 LAST_FRAME_CHECKS(cx, ok);
5148 return ok;
5151 JS_PUBLIC_API(void)
5152 JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback,
5153 uint32 operationLimit)
5155 JS_ASSERT(callback);
5156 JS_ASSERT(operationLimit <= JS_MAX_OPERATION_LIMIT);
5157 JS_ASSERT(operationLimit > 0);
5159 cx->operationCount = (int32) operationLimit;
5160 cx->operationLimit = operationLimit;
5161 cx->operationCallbackIsSet = 1;
5162 cx->operationCallback = callback;
5165 JS_PUBLIC_API(void)
5166 JS_ClearOperationCallback(JSContext *cx)
5168 cx->operationCount = (int32) JS_MAX_OPERATION_LIMIT;
5169 cx->operationLimit = JS_MAX_OPERATION_LIMIT;
5170 cx->operationCallbackIsSet = 0;
5171 cx->operationCallback = NULL;
5174 JS_PUBLIC_API(JSOperationCallback)
5175 JS_GetOperationCallback(JSContext *cx)
5177 JS_ASSERT(cx->operationCallbackIsSet || !cx->operationCallback);
5178 return cx->operationCallback;
5181 JS_PUBLIC_API(uint32)
5182 JS_GetOperationLimit(JSContext *cx)
5184 JS_ASSERT(cx->operationCallbackIsSet);
5185 return cx->operationLimit;
5188 JS_PUBLIC_API(void)
5189 JS_SetOperationLimit(JSContext *cx, uint32 operationLimit)
5191 JS_ASSERT(operationLimit <= JS_MAX_OPERATION_LIMIT);
5192 JS_ASSERT(operationLimit > 0);
5193 JS_ASSERT(cx->operationCallbackIsSet);
5195 cx->operationLimit = operationLimit;
5196 if (cx->operationCount > (int32) operationLimit)
5197 cx->operationCount = (int32) operationLimit;
5200 JS_PUBLIC_API(JSBranchCallback)
5201 JS_SetBranchCallback(JSContext *cx, JSBranchCallback cb)
5203 JSBranchCallback oldcb;
5205 if (cx->operationCallbackIsSet) {
5206 #ifdef DEBUG
5207 fprintf(stderr,
5208 "JS API usage error: call to JS_SetOperationCallback is followed by\n"
5209 "invocation of deprecated JS_SetBranchCallback\n");
5210 JS_ASSERT(0);
5211 #endif
5212 cx->operationCallbackIsSet = 0;
5213 oldcb = NULL;
5214 } else {
5215 oldcb = (JSBranchCallback) cx->operationCallback;
5217 if (cb) {
5218 cx->operationCount = JSOW_SCRIPT_JUMP;
5219 cx->operationLimit = JSOW_SCRIPT_JUMP;
5220 cx->operationCallback = (JSOperationCallback) cb;
5221 } else {
5222 JS_ClearOperationCallback(cx);
5224 return oldcb;
5227 JS_PUBLIC_API(JSBool)
5228 JS_IsRunning(JSContext *cx)
5230 return cx->fp != NULL;
5233 JS_PUBLIC_API(JSBool)
5234 JS_IsConstructing(JSContext *cx)
5236 return cx->fp && (cx->fp->flags & JSFRAME_CONSTRUCTING);
5239 JS_FRIEND_API(JSBool)
5240 JS_IsAssigning(JSContext *cx)
5242 JSStackFrame *fp;
5244 for (fp = cx->fp; fp && !fp->script; fp = fp->down)
5245 continue;
5246 if (!fp || !fp->regs)
5247 return JS_FALSE;
5248 return (js_CodeSpec[*fp->regs->pc].format & JOF_ASSIGNING) != 0;
5251 JS_PUBLIC_API(void)
5252 JS_SetCallReturnValue2(JSContext *cx, jsval v)
5254 #if JS_HAS_LVALUE_RETURN
5255 cx->rval2 = v;
5256 cx->rval2set = JS_TRUE;
5257 #endif
5260 JS_PUBLIC_API(JSStackFrame *)
5261 JS_SaveFrameChain(JSContext *cx)
5263 JSStackFrame *fp;
5265 fp = cx->fp;
5266 if (!fp)
5267 return fp;
5269 JS_ASSERT(!fp->dormantNext);
5270 fp->dormantNext = cx->dormantFrameChain;
5271 cx->dormantFrameChain = fp;
5272 cx->fp = NULL;
5273 return fp;
5276 JS_PUBLIC_API(void)
5277 JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
5279 JS_ASSERT(!cx->fp);
5280 if (!fp)
5281 return;
5283 JS_ASSERT(fp == cx->dormantFrameChain);
5284 cx->fp = fp;
5285 cx->dormantFrameChain = fp->dormantNext;
5286 fp->dormantNext = NULL;
5289 /************************************************************************/
5291 JS_PUBLIC_API(JSString *)
5292 JS_NewString(JSContext *cx, char *bytes, size_t nbytes)
5294 size_t length = nbytes;
5295 jschar *chars;
5296 JSString *str;
5298 CHECK_REQUEST(cx);
5300 /* Make a UTF-16 vector from the 8-bit char codes in bytes. */
5301 chars = js_InflateString(cx, bytes, &length);
5302 if (!chars)
5303 return NULL;
5305 /* Free chars (but not bytes, which caller frees on error) if we fail. */
5306 str = js_NewString(cx, chars, length);
5307 if (!str) {
5308 JS_free(cx, chars);
5309 return NULL;
5312 /* Hand off bytes to the deflated string cache, if possible. */
5313 if (!js_SetStringBytes(cx, str, bytes, nbytes))
5314 JS_free(cx, bytes);
5315 return str;
5318 JS_PUBLIC_API(JSString *)
5319 JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
5321 jschar *js;
5322 JSString *str;
5324 CHECK_REQUEST(cx);
5325 js = js_InflateString(cx, s, &n);
5326 if (!js)
5327 return NULL;
5328 str = js_NewString(cx, js, n);
5329 if (!str)
5330 JS_free(cx, js);
5331 return str;
5334 JS_PUBLIC_API(JSString *)
5335 JS_NewStringCopyZ(JSContext *cx, const char *s)
5337 size_t n;
5338 jschar *js;
5339 JSString *str;
5341 CHECK_REQUEST(cx);
5342 if (!s)
5343 return cx->runtime->emptyString;
5344 n = strlen(s);
5345 js = js_InflateString(cx, s, &n);
5346 if (!js)
5347 return NULL;
5348 str = js_NewString(cx, js, n);
5349 if (!str)
5350 JS_free(cx, js);
5351 return str;
5354 JS_PUBLIC_API(JSString *)
5355 JS_InternString(JSContext *cx, const char *s)
5357 JSAtom *atom;
5359 CHECK_REQUEST(cx);
5360 atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
5361 if (!atom)
5362 return NULL;
5363 return ATOM_TO_STRING(atom);
5366 JS_PUBLIC_API(JSString *)
5367 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
5369 CHECK_REQUEST(cx);
5370 return js_NewString(cx, chars, length);
5373 JS_PUBLIC_API(JSString *)
5374 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
5376 CHECK_REQUEST(cx);
5377 return js_NewStringCopyN(cx, s, n);
5380 JS_PUBLIC_API(JSString *)
5381 JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
5383 CHECK_REQUEST(cx);
5384 if (!s)
5385 return cx->runtime->emptyString;
5386 return js_NewStringCopyZ(cx, s);
5389 JS_PUBLIC_API(JSString *)
5390 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
5392 JSAtom *atom;
5394 CHECK_REQUEST(cx);
5395 atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
5396 if (!atom)
5397 return NULL;
5398 return ATOM_TO_STRING(atom);
5401 JS_PUBLIC_API(JSString *)
5402 JS_InternUCString(JSContext *cx, const jschar *s)
5404 return JS_InternUCStringN(cx, s, js_strlen(s));
5407 JS_PUBLIC_API(char *)
5408 JS_GetStringBytes(JSString *str)
5410 const char *bytes;
5412 bytes = js_GetStringBytes(NULL, str);
5413 return (char *)(bytes ? bytes : "");
5416 JS_PUBLIC_API(jschar *)
5417 JS_GetStringChars(JSString *str)
5419 size_t n, size;
5420 jschar *s;
5423 * API botch (again, shades of JS_GetStringBytes): we have no cx to report
5424 * out-of-memory when undepending strings, so we replace js_UndependString
5425 * with explicit malloc call and ignore its errors.
5427 * If we fail to convert a dependent string into an independent one, our
5428 * caller will not be guaranteed a \u0000 terminator as a backstop. This
5429 * may break some clients who already misbehave on embedded NULs.
5431 * The gain of dependent strings, which cure quadratic and cubic growth
5432 * rate bugs in string concatenation, is worth this slight loss in API
5433 * compatibility.
5435 if (JSSTRING_IS_DEPENDENT(str)) {
5436 n = JSSTRDEP_LENGTH(str);
5437 size = (n + 1) * sizeof(jschar);
5438 s = (jschar *) malloc(size);
5439 if (s) {
5440 memcpy(s, JSSTRDEP_CHARS(str), n * sizeof *s);
5441 s[n] = 0;
5442 JSFLATSTR_INIT(str, s, n);
5443 } else {
5444 s = JSSTRDEP_CHARS(str);
5446 } else {
5447 JSFLATSTR_CLEAR_MUTABLE(str);
5448 s = JSFLATSTR_CHARS(str);
5450 return s;
5453 JS_PUBLIC_API(size_t)
5454 JS_GetStringLength(JSString *str)
5456 return JSSTRING_LENGTH(str);
5459 JS_PUBLIC_API(intN)
5460 JS_CompareStrings(JSString *str1, JSString *str2)
5462 return js_CompareStrings(str1, str2);
5465 JS_PUBLIC_API(JSString *)
5466 JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
5468 JSString *str;
5470 CHECK_REQUEST(cx);
5471 str = js_NewString(cx, chars, length);
5472 if (!str)
5473 return str;
5474 JSFLATSTR_SET_MUTABLE(str);
5475 return str;
5478 JS_PUBLIC_API(JSString *)
5479 JS_NewDependentString(JSContext *cx, JSString *str, size_t start,
5480 size_t length)
5482 CHECK_REQUEST(cx);
5483 return js_NewDependentString(cx, str, start, length);
5486 JS_PUBLIC_API(JSString *)
5487 JS_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
5489 CHECK_REQUEST(cx);
5490 return js_ConcatStrings(cx, left, right);
5493 JS_PUBLIC_API(const jschar *)
5494 JS_UndependString(JSContext *cx, JSString *str)
5496 CHECK_REQUEST(cx);
5497 return js_UndependString(cx, str);
5500 JS_PUBLIC_API(JSBool)
5501 JS_MakeStringImmutable(JSContext *cx, JSString *str)
5503 CHECK_REQUEST(cx);
5504 return js_MakeStringImmutable(cx, str);
5507 JS_PUBLIC_API(JSBool)
5508 JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst,
5509 size_t *dstlenp)
5511 size_t n;
5513 if (!dst) {
5514 n = js_GetDeflatedStringLength(cx, src, srclen);
5515 if (n == (size_t)-1) {
5516 *dstlenp = 0;
5517 return JS_FALSE;
5519 *dstlenp = n;
5520 return JS_TRUE;
5523 return js_DeflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5526 JS_PUBLIC_API(JSBool)
5527 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst,
5528 size_t *dstlenp)
5530 return js_InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
5533 JS_PUBLIC_API(char *)
5534 JS_EncodeString(JSContext *cx, JSString *str)
5536 return js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
5539 JS_PUBLIC_API(JSBool)
5540 JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer,
5541 JSONWriteCallback callback, void *data)
5543 CHECK_REQUEST(cx);
5544 return js_Stringify(cx, vp, replacer, callback, data, 0);
5547 JS_PUBLIC_API(JSBool)
5548 JS_TryJSON(JSContext *cx, jsval *vp)
5550 CHECK_REQUEST(cx);
5551 return js_TryJSON(cx, vp);
5554 JS_PUBLIC_API(JSONParser *)
5555 JS_BeginJSONParse(JSContext *cx, jsval *vp)
5557 CHECK_REQUEST(cx);
5558 return js_BeginJSONParse(cx, vp);
5561 JS_PUBLIC_API(JSBool)
5562 JS_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len)
5564 CHECK_REQUEST(cx);
5565 return js_ConsumeJSONText(cx, jp, data, len);
5568 JS_PUBLIC_API(JSBool)
5569 JS_FinishJSONParse(JSContext *cx, JSONParser *jp)
5571 CHECK_REQUEST(cx);
5572 return js_FinishJSONParse(cx, jp);
5576 * The following determines whether C Strings are to be treated as UTF-8
5577 * or ISO-8859-1. For correct operation, it must be set prior to the
5578 * first call to JS_NewRuntime.
5580 #ifndef JS_C_STRINGS_ARE_UTF8
5581 JSBool js_CStringsAreUTF8 = JS_FALSE;
5582 #endif
5584 JS_PUBLIC_API(JSBool)
5585 JS_CStringsAreUTF8()
5587 return js_CStringsAreUTF8;
5590 JS_PUBLIC_API(void)
5591 JS_SetCStringsAreUTF8()
5593 JS_ASSERT(!js_NewRuntimeWasCalled);
5595 #ifndef JS_C_STRINGS_ARE_UTF8
5596 js_CStringsAreUTF8 = JS_TRUE;
5597 #endif
5600 /************************************************************************/
5602 JS_PUBLIC_API(void)
5603 JS_ReportError(JSContext *cx, const char *format, ...)
5605 va_list ap;
5607 va_start(ap, format);
5608 js_ReportErrorVA(cx, JSREPORT_ERROR, format, ap);
5609 va_end(ap);
5612 JS_PUBLIC_API(void)
5613 JS_ReportErrorNumber(JSContext *cx, JSErrorCallback errorCallback,
5614 void *userRef, const uintN errorNumber, ...)
5616 va_list ap;
5618 va_start(ap, errorNumber);
5619 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5620 errorNumber, JS_TRUE, ap);
5621 va_end(ap);
5624 JS_PUBLIC_API(void)
5625 JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
5626 void *userRef, const uintN errorNumber, ...)
5628 va_list ap;
5630 va_start(ap, errorNumber);
5631 js_ReportErrorNumberVA(cx, JSREPORT_ERROR, errorCallback, userRef,
5632 errorNumber, JS_FALSE, ap);
5633 va_end(ap);
5636 JS_PUBLIC_API(JSBool)
5637 JS_ReportWarning(JSContext *cx, const char *format, ...)
5639 va_list ap;
5640 JSBool ok;
5642 va_start(ap, format);
5643 ok = js_ReportErrorVA(cx, JSREPORT_WARNING, format, ap);
5644 va_end(ap);
5645 return ok;
5648 JS_PUBLIC_API(JSBool)
5649 JS_ReportErrorFlagsAndNumber(JSContext *cx, uintN flags,
5650 JSErrorCallback errorCallback, void *userRef,
5651 const uintN errorNumber, ...)
5653 va_list ap;
5654 JSBool ok;
5656 va_start(ap, errorNumber);
5657 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5658 errorNumber, JS_TRUE, ap);
5659 va_end(ap);
5660 return ok;
5663 JS_PUBLIC_API(JSBool)
5664 JS_ReportErrorFlagsAndNumberUC(JSContext *cx, uintN flags,
5665 JSErrorCallback errorCallback, void *userRef,
5666 const uintN errorNumber, ...)
5668 va_list ap;
5669 JSBool ok;
5671 va_start(ap, errorNumber);
5672 ok = js_ReportErrorNumberVA(cx, flags, errorCallback, userRef,
5673 errorNumber, JS_FALSE, ap);
5674 va_end(ap);
5675 return ok;
5678 JS_PUBLIC_API(void)
5679 JS_ReportOutOfMemory(JSContext *cx)
5681 js_ReportOutOfMemory(cx);
5684 JS_PUBLIC_API(void)
5685 JS_ReportAllocationOverflow(JSContext *cx)
5687 js_ReportAllocationOverflow(cx);
5690 JS_PUBLIC_API(JSErrorReporter)
5691 JS_SetErrorReporter(JSContext *cx, JSErrorReporter er)
5693 JSErrorReporter older;
5695 older = cx->errorReporter;
5696 cx->errorReporter = er;
5697 return older;
5700 /************************************************************************/
5703 * Regular Expressions.
5705 JS_PUBLIC_API(JSObject *)
5706 JS_NewRegExpObject(JSContext *cx, char *bytes, size_t length, uintN flags)
5708 jschar *chars;
5709 JSObject *obj;
5711 CHECK_REQUEST(cx);
5712 chars = js_InflateString(cx, bytes, &length);
5713 if (!chars)
5714 return NULL;
5715 obj = js_NewRegExpObject(cx, NULL, chars, length, flags);
5716 JS_free(cx, chars);
5717 return obj;
5720 JS_PUBLIC_API(JSObject *)
5721 JS_NewUCRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags)
5723 CHECK_REQUEST(cx);
5724 return js_NewRegExpObject(cx, NULL, chars, length, flags);
5727 JS_PUBLIC_API(void)
5728 JS_SetRegExpInput(JSContext *cx, JSString *input, JSBool multiline)
5730 JSRegExpStatics *res;
5732 CHECK_REQUEST(cx);
5733 /* No locking required, cx is thread-private and input must be live. */
5734 res = &cx->regExpStatics;
5735 res->input = input;
5736 res->multiline = multiline;
5737 cx->runtime->gcPoke = JS_TRUE;
5740 JS_PUBLIC_API(void)
5741 JS_ClearRegExpStatics(JSContext *cx)
5743 JSRegExpStatics *res;
5745 /* No locking required, cx is thread-private and input must be live. */
5746 res = &cx->regExpStatics;
5747 res->input = NULL;
5748 res->multiline = JS_FALSE;
5749 res->parenCount = 0;
5750 res->lastMatch = res->lastParen = js_EmptySubString;
5751 res->leftContext = res->rightContext = js_EmptySubString;
5752 cx->runtime->gcPoke = JS_TRUE;
5755 JS_PUBLIC_API(void)
5756 JS_ClearRegExpRoots(JSContext *cx)
5758 JSRegExpStatics *res;
5760 /* No locking required, cx is thread-private and input must be live. */
5761 res = &cx->regExpStatics;
5762 res->input = NULL;
5763 cx->runtime->gcPoke = JS_TRUE;
5766 /* TODO: compile, execute, get/set other statics... */
5768 /************************************************************************/
5770 JS_PUBLIC_API(void)
5771 JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
5773 cx->localeCallbacks = callbacks;
5776 JS_PUBLIC_API(JSLocaleCallbacks *)
5777 JS_GetLocaleCallbacks(JSContext *cx)
5779 return cx->localeCallbacks;
5782 /************************************************************************/
5784 JS_PUBLIC_API(JSBool)
5785 JS_IsExceptionPending(JSContext *cx)
5787 return (JSBool) cx->throwing;
5790 JS_PUBLIC_API(JSBool)
5791 JS_GetPendingException(JSContext *cx, jsval *vp)
5793 CHECK_REQUEST(cx);
5794 if (!cx->throwing)
5795 return JS_FALSE;
5796 *vp = cx->exception;
5797 return JS_TRUE;
5800 JS_PUBLIC_API(void)
5801 JS_SetPendingException(JSContext *cx, jsval v)
5803 CHECK_REQUEST(cx);
5804 cx->throwing = JS_TRUE;
5805 cx->exception = v;
5808 JS_PUBLIC_API(void)
5809 JS_ClearPendingException(JSContext *cx)
5811 cx->throwing = JS_FALSE;
5812 cx->exception = JSVAL_VOID;
5815 JS_PUBLIC_API(JSBool)
5816 JS_ReportPendingException(JSContext *cx)
5818 JSBool save, ok;
5820 CHECK_REQUEST(cx);
5823 * Set cx->generatingError to suppress the standard error-to-exception
5824 * conversion done by all {js,JS}_Report* functions except for OOM. The
5825 * cx->generatingError flag was added to suppress recursive divergence
5826 * under js_ErrorToException, but it serves for our purposes here too.
5828 save = cx->generatingError;
5829 cx->generatingError = JS_TRUE;
5830 ok = js_ReportUncaughtException(cx);
5831 cx->generatingError = save;
5832 return ok;
5835 struct JSExceptionState {
5836 JSBool throwing;
5837 jsval exception;
5840 JS_PUBLIC_API(JSExceptionState *)
5841 JS_SaveExceptionState(JSContext *cx)
5843 JSExceptionState *state;
5845 CHECK_REQUEST(cx);
5846 state = (JSExceptionState *) JS_malloc(cx, sizeof(JSExceptionState));
5847 if (state) {
5848 state->throwing = JS_GetPendingException(cx, &state->exception);
5849 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
5850 js_AddRoot(cx, &state->exception, "JSExceptionState.exception");
5852 return state;
5855 JS_PUBLIC_API(void)
5856 JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
5858 CHECK_REQUEST(cx);
5859 if (state) {
5860 if (state->throwing)
5861 JS_SetPendingException(cx, state->exception);
5862 else
5863 JS_ClearPendingException(cx);
5864 JS_DropExceptionState(cx, state);
5868 JS_PUBLIC_API(void)
5869 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
5871 CHECK_REQUEST(cx);
5872 if (state) {
5873 if (state->throwing && JSVAL_IS_GCTHING(state->exception))
5874 JS_RemoveRoot(cx, &state->exception);
5875 JS_free(cx, state);
5879 JS_PUBLIC_API(JSErrorReport *)
5880 JS_ErrorFromException(JSContext *cx, jsval v)
5882 CHECK_REQUEST(cx);
5883 return js_ErrorFromException(cx, v);
5886 JS_PUBLIC_API(JSBool)
5887 JS_ThrowReportedError(JSContext *cx, const char *message,
5888 JSErrorReport *reportp)
5890 return cx->fp && js_ErrorToException(cx, message, reportp);
5893 JS_PUBLIC_API(JSBool)
5894 JS_ThrowStopIteration(JSContext *cx)
5896 return js_ThrowStopIteration(cx);
5900 * Get the owning thread id of a context. Returns 0 if the context is not
5901 * owned by any thread.
5903 JS_PUBLIC_API(jsword)
5904 JS_GetContextThread(JSContext *cx)
5906 #ifdef JS_THREADSAFE
5907 return JS_THREAD_ID(cx);
5908 #else
5909 return 0;
5910 #endif
5914 * Set the current thread as the owning thread of a context. Returns the
5915 * old owning thread id, or -1 if the operation failed.
5917 JS_PUBLIC_API(jsword)
5918 JS_SetContextThread(JSContext *cx)
5920 #ifdef JS_THREADSAFE
5921 jsword old = JS_THREAD_ID(cx);
5922 if (!js_SetContextThread(cx))
5923 return -1;
5924 return old;
5925 #else
5926 return 0;
5927 #endif
5930 JS_PUBLIC_API(jsword)
5931 JS_ClearContextThread(JSContext *cx)
5933 #ifdef JS_THREADSAFE
5934 jsword old = JS_THREAD_ID(cx);
5935 js_ClearContextThread(cx);
5936 return old;
5937 #else
5938 return 0;
5939 #endif
5942 #ifdef JS_GC_ZEAL
5943 JS_PUBLIC_API(void)
5944 JS_SetGCZeal(JSContext *cx, uint8 zeal)
5946 cx->runtime->gcZeal = zeal;
5948 #endif
5950 /************************************************************************/
5952 #if !defined(STATIC_JS_API) && defined(XP_WIN) && !defined (WINCE)
5954 #include <windows.h>
5957 * Initialization routine for the JS DLL.
5959 BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
5961 return TRUE;
5964 #endif