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
17 * The Original Code is Mozilla Communicator client code, released
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.
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 ***** */
50 #include "jsarena.h" /* Added by JSIFY */
51 #include "jsutil.h" /* Added by JSIFY */
59 #include "jsbuiltins.h"
61 #include "jsversion.h"
85 #include "jsstaticcheck.h"
87 #if JS_HAS_FILE_OBJECT
91 #if JS_HAS_XML_SUPPORT
95 #ifdef HAVE_VA_LIST_AS_ARRAY
96 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
98 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
101 #if defined(JS_THREADSAFE)
102 #define CHECK_REQUEST(cx) \
103 JS_ASSERT((cx)->requestDepth || (cx)->thread == (cx)->runtime->gcThread)
105 #define CHECK_REQUEST(cx) ((void)0)
108 /* Check that we can cast JSObject* as jsval without tag bit manipulations. */
109 JS_STATIC_ASSERT(JSVAL_OBJECT
== 0);
111 /* Check that JSVAL_TRACE_KIND works. */
112 JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_OBJECT
) == JSTRACE_OBJECT
);
113 JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_DOUBLE
) == JSTRACE_DOUBLE
);
114 JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_STRING
) == JSTRACE_STRING
);
123 JS_GetNaNValue(JSContext
*cx
)
125 return DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
);
129 JS_GetNegativeInfinityValue(JSContext
*cx
)
131 return DOUBLE_TO_JSVAL(cx
->runtime
->jsNegativeInfinity
);
135 JS_GetPositiveInfinityValue(JSContext
*cx
)
137 return DOUBLE_TO_JSVAL(cx
->runtime
->jsPositiveInfinity
);
141 JS_GetEmptyStringValue(JSContext
*cx
)
143 return STRING_TO_JSVAL(cx
->runtime
->emptyString
);
147 TryArgumentFormatter(JSContext
*cx
, const char **formatp
, JSBool fromJS
,
148 jsval
**vpp
, va_list *app
)
151 JSArgumentFormatMap
*map
;
154 for (map
= cx
->argumentFormatMap
; map
; map
= map
->next
) {
155 if (!strncmp(format
, map
->format
, map
->length
)) {
156 *formatp
= format
+ map
->length
;
157 return map
->formatter(cx
, format
, fromJS
, vpp
, app
);
160 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_CHAR
, format
);
164 JS_PUBLIC_API(JSBool
)
165 JS_ConvertArguments(JSContext
*cx
, uintN argc
, jsval
*argv
, const char *format
,
171 va_start(ap
, format
);
172 ok
= JS_ConvertArgumentsVA(cx
, argc
, argv
, format
, ap
);
177 JS_PUBLIC_API(JSBool
)
178 JS_ConvertArgumentsVA(JSContext
*cx
, uintN argc
, jsval
*argv
,
179 const char *format
, va_list ap
)
192 while ((c
= *format
++) != '\0') {
199 if (sp
== argv
+ argc
) {
201 fun
= js_ValueToFunction(cx
, &argv
[-2], 0);
204 JS_snprintf(numBuf
, sizeof numBuf
, "%u", argc
);
205 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
206 JSMSG_MORE_ARGS_NEEDED
,
207 JS_GetFunctionName(fun
), numBuf
,
208 (argc
== 1) ? "" : "s");
216 *va_arg(ap
, JSBool
*) = js_ValueToBoolean(*sp
);
219 if (!JS_ValueToUint16(cx
, *sp
, va_arg(ap
, uint16
*)))
223 if (!JS_ValueToECMAInt32(cx
, *sp
, va_arg(ap
, int32
*)))
227 if (!JS_ValueToECMAUint32(cx
, *sp
, va_arg(ap
, uint32
*)))
231 if (!JS_ValueToInt32(cx
, *sp
, va_arg(ap
, int32
*)))
235 if (!JS_ValueToNumber(cx
, *sp
, va_arg(ap
, jsdouble
*)))
239 if (!JS_ValueToNumber(cx
, *sp
, &d
))
241 *va_arg(ap
, jsdouble
*) = js_DoubleToInteger(d
);
246 str
= js_ValueToString(cx
, *sp
);
249 *sp
= STRING_TO_JSVAL(str
);
251 const char *bytes
= js_GetStringBytes(cx
, str
);
254 *va_arg(ap
, const char **) = bytes
;
255 } else if (c
== 'W') {
256 const jschar
*chars
= js_GetStringChars(cx
, str
);
259 *va_arg(ap
, const jschar
**) = chars
;
261 *va_arg(ap
, JSString
**) = str
;
265 if (!js_ValueToObject(cx
, *sp
, &obj
))
267 *sp
= OBJECT_TO_JSVAL(obj
);
268 *va_arg(ap
, JSObject
**) = obj
;
271 obj
= js_ValueToFunctionObject(cx
, sp
, 0);
274 *sp
= OBJECT_TO_JSVAL(obj
);
275 *va_arg(ap
, JSFunction
**) = (JSFunction
*) JS_GetPrivate(cx
, obj
);
278 *va_arg(ap
, jsval
*) = *sp
;
284 if (!TryArgumentFormatter(cx
, &format
, JS_TRUE
, &sp
,
285 JS_ADDRESSOF_VA_LIST(ap
))) {
288 /* NB: the formatter already updated sp, so we continue here. */
296 JS_PUBLIC_API(jsval
*)
297 JS_PushArguments(JSContext
*cx
, void **markp
, const char *format
, ...)
302 va_start(ap
, format
);
303 argv
= JS_PushArgumentsVA(cx
, markp
, format
, ap
);
308 JS_PUBLIC_API(jsval
*)
309 JS_PushArgumentsVA(JSContext
*cx
, void **markp
, const char *format
, va_list ap
)
322 for (cp
= format
; (c
= *cp
) != '\0'; cp
++) {
324 * Count non-space non-star characters as individual jsval arguments.
325 * This may over-allocate stack, but we'll fix below.
327 if (isspace(c
) || c
== '*')
332 sp
= js_AllocStack(cx
, argc
, markp
);
336 while ((c
= *format
++) != '\0') {
337 if (isspace(c
) || c
== '*')
341 *sp
= BOOLEAN_TO_JSVAL((JSBool
) va_arg(ap
, int));
344 *sp
= INT_TO_JSVAL((uint16
) va_arg(ap
, unsigned int));
349 * Use JS_New{Double,Number}Value here and in the next two cases,
350 * not js_New{Double,Number}InRootedValue, as sp may point to an
353 if (!JS_NewNumberValue(cx
, (jsdouble
) va_arg(ap
, int32
), sp
))
357 if (!JS_NewNumberValue(cx
, (jsdouble
) va_arg(ap
, uint32
), sp
))
362 if (!JS_NewDoubleValue(cx
, va_arg(ap
, jsdouble
), sp
))
366 str
= JS_NewStringCopyZ(cx
, va_arg(ap
, char *));
369 *sp
= STRING_TO_JSVAL(str
);
372 str
= JS_NewUCStringCopyZ(cx
, va_arg(ap
, jschar
*));
375 *sp
= STRING_TO_JSVAL(str
);
378 str
= va_arg(ap
, JSString
*);
379 *sp
= STRING_TO_JSVAL(str
);
382 *sp
= OBJECT_TO_JSVAL(va_arg(ap
, JSObject
*));
385 fun
= va_arg(ap
, JSFunction
*);
386 *sp
= fun
? OBJECT_TO_JSVAL(FUN_OBJECT(fun
)) : JSVAL_NULL
;
389 *sp
= va_arg(ap
, jsval
);
393 if (!TryArgumentFormatter(cx
, &format
, JS_FALSE
, &sp
,
394 JS_ADDRESSOF_VA_LIST(ap
))) {
397 /* NB: the formatter already updated sp, so we continue here. */
404 * We may have overallocated stack due to a multi-character format code
405 * handled by a JSArgumentFormatter. Give back that stack space!
407 JS_ASSERT(sp
<= argv
+ argc
);
408 if (sp
< argv
+ argc
) {
409 /* Return slots not pushed to the current stack arena. */
410 cx
->stackPool
.current
->avail
= (jsuword
)sp
;
412 /* Reduce the count of slots the GC will scan in this stack segment. */
413 sh
= cx
->stackHeaders
;
414 JS_ASSERT(JS_STACK_SEGMENT(sh
) + sh
->nslots
== argv
+ argc
);
415 sh
->nslots
-= argc
- (sp
- argv
);
420 js_FreeStack(cx
, *markp
);
425 JS_PopArguments(JSContext
*cx
, void *mark
)
428 JS_ASSERT_NOT_ON_TRACE(cx
);
429 js_FreeStack(cx
, mark
);
432 JS_PUBLIC_API(JSBool
)
433 JS_AddArgumentFormatter(JSContext
*cx
, const char *format
,
434 JSArgumentFormatter formatter
)
437 JSArgumentFormatMap
**mpp
, *map
;
439 length
= strlen(format
);
440 mpp
= &cx
->argumentFormatMap
;
441 while ((map
= *mpp
) != NULL
) {
442 /* Insert before any shorter string to match before prefixes. */
443 if (map
->length
< length
)
445 if (map
->length
== length
&& !strcmp(map
->format
, format
))
449 map
= (JSArgumentFormatMap
*) JS_malloc(cx
, sizeof *map
);
452 map
->format
= format
;
453 map
->length
= length
;
457 map
->formatter
= formatter
;
462 JS_RemoveArgumentFormatter(JSContext
*cx
, const char *format
)
465 JSArgumentFormatMap
**mpp
, *map
;
467 length
= strlen(format
);
468 mpp
= &cx
->argumentFormatMap
;
469 while ((map
= *mpp
) != NULL
) {
470 if (map
->length
== length
&& !strcmp(map
->format
, format
)) {
479 JS_PUBLIC_API(JSBool
)
480 JS_ConvertValue(JSContext
*cx
, jsval v
, JSType type
, jsval
*vp
)
494 ok
= js_ValueToObject(cx
, v
, &obj
);
496 *vp
= OBJECT_TO_JSVAL(obj
);
498 case JSTYPE_FUNCTION
:
500 obj
= js_ValueToFunctionObject(cx
, vp
, JSV2F_SEARCH_STACK
);
504 str
= js_ValueToString(cx
, v
);
507 *vp
= STRING_TO_JSVAL(str
);
510 ok
= JS_ValueToNumber(cx
, v
, &d
);
512 dp
= js_NewWeaklyRootedDouble(cx
, d
);
515 *vp
= DOUBLE_TO_JSVAL(dp
);
519 *vp
= BOOLEAN_TO_JSVAL(js_ValueToBoolean(v
));
523 JS_snprintf(numBuf
, sizeof numBuf
, "%d", (int)type
);
524 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_TYPE
,
533 JS_PUBLIC_API(JSBool
)
534 JS_ValueToObject(JSContext
*cx
, jsval v
, JSObject
**objp
)
537 return js_ValueToObject(cx
, v
, objp
);
540 JS_PUBLIC_API(JSFunction
*)
541 JS_ValueToFunction(JSContext
*cx
, jsval v
)
544 return js_ValueToFunction(cx
, &v
, JSV2F_SEARCH_STACK
);
547 JS_PUBLIC_API(JSFunction
*)
548 JS_ValueToConstructor(JSContext
*cx
, jsval v
)
551 return js_ValueToFunction(cx
, &v
, JSV2F_SEARCH_STACK
);
554 JS_PUBLIC_API(JSString
*)
555 JS_ValueToString(JSContext
*cx
, jsval v
)
558 return js_ValueToString(cx
, v
);
561 JS_PUBLIC_API(JSString
*)
562 JS_ValueToSource(JSContext
*cx
, jsval v
)
565 return js_ValueToSource(cx
, v
);
568 JS_PUBLIC_API(JSBool
)
569 JS_ValueToNumber(JSContext
*cx
, jsval v
, jsdouble
*dp
)
571 JSTempValueRooter tvr
;
574 JS_PUSH_SINGLE_TEMP_ROOT(cx
, v
, &tvr
);
575 *dp
= js_ValueToNumber(cx
, &tvr
.u
.value
);
576 JS_POP_TEMP_ROOT(cx
, &tvr
);
577 return !JSVAL_IS_NULL(tvr
.u
.value
);
580 JS_PUBLIC_API(JSBool
)
581 JS_ValueToECMAInt32(JSContext
*cx
, jsval v
, int32
*ip
)
583 JSTempValueRooter tvr
;
586 JS_PUSH_SINGLE_TEMP_ROOT(cx
, v
, &tvr
);
587 *ip
= js_ValueToECMAInt32(cx
, &tvr
.u
.value
);
588 JS_POP_TEMP_ROOT(cx
, &tvr
);
589 return !JSVAL_IS_NULL(tvr
.u
.value
);
592 JS_PUBLIC_API(JSBool
)
593 JS_ValueToECMAUint32(JSContext
*cx
, jsval v
, uint32
*ip
)
595 JSTempValueRooter tvr
;
598 JS_PUSH_SINGLE_TEMP_ROOT(cx
, v
, &tvr
);
599 *ip
= js_ValueToECMAUint32(cx
, &tvr
.u
.value
);
600 JS_POP_TEMP_ROOT(cx
, &tvr
);
601 return !JSVAL_IS_NULL(tvr
.u
.value
);
604 JS_PUBLIC_API(JSBool
)
605 JS_ValueToInt32(JSContext
*cx
, jsval v
, int32
*ip
)
607 JSTempValueRooter tvr
;
610 JS_PUSH_SINGLE_TEMP_ROOT(cx
, v
, &tvr
);
611 *ip
= js_ValueToInt32(cx
, &tvr
.u
.value
);
612 JS_POP_TEMP_ROOT(cx
, &tvr
);
613 return !JSVAL_IS_NULL(tvr
.u
.value
);
616 JS_PUBLIC_API(JSBool
)
617 JS_ValueToUint16(JSContext
*cx
, jsval v
, uint16
*ip
)
619 JSTempValueRooter tvr
;
622 JS_PUSH_SINGLE_TEMP_ROOT(cx
, v
, &tvr
);
623 *ip
= js_ValueToUint16(cx
, &tvr
.u
.value
);
624 JS_POP_TEMP_ROOT(cx
, &tvr
);
625 return !JSVAL_IS_NULL(tvr
.u
.value
);
628 JS_PUBLIC_API(JSBool
)
629 JS_ValueToBoolean(JSContext
*cx
, jsval v
, JSBool
*bp
)
632 *bp
= js_ValueToBoolean(v
);
636 JS_PUBLIC_API(JSType
)
637 JS_TypeOfValue(JSContext
*cx
, jsval v
)
645 if (JSVAL_IS_OBJECT(v
)) {
646 type
= JSTYPE_OBJECT
; /* XXXbe JSTYPE_NULL for JS2 */
647 obj
= JSVAL_TO_OBJECT(v
);
651 wrapped
= js_GetWrappedObject(cx
, obj
);
656 #if JS_HAS_XML_SUPPORT
657 if (ops
== &js_XMLObjectOps
) {
663 * ECMA 262, 11.4.3 says that any native object that implements
664 * [[Call]] should be of type "function". However, RegExp is of
665 * type "object", not "function", for Web compatibility.
667 clasp
= OBJ_GET_CLASS(cx
, obj
);
668 if ((ops
== &js_ObjectOps
)
670 ? clasp
== &js_ScriptClass
671 : clasp
== &js_FunctionClass
)
672 : ops
->call
!= NULL
) {
673 type
= JSTYPE_FUNCTION
;
676 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
);
678 if (!OBJ_GET_PROPERTY(cx
, obj
,
679 ATOM_TO_JSID(cx
->runtime
->atomState
682 JS_ClearPendingException(cx
);
683 } else if (VALUE_IS_FUNCTION(cx
, v
)) {
684 type
= JSTYPE_FUNCTION
;
690 } else if (JSVAL_IS_NUMBER(v
)) {
691 type
= JSTYPE_NUMBER
;
692 } else if (JSVAL_IS_STRING(v
)) {
693 type
= JSTYPE_STRING
;
694 } else if (JSVAL_IS_BOOLEAN(v
)) {
695 type
= JSTYPE_BOOLEAN
;
702 JS_PUBLIC_API(const char *)
703 JS_GetTypeName(JSContext
*cx
, JSType type
)
705 if ((uintN
)type
>= (uintN
)JSTYPE_LIMIT
)
707 return JS_TYPE_STR(type
);
710 /************************************************************************/
713 * Has a new runtime ever been created? This flag is used to detect unsafe
714 * changes to js_CStringsAreUTF8 after a runtime has been created, and to
715 * ensure that "first checks" on runtime creation are run only once.
718 static JSBool js_NewRuntimeWasCalled
= JS_FALSE
;
721 JS_PUBLIC_API(JSRuntime
*)
722 JS_NewRuntime(uint32 maxbytes
)
727 if (!js_NewRuntimeWasCalled
) {
729 * This code asserts that the numbers associated with the error names
730 * in jsmsg.def are monotonically increasing. It uses values for the
731 * error names enumerated in jscntxt.c. It's not a compile-time check
732 * but it's better than nothing.
735 #define MSG_DEF(name, number, count, exception, format) \
736 JS_ASSERT(name == errorNumber++);
740 #define MSG_DEF(name, number, count, exception, format) \
742 uintN numfmtspecs = 0; \
744 for (fmt = format; *fmt != '\0'; fmt++) { \
745 if (*fmt == '{' && isdigit(fmt[1])) \
748 JS_ASSERT(count == numfmtspecs); \
754 * If it were possible for pure inline function calls with constant
755 * arguments to be computed at compile time, these would be static
756 * assertions, but since it isn't, this is the best we can do.
758 JS_ASSERT(JSVAL_NULL
== OBJECT_TO_JSVAL(NULL
));
759 JS_ASSERT(JSVAL_ZERO
== INT_TO_JSVAL(0));
760 JS_ASSERT(JSVAL_ONE
== INT_TO_JSVAL(1));
761 JS_ASSERT(JSVAL_FALSE
== BOOLEAN_TO_JSVAL(JS_FALSE
));
762 JS_ASSERT(JSVAL_TRUE
== BOOLEAN_TO_JSVAL(JS_TRUE
));
764 JS_ASSERT(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID
) == 2);
765 JS_ASSERT(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_HOLE
) == 3);
766 JS_ASSERT(JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_ARETURN
) == 4);
768 js_NewRuntimeWasCalled
= JS_TRUE
;
772 rt
= (JSRuntime
*) malloc(sizeof(JSRuntime
));
776 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
777 memset(rt
, 0, sizeof(JSRuntime
));
778 JS_INIT_CLIST(&rt
->contextList
);
779 JS_INIT_CLIST(&rt
->trapList
);
780 JS_INIT_CLIST(&rt
->watchPointList
);
784 if (!js_InitGC(rt
, maxbytes
))
786 if (!js_InitAtomState(rt
))
788 if (!js_InitDeflatedStringCache(rt
))
791 rt
->gcLock
= JS_NEW_LOCK();
794 rt
->gcDone
= JS_NEW_CONDVAR(rt
->gcLock
);
797 rt
->requestDone
= JS_NEW_CONDVAR(rt
->gcLock
);
798 if (!rt
->requestDone
)
800 /* this is asymmetric with JS_ShutDown: */
801 if (!js_SetupLocks(8, 16))
803 rt
->rtLock
= JS_NEW_LOCK();
806 rt
->stateChange
= JS_NEW_CONDVAR(rt
->gcLock
);
807 if (!rt
->stateChange
)
809 rt
->titleSharingDone
= JS_NEW_CONDVAR(rt
->gcLock
);
810 if (!rt
->titleSharingDone
)
812 rt
->titleSharingTodo
= NO_TITLE_SHARING_TODO
;
813 rt
->debuggerLock
= JS_NEW_LOCK();
814 if (!rt
->debuggerLock
)
817 if (!js_InitPropertyTree(rt
))
819 if (!js_InitThreads(rt
))
825 JS_DestroyRuntime(rt
);
830 JS_DestroyRuntime(JSRuntime
*rt
)
833 /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
834 if (!JS_CLIST_IS_EMPTY(&rt
->contextList
)) {
835 JSContext
*cx
, *iter
= NULL
;
837 while ((cx
= js_ContextIterator(rt
, JS_TRUE
, &iter
)) != NULL
) {
839 "JS API usage error: found live context at %p\n",
844 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
845 cxcount
, (cxcount
== 1) ? "" : "s");
849 js_FinishThreads(rt
);
850 js_FreeRuntimeScriptState(rt
);
851 js_FinishAtomState(rt
);
854 * Free unit string storage only after all strings have been finalized, so
855 * that js_FinalizeString can detect unit strings and avoid calling free
856 * on their chars storage.
858 js_FinishUnitStrings(rt
);
861 * Finish the deflated string cache after the last GC and after
862 * calling js_FinishAtomState, which finalizes strings.
864 js_FinishDeflatedStringCache(rt
);
868 JS_DESTROY_LOCK(rt
->gcLock
);
870 JS_DESTROY_CONDVAR(rt
->gcDone
);
872 JS_DESTROY_CONDVAR(rt
->requestDone
);
874 JS_DESTROY_LOCK(rt
->rtLock
);
876 JS_DESTROY_CONDVAR(rt
->stateChange
);
877 if (rt
->titleSharingDone
)
878 JS_DESTROY_CONDVAR(rt
->titleSharingDone
);
879 if (rt
->debuggerLock
)
880 JS_DESTROY_LOCK(rt
->debuggerLock
);
882 js_FinishPropertyTree(rt
);
890 extern void js_DumpOpMeters();
902 JS_PUBLIC_API(void *)
903 JS_GetRuntimePrivate(JSRuntime
*rt
)
909 JS_SetRuntimePrivate(JSRuntime
*rt
, void *data
)
915 JS_BeginRequest(JSContext
*cx
)
920 JS_ASSERT(CURRENT_THREAD_IS_ME(cx
->thread
));
921 if (!cx
->requestDepth
) {
922 JS_ASSERT(cx
->gcLocalFreeLists
== &js_GCEmptyFreeListSet
);
924 /* Wait until the GC is finished. */
928 if (rt
->gcThread
!= cx
->thread
) {
929 while (rt
->gcLevel
> 0)
930 JS_AWAIT_GC_DONE(rt
);
933 /* Indicate that a request is running. */
935 cx
->requestDepth
= 1;
936 cx
->outstandingRequests
++;
941 cx
->outstandingRequests
++;
946 JS_EndRequest(JSContext
*cx
)
952 JS_ASSERT(CURRENT_THREAD_IS_ME(cx
->thread
));
953 JS_ASSERT(cx
->requestDepth
> 0);
954 JS_ASSERT(cx
->outstandingRequests
> 0);
955 if (cx
->requestDepth
== 1) {
956 js_LeaveTrace(cx
); /* for GC safety */
958 /* Lock before clearing to interlock with ClaimScope, in jslock.c. */
961 cx
->requestDepth
= 0;
962 cx
->outstandingRequests
--;
964 js_ShareWaitingTitles(cx
);
965 js_RevokeGCLocalFreeLists(cx
);
967 /* Give the GC a chance to run if this was the last request running. */
968 JS_ASSERT(rt
->requestCount
> 0);
970 if (rt
->requestCount
== 0)
971 JS_NOTIFY_REQUEST_DONE(rt
);
978 cx
->outstandingRequests
--;
982 /* Yield to pending GC operations, regardless of request depth */
984 JS_YieldRequest(JSContext
*cx
)
987 JS_ASSERT(cx
->thread
);
989 JS_ResumeRequest(cx
, JS_SuspendRequest(cx
));
993 JS_PUBLIC_API(jsrefcount
)
994 JS_SuspendRequest(JSContext
*cx
)
997 jsrefcount saveDepth
= cx
->requestDepth
;
999 while (cx
->requestDepth
) {
1000 cx
->outstandingRequests
++; /* compensate for JS_EndRequest */
1010 JS_ResumeRequest(JSContext
*cx
, jsrefcount saveDepth
)
1012 #ifdef JS_THREADSAFE
1013 JS_ASSERT(!cx
->requestDepth
);
1014 while (--saveDepth
>= 0) {
1015 JS_BeginRequest(cx
);
1016 cx
->outstandingRequests
--; /* compensate for JS_BeginRequest */
1022 JS_Lock(JSRuntime
*rt
)
1024 JS_LOCK_RUNTIME(rt
);
1028 JS_Unlock(JSRuntime
*rt
)
1030 JS_UNLOCK_RUNTIME(rt
);
1033 JS_PUBLIC_API(JSContextCallback
)
1034 JS_SetContextCallback(JSRuntime
*rt
, JSContextCallback cxCallback
)
1036 JSContextCallback old
;
1038 old
= rt
->cxCallback
;
1039 rt
->cxCallback
= cxCallback
;
1043 JS_PUBLIC_API(JSContext
*)
1044 JS_NewContext(JSRuntime
*rt
, size_t stackChunkSize
)
1046 return js_NewContext(rt
, stackChunkSize
);
1050 JS_DestroyContext(JSContext
*cx
)
1052 js_DestroyContext(cx
, JSDCM_FORCE_GC
);
1056 JS_DestroyContextNoGC(JSContext
*cx
)
1058 js_DestroyContext(cx
, JSDCM_NO_GC
);
1062 JS_DestroyContextMaybeGC(JSContext
*cx
)
1064 js_DestroyContext(cx
, JSDCM_MAYBE_GC
);
1067 JS_PUBLIC_API(void *)
1068 JS_GetContextPrivate(JSContext
*cx
)
1074 JS_SetContextPrivate(JSContext
*cx
, void *data
)
1079 JS_PUBLIC_API(JSRuntime
*)
1080 JS_GetRuntime(JSContext
*cx
)
1085 JS_PUBLIC_API(JSContext
*)
1086 JS_ContextIterator(JSRuntime
*rt
, JSContext
**iterp
)
1088 return js_ContextIterator(rt
, JS_TRUE
, iterp
);
1091 JS_PUBLIC_API(JSVersion
)
1092 JS_GetVersion(JSContext
*cx
)
1094 return JSVERSION_NUMBER(cx
);
1097 JS_PUBLIC_API(JSVersion
)
1098 JS_SetVersion(JSContext
*cx
, JSVersion version
)
1100 JSVersion oldVersion
;
1102 JS_ASSERT(version
!= JSVERSION_UNKNOWN
);
1103 JS_ASSERT((version
& ~JSVERSION_MASK
) == 0);
1105 oldVersion
= JSVERSION_NUMBER(cx
);
1106 if (version
== oldVersion
)
1109 /* We no longer support 1.4 or below. */
1110 if (version
!= JSVERSION_DEFAULT
&& version
<= JSVERSION_1_4
)
1113 cx
->version
= (cx
->version
& ~JSVERSION_MASK
) | version
;
1114 js_OnVersionChange(cx
);
1118 static struct v2smap
{
1122 {JSVERSION_1_0
, "1.0"},
1123 {JSVERSION_1_1
, "1.1"},
1124 {JSVERSION_1_2
, "1.2"},
1125 {JSVERSION_1_3
, "1.3"},
1126 {JSVERSION_1_4
, "1.4"},
1127 {JSVERSION_ECMA_3
, "ECMAv3"},
1128 {JSVERSION_1_5
, "1.5"},
1129 {JSVERSION_1_6
, "1.6"},
1130 {JSVERSION_1_7
, "1.7"},
1131 {JSVERSION_1_8
, "1.8"},
1132 {JSVERSION_DEFAULT
, js_default_str
},
1133 {JSVERSION_UNKNOWN
, NULL
}, /* must be last, NULL is sentinel */
1136 JS_PUBLIC_API(const char *)
1137 JS_VersionToString(JSVersion version
)
1141 for (i
= 0; v2smap
[i
].string
; i
++)
1142 if (v2smap
[i
].version
== version
)
1143 return v2smap
[i
].string
;
1147 JS_PUBLIC_API(JSVersion
)
1148 JS_StringToVersion(const char *string
)
1152 for (i
= 0; v2smap
[i
].string
; i
++)
1153 if (strcmp(v2smap
[i
].string
, string
) == 0)
1154 return v2smap
[i
].version
;
1155 return JSVERSION_UNKNOWN
;
1158 JS_PUBLIC_API(uint32
)
1159 JS_GetOptions(JSContext
*cx
)
1164 JS_PUBLIC_API(uint32
)
1165 JS_SetOptions(JSContext
*cx
, uint32 options
)
1167 uint32 oldopts
= cx
->options
;
1168 cx
->options
= options
;
1169 js_SyncOptionsToVersion(cx
);
1173 JS_PUBLIC_API(uint32
)
1174 JS_ToggleOptions(JSContext
*cx
, uint32 options
)
1176 uint32 oldopts
= cx
->options
;
1177 cx
->options
^= options
;
1178 js_SyncOptionsToVersion(cx
);
1182 JS_PUBLIC_API(const char *)
1183 JS_GetImplementationVersion(void)
1185 return "JavaScript-C 1.8.0 pre-release 1 2007-10-03";
1189 JS_PUBLIC_API(JSObject
*)
1190 JS_GetGlobalObject(JSContext
*cx
)
1192 return cx
->globalObject
;
1196 JS_SetGlobalObject(JSContext
*cx
, JSObject
*obj
)
1198 cx
->globalObject
= obj
;
1200 #if JS_HAS_XML_SUPPORT
1201 cx
->xmlSettingFlags
= 0;
1208 js_InitFunctionAndObjectClasses(JSContext
*cx
, JSObject
*obj
)
1210 JSDHashTable
*table
;
1214 JSResolvingEntry
*entry
;
1215 JSObject
*fun_proto
, *obj_proto
;
1217 /* If cx has no global object, use obj so prototypes can be found. */
1218 if (!cx
->globalObject
)
1219 JS_SetGlobalObject(cx
, obj
);
1221 /* Record Function and Object in cx->resolvingTable, if we are resolving. */
1222 table
= cx
->resolvingTable
;
1223 resolving
= (table
&& table
->entryCount
);
1227 key
.id
= ATOM_TO_JSID(rt
->atomState
.classAtoms
[JSProto_Function
]);
1228 entry
= (JSResolvingEntry
*)
1229 JS_DHashTableOperate(table
, &key
, JS_DHASH_ADD
);
1230 if (entry
&& entry
->key
.obj
&& (entry
->flags
& JSRESFLAG_LOOKUP
)) {
1231 /* Already resolving Function, record Object too. */
1232 JS_ASSERT(entry
->key
.obj
== obj
);
1233 key
.id
= ATOM_TO_JSID(rt
->atomState
.classAtoms
[JSProto_Object
]);
1234 entry
= (JSResolvingEntry
*)
1235 JS_DHashTableOperate(table
, &key
, JS_DHASH_ADD
);
1238 JS_ReportOutOfMemory(cx
);
1241 JS_ASSERT(!entry
->key
.obj
&& entry
->flags
== 0);
1243 entry
->flags
= JSRESFLAG_LOOKUP
;
1245 key
.id
= ATOM_TO_JSID(rt
->atomState
.classAtoms
[JSProto_Object
]);
1246 if (!js_StartResolving(cx
, &key
, JSRESFLAG_LOOKUP
, &entry
))
1249 key
.id
= ATOM_TO_JSID(rt
->atomState
.classAtoms
[JSProto_Function
]);
1250 if (!js_StartResolving(cx
, &key
, JSRESFLAG_LOOKUP
, &entry
)) {
1251 key
.id
= ATOM_TO_JSID(rt
->atomState
.classAtoms
[JSProto_Object
]);
1252 JS_DHashTableOperate(table
, &key
, JS_DHASH_REMOVE
);
1256 table
= cx
->resolvingTable
;
1259 /* Initialize the function class first so constructors can be made. */
1260 if (!js_GetClassPrototype(cx
, obj
, INT_TO_JSID(JSProto_Function
),
1266 fun_proto
= js_InitFunctionClass(cx
, obj
);
1272 ctor
= JS_GetConstructor(cx
, fun_proto
);
1277 OBJ_DEFINE_PROPERTY(cx
, obj
, ATOM_TO_JSID(CLASS_ATOM(cx
, Function
)),
1278 OBJECT_TO_JSVAL(ctor
), 0, 0, 0, NULL
);
1281 /* Initialize the object class next so Object.prototype works. */
1282 if (!js_GetClassPrototype(cx
, obj
, INT_TO_JSID(JSProto_Object
),
1288 obj_proto
= js_InitObjectClass(cx
, obj
);
1294 /* Function.prototype and the global object delegate to Object.prototype. */
1295 OBJ_SET_PROTO(cx
, fun_proto
, obj_proto
);
1296 if (!OBJ_GET_PROTO(cx
, obj
))
1297 OBJ_SET_PROTO(cx
, obj
, obj_proto
);
1300 /* If resolving, remove the other entry (Object or Function) from table. */
1301 JS_DHashTableOperate(table
, &key
, JS_DHASH_REMOVE
);
1303 /* If not resolving, remove the first entry added above, for Object. */
1304 JS_ASSERT(key
.id
== \
1305 ATOM_TO_JSID(rt
->atomState
.classAtoms
[JSProto_Function
]));
1306 key
.id
= ATOM_TO_JSID(rt
->atomState
.classAtoms
[JSProto_Object
]);
1307 JS_DHashTableOperate(table
, &key
, JS_DHASH_REMOVE
);
1314 JS_PUBLIC_API(JSBool
)
1315 JS_InitStandardClasses(JSContext
*cx
, JSObject
*obj
)
1321 /* Define a top-level property 'undefined' with the undefined value. */
1322 atom
= cx
->runtime
->atomState
.typeAtoms
[JSTYPE_VOID
];
1323 if (!OBJ_DEFINE_PROPERTY(cx
, obj
, ATOM_TO_JSID(atom
), JSVAL_VOID
,
1324 JS_PropertyStub
, JS_PropertyStub
, JSPROP_PERMANENT
,
1329 /* Function and Object require cooperative bootstrapping magic. */
1330 if (!js_InitFunctionAndObjectClasses(cx
, obj
))
1333 /* Initialize the rest of the standard objects and functions. */
1334 return js_InitArrayClass(cx
, obj
) &&
1335 js_InitBlockClass(cx
, obj
) &&
1336 js_InitBooleanClass(cx
, obj
) &&
1337 js_InitExceptionClasses(cx
, obj
) &&
1338 js_InitMathClass(cx
, obj
) &&
1339 js_InitNumberClass(cx
, obj
) &&
1340 js_InitJSONClass(cx
, obj
) &&
1341 js_InitRegExpClass(cx
, obj
) &&
1342 js_InitStringClass(cx
, obj
) &&
1343 js_InitEval(cx
, obj
) &&
1344 #if JS_HAS_SCRIPT_OBJECT
1345 js_InitScriptClass(cx
, obj
) &&
1347 #if JS_HAS_XML_SUPPORT
1348 js_InitXMLClasses(cx
, obj
) &&
1350 #if JS_HAS_FILE_OBJECT
1351 js_InitFileClass(cx
, obj
) &&
1353 #if JS_HAS_GENERATORS
1354 js_InitIteratorClasses(cx
, obj
) &&
1356 js_InitDateClass(cx
, obj
);
1359 #define CLASP(name) (&js_##name##Class)
1360 #define EXT_CLASP(name) (&js_##name##Class.base)
1361 #define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
1362 #define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
1363 #define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
1364 #define EAGER_ATOM_AND_EXT_CLASP(name) EAGER_CLASS_ATOM(name), EXT_CLASP(name)
1365 #define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
1367 typedef struct JSStdName
{
1369 size_t atomOffset
; /* offset of atom pointer in JSAtomState */
1370 const char *name
; /* null if atom is pre-pinned, else name */
1375 StdNameToAtom(JSContext
*cx
, JSStdName
*stdn
)
1381 offset
= stdn
->atomOffset
;
1382 atom
= OFFSET_TO_ATOM(cx
->runtime
, offset
);
1386 atom
= js_Atomize(cx
, name
, strlen(name
), ATOM_PINNED
);
1387 OFFSET_TO_ATOM(cx
->runtime
, offset
) = atom
;
1394 * Table of class initializers and their atom offsets in rt->atomState.
1395 * If you add a "standard" class, remember to update this table.
1397 static JSStdName standard_class_atoms
[] = {
1398 {js_InitFunctionAndObjectClasses
, EAGER_ATOM_AND_CLASP(Function
)},
1399 {js_InitFunctionAndObjectClasses
, EAGER_ATOM_AND_CLASP(Object
)},
1400 {js_InitArrayClass
, EAGER_ATOM_AND_CLASP(Array
)},
1401 {js_InitBlockClass
, EAGER_ATOM_AND_CLASP(Block
)},
1402 {js_InitBooleanClass
, EAGER_ATOM_AND_CLASP(Boolean
)},
1403 {js_InitDateClass
, EAGER_ATOM_AND_CLASP(Date
)},
1404 {js_InitMathClass
, EAGER_ATOM_AND_CLASP(Math
)},
1405 {js_InitNumberClass
, EAGER_ATOM_AND_CLASP(Number
)},
1406 {js_InitStringClass
, EAGER_ATOM_AND_CLASP(String
)},
1407 {js_InitExceptionClasses
, EAGER_ATOM_AND_CLASP(Error
)},
1408 {js_InitRegExpClass
, EAGER_ATOM_AND_CLASP(RegExp
)},
1409 #if JS_HAS_SCRIPT_OBJECT
1410 {js_InitScriptClass
, EAGER_ATOM_AND_CLASP(Script
)},
1412 #if JS_HAS_XML_SUPPORT
1413 {js_InitXMLClass
, EAGER_ATOM_AND_CLASP(XML
)},
1414 {js_InitNamespaceClass
, EAGER_ATOM_AND_EXT_CLASP(Namespace
)},
1415 {js_InitQNameClass
, EAGER_ATOM_AND_EXT_CLASP(QName
)},
1417 #if JS_HAS_FILE_OBJECT
1418 {js_InitFileClass
, EAGER_ATOM_AND_CLASP(File
)},
1420 #if JS_HAS_GENERATORS
1421 {js_InitIteratorClasses
, EAGER_ATOM_AND_CLASP(StopIteration
)},
1423 {js_InitJSONClass
, EAGER_ATOM_AND_CLASP(JSON
)},
1424 {NULL
, 0, NULL
, NULL
}
1428 * Table of top-level function and constant names and their init functions.
1429 * If you add a "standard" global function or property, remember to update
1432 static JSStdName standard_class_names
[] = {
1433 /* ECMA requires that eval be a direct property of the global object. */
1434 {js_InitEval
, EAGER_ATOM(eval
), NULL
},
1436 /* Global properties and functions defined by the Number class. */
1437 {js_InitNumberClass
, LAZY_ATOM(NaN
), NULL
},
1438 {js_InitNumberClass
, LAZY_ATOM(Infinity
), NULL
},
1439 {js_InitNumberClass
, LAZY_ATOM(isNaN
), NULL
},
1440 {js_InitNumberClass
, LAZY_ATOM(isFinite
), NULL
},
1441 {js_InitNumberClass
, LAZY_ATOM(parseFloat
), NULL
},
1442 {js_InitNumberClass
, LAZY_ATOM(parseInt
), NULL
},
1444 /* String global functions. */
1445 {js_InitStringClass
, LAZY_ATOM(escape
), NULL
},
1446 {js_InitStringClass
, LAZY_ATOM(unescape
), NULL
},
1447 {js_InitStringClass
, LAZY_ATOM(decodeURI
), NULL
},
1448 {js_InitStringClass
, LAZY_ATOM(encodeURI
), NULL
},
1449 {js_InitStringClass
, LAZY_ATOM(decodeURIComponent
), NULL
},
1450 {js_InitStringClass
, LAZY_ATOM(encodeURIComponent
), NULL
},
1452 {js_InitStringClass
, LAZY_ATOM(uneval
), NULL
},
1455 /* Exception constructors. */
1456 {js_InitExceptionClasses
, EAGER_CLASS_ATOM(Error
), CLASP(Error
)},
1457 {js_InitExceptionClasses
, EAGER_CLASS_ATOM(InternalError
), CLASP(Error
)},
1458 {js_InitExceptionClasses
, EAGER_CLASS_ATOM(EvalError
), CLASP(Error
)},
1459 {js_InitExceptionClasses
, EAGER_CLASS_ATOM(RangeError
), CLASP(Error
)},
1460 {js_InitExceptionClasses
, EAGER_CLASS_ATOM(ReferenceError
), CLASP(Error
)},
1461 {js_InitExceptionClasses
, EAGER_CLASS_ATOM(SyntaxError
), CLASP(Error
)},
1462 {js_InitExceptionClasses
, EAGER_CLASS_ATOM(TypeError
), CLASP(Error
)},
1463 {js_InitExceptionClasses
, EAGER_CLASS_ATOM(URIError
), CLASP(Error
)},
1465 #if JS_HAS_XML_SUPPORT
1466 {js_InitAnyNameClass
, EAGER_ATOM_AND_CLASP(AnyName
)},
1467 {js_InitAttributeNameClass
, EAGER_ATOM_AND_CLASP(AttributeName
)},
1468 {js_InitXMLClass
, LAZY_ATOM(XMLList
), &js_XMLClass
},
1469 {js_InitXMLClass
, LAZY_ATOM(isXMLName
), NULL
},
1472 #if JS_HAS_GENERATORS
1473 {js_InitIteratorClasses
, EAGER_ATOM_AND_CLASP(Iterator
)},
1474 {js_InitIteratorClasses
, EAGER_ATOM_AND_CLASP(Generator
)},
1477 {NULL
, 0, NULL
, NULL
}
1480 static JSStdName object_prototype_names
[] = {
1481 /* Object.prototype properties (global delegates to Object.prototype). */
1482 {js_InitObjectClass
, EAGER_ATOM(proto
), NULL
},
1483 {js_InitObjectClass
, EAGER_ATOM(parent
), NULL
},
1484 {js_InitObjectClass
, EAGER_ATOM(count
), NULL
},
1486 {js_InitObjectClass
, EAGER_ATOM(toSource
), NULL
},
1488 {js_InitObjectClass
, EAGER_ATOM(toString
), NULL
},
1489 {js_InitObjectClass
, EAGER_ATOM(toLocaleString
), NULL
},
1490 {js_InitObjectClass
, EAGER_ATOM(valueOf
), NULL
},
1491 #if JS_HAS_OBJ_WATCHPOINT
1492 {js_InitObjectClass
, LAZY_ATOM(watch
), NULL
},
1493 {js_InitObjectClass
, LAZY_ATOM(unwatch
), NULL
},
1495 {js_InitObjectClass
, LAZY_ATOM(hasOwnProperty
), NULL
},
1496 {js_InitObjectClass
, LAZY_ATOM(isPrototypeOf
), NULL
},
1497 {js_InitObjectClass
, LAZY_ATOM(propertyIsEnumerable
), NULL
},
1498 #if JS_HAS_GETTER_SETTER
1499 {js_InitObjectClass
, LAZY_ATOM(defineGetter
), NULL
},
1500 {js_InitObjectClass
, LAZY_ATOM(defineSetter
), NULL
},
1501 {js_InitObjectClass
, LAZY_ATOM(lookupGetter
), NULL
},
1502 {js_InitObjectClass
, LAZY_ATOM(lookupSetter
), NULL
},
1505 {NULL
, 0, NULL
, NULL
}
1508 JS_PUBLIC_API(JSBool
)
1509 JS_ResolveStandardClass(JSContext
*cx
, JSObject
*obj
, jsval id
,
1519 *resolved
= JS_FALSE
;
1522 JS_ASSERT(rt
->state
!= JSRTS_DOWN
);
1523 if (rt
->state
== JSRTS_LANDING
|| !JSVAL_IS_STRING(id
))
1526 idstr
= JSVAL_TO_STRING(id
);
1528 /* Check whether we're resolving 'undefined', and define it if so. */
1529 atom
= rt
->atomState
.typeAtoms
[JSTYPE_VOID
];
1530 if (idstr
== ATOM_TO_STRING(atom
)) {
1531 *resolved
= JS_TRUE
;
1532 return OBJ_DEFINE_PROPERTY(cx
, obj
, ATOM_TO_JSID(atom
), JSVAL_VOID
,
1533 JS_PropertyStub
, JS_PropertyStub
,
1534 JSPROP_PERMANENT
, NULL
);
1537 /* Try for class constructors/prototypes named by well-known atoms. */
1539 for (i
= 0; standard_class_atoms
[i
].init
; i
++) {
1540 atom
= OFFSET_TO_ATOM(rt
, standard_class_atoms
[i
].atomOffset
);
1541 if (idstr
== ATOM_TO_STRING(atom
)) {
1542 stdnm
= &standard_class_atoms
[i
];
1548 /* Try less frequently used top-level functions and constants. */
1549 for (i
= 0; standard_class_names
[i
].init
; i
++) {
1550 atom
= StdNameToAtom(cx
, &standard_class_names
[i
]);
1553 if (idstr
== ATOM_TO_STRING(atom
)) {
1554 stdnm
= &standard_class_names
[i
];
1559 if (!stdnm
&& !OBJ_GET_PROTO(cx
, obj
)) {
1561 * Try even less frequently used names delegated from the global
1562 * object to Object.prototype, but only if the Object class hasn't
1563 * yet been initialized.
1565 for (i
= 0; object_prototype_names
[i
].init
; i
++) {
1566 atom
= StdNameToAtom(cx
, &object_prototype_names
[i
]);
1569 if (idstr
== ATOM_TO_STRING(atom
)) {
1570 stdnm
= &standard_class_names
[i
];
1579 * If this standard class is anonymous and obj advertises itself as a
1580 * global object (in order to reserve slots for standard class object
1581 * pointers), then we don't want to resolve by name.
1583 * If inversely, either id does not name a class, or id does not name
1584 * an anonymous class, or the global does not reserve slots for class
1585 * objects, then we must call the init hook here.
1588 (stdnm
->clasp
->flags
& JSCLASS_IS_ANONYMOUS
) &&
1589 (OBJ_GET_CLASS(cx
, obj
)->flags
& JSCLASS_IS_GLOBAL
)) {
1593 if (!stdnm
->init(cx
, obj
))
1595 *resolved
= JS_TRUE
;
1601 AlreadyHasOwnProperty(JSContext
*cx
, JSObject
*obj
, JSAtom
*atom
)
1603 JSScopeProperty
*sprop
;
1606 JS_ASSERT(OBJ_IS_NATIVE(obj
));
1607 JS_LOCK_OBJ(cx
, obj
);
1608 scope
= OBJ_SCOPE(obj
);
1609 sprop
= SCOPE_GET_PROPERTY(scope
, ATOM_TO_JSID(atom
));
1610 JS_UNLOCK_SCOPE(cx
, scope
);
1611 return sprop
!= NULL
;
1614 JS_PUBLIC_API(JSBool
)
1615 JS_EnumerateStandardClasses(JSContext
*cx
, JSObject
*obj
)
1624 /* Check whether we need to bind 'undefined' and define it if so. */
1625 atom
= rt
->atomState
.typeAtoms
[JSTYPE_VOID
];
1626 if (!AlreadyHasOwnProperty(cx
, obj
, atom
) &&
1627 !OBJ_DEFINE_PROPERTY(cx
, obj
, ATOM_TO_JSID(atom
), JSVAL_VOID
,
1628 JS_PropertyStub
, JS_PropertyStub
, JSPROP_PERMANENT
,
1633 /* Initialize any classes that have not been resolved yet. */
1634 for (i
= 0; standard_class_atoms
[i
].init
; i
++) {
1635 atom
= OFFSET_TO_ATOM(rt
, standard_class_atoms
[i
].atomOffset
);
1636 if (!AlreadyHasOwnProperty(cx
, obj
, atom
) &&
1637 !standard_class_atoms
[i
].init(cx
, obj
)) {
1646 NewIdArray(JSContext
*cx
, jsint length
)
1651 JS_malloc(cx
, offsetof(JSIdArray
, vector
) + length
* sizeof(jsval
));
1653 ida
->length
= length
;
1658 * Unlike realloc(3), this function frees ida on failure.
1661 SetIdArrayLength(JSContext
*cx
, JSIdArray
*ida
, jsint length
)
1665 rida
= (JSIdArray
*)
1667 offsetof(JSIdArray
, vector
) + length
* sizeof(jsval
));
1669 JS_DestroyIdArray(cx
, ida
);
1671 rida
->length
= length
;
1676 AddAtomToArray(JSContext
*cx
, JSAtom
*atom
, JSIdArray
*ida
, jsint
*ip
)
1681 length
= ida
->length
;
1683 ida
= SetIdArrayLength(cx
, ida
, JS_MAX(length
* 2, 8));
1686 JS_ASSERT(i
< ida
->length
);
1688 ida
->vector
[i
] = ATOM_TO_JSID(atom
);
1694 EnumerateIfResolved(JSContext
*cx
, JSObject
*obj
, JSAtom
*atom
, JSIdArray
*ida
,
1695 jsint
*ip
, JSBool
*foundp
)
1697 *foundp
= AlreadyHasOwnProperty(cx
, obj
, atom
);
1699 ida
= AddAtomToArray(cx
, atom
, ida
, ip
);
1703 JS_PUBLIC_API(JSIdArray
*)
1704 JS_EnumerateResolvedStandardClasses(JSContext
*cx
, JSObject
*obj
,
1718 ida
= NewIdArray(cx
, 8);
1724 /* Check whether 'undefined' has been resolved and enumerate it if so. */
1725 atom
= rt
->atomState
.typeAtoms
[JSTYPE_VOID
];
1726 ida
= EnumerateIfResolved(cx
, obj
, atom
, ida
, &i
, &found
);
1730 /* Enumerate only classes that *have* been resolved. */
1731 for (j
= 0; standard_class_atoms
[j
].init
; j
++) {
1732 atom
= OFFSET_TO_ATOM(rt
, standard_class_atoms
[j
].atomOffset
);
1733 ida
= EnumerateIfResolved(cx
, obj
, atom
, ida
, &i
, &found
);
1738 init
= standard_class_atoms
[j
].init
;
1740 for (k
= 0; standard_class_names
[k
].init
; k
++) {
1741 if (standard_class_names
[k
].init
== init
) {
1742 atom
= StdNameToAtom(cx
, &standard_class_names
[k
]);
1743 ida
= AddAtomToArray(cx
, atom
, ida
, &i
);
1749 if (init
== js_InitObjectClass
) {
1750 for (k
= 0; object_prototype_names
[k
].init
; k
++) {
1751 atom
= StdNameToAtom(cx
, &object_prototype_names
[k
]);
1752 ida
= AddAtomToArray(cx
, atom
, ida
, &i
);
1760 /* Trim to exact length. */
1761 return SetIdArrayLength(cx
, ida
, i
);
1766 #undef EAGER_CLASS_ATOM
1767 #undef EAGER_ATOM_CLASP
1770 JS_PUBLIC_API(JSBool
)
1771 JS_GetClassObject(JSContext
*cx
, JSObject
*obj
, JSProtoKey key
,
1775 return js_GetClassObject(cx
, obj
, key
, objp
);
1778 JS_PUBLIC_API(JSObject
*)
1779 JS_GetScopeChain(JSContext
*cx
)
1784 fp
= js_GetTopStackFrame(cx
);
1787 * There is no code active on this context. In place of an actual
1788 * scope chain, use the context's global object, which is set in
1789 * js_InitFunctionAndObjectClasses, and which represents the default
1790 * scope chain for the embedding. See also js_FindClassObject.
1792 * For embeddings that use the inner and outer object hooks, the inner
1793 * object represents the ultimate global object, with the outer object
1794 * acting as a stand-in.
1796 JSObject
*obj
= cx
->globalObject
;
1798 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_INACTIVE
);
1802 OBJ_TO_INNER_OBJECT(cx
, obj
);
1805 return js_GetScopeChain(cx
, fp
);
1808 JS_PUBLIC_API(JSObject
*)
1809 JS_GetGlobalForObject(JSContext
*cx
, JSObject
*obj
)
1813 while ((parent
= OBJ_GET_PARENT(cx
, obj
)) != NULL
)
1818 JS_PUBLIC_API(jsval
)
1819 JS_ComputeThis(JSContext
*cx
, jsval
*vp
)
1821 if (!js_ComputeThis(cx
, JS_FALSE
, vp
+ 2))
1826 JS_PUBLIC_API(void *)
1827 JS_malloc(JSContext
*cx
, size_t nbytes
)
1831 JS_ASSERT(nbytes
!= 0);
1837 JS_ReportOutOfMemory(cx
);
1840 js_UpdateMallocCounter(cx
, nbytes
);
1845 JS_PUBLIC_API(void *)
1846 JS_realloc(JSContext
*cx
, void *p
, size_t nbytes
)
1849 p
= realloc(p
, nbytes
);
1851 JS_ReportOutOfMemory(cx
);
1855 js_UpdateMallocCounter(cx
, nbytes
);
1860 JS_free(JSContext
*cx
, void *p
)
1866 JS_PUBLIC_API(char *)
1867 JS_strdup(JSContext
*cx
, const char *s
)
1873 p
= JS_malloc(cx
, n
);
1876 return (char *)memcpy(p
, s
, n
);
1879 JS_PUBLIC_API(jsdouble
*)
1880 JS_NewDouble(JSContext
*cx
, jsdouble d
)
1883 return js_NewWeaklyRootedDouble(cx
, d
);
1886 JS_PUBLIC_API(JSBool
)
1887 JS_NewDoubleValue(JSContext
*cx
, jsdouble d
, jsval
*rval
)
1892 dp
= js_NewWeaklyRootedDouble(cx
, d
);
1895 *rval
= DOUBLE_TO_JSVAL(dp
);
1899 JS_PUBLIC_API(JSBool
)
1900 JS_NewNumberValue(JSContext
*cx
, jsdouble d
, jsval
*rval
)
1903 return js_NewWeaklyRootedNumber(cx
, d
, rval
);
1907 JS_PUBLIC_API(JSBool
)
1908 JS_AddRoot(JSContext
*cx
, void *rp
)
1911 return js_AddRoot(cx
, rp
, NULL
);
1914 JS_PUBLIC_API(JSBool
)
1915 JS_AddNamedRootRT(JSRuntime
*rt
, void *rp
, const char *name
)
1917 return js_AddRootRT(rt
, rp
, name
);
1920 JS_PUBLIC_API(JSBool
)
1921 JS_RemoveRoot(JSContext
*cx
, void *rp
)
1924 return js_RemoveRoot(cx
->runtime
, rp
);
1927 JS_PUBLIC_API(JSBool
)
1928 JS_RemoveRootRT(JSRuntime
*rt
, void *rp
)
1930 return js_RemoveRoot(rt
, rp
);
1933 JS_PUBLIC_API(JSBool
)
1934 JS_AddNamedRoot(JSContext
*cx
, void *rp
, const char *name
)
1937 return js_AddRoot(cx
, rp
, name
);
1941 JS_ClearNewbornRoots(JSContext
*cx
)
1943 JS_CLEAR_WEAK_ROOTS(&cx
->weakRoots
);
1946 JS_PUBLIC_API(JSBool
)
1947 JS_EnterLocalRootScope(JSContext
*cx
)
1950 return js_EnterLocalRootScope(cx
);
1954 JS_LeaveLocalRootScope(JSContext
*cx
)
1957 js_LeaveLocalRootScope(cx
);
1961 JS_LeaveLocalRootScopeWithResult(JSContext
*cx
, jsval rval
)
1964 js_LeaveLocalRootScopeWithResult(cx
, rval
);
1968 JS_ForgetLocalRoot(JSContext
*cx
, void *thing
)
1971 js_ForgetLocalRoot(cx
, (jsval
) thing
);
1977 JS_DumpNamedRoots(JSRuntime
*rt
,
1978 void (*dump
)(const char *name
, void *rp
, void *data
),
1981 js_DumpNamedRoots(rt
, dump
, data
);
1986 JS_PUBLIC_API(uint32
)
1987 JS_MapGCRoots(JSRuntime
*rt
, JSGCRootMapFun map
, void *data
)
1989 return js_MapGCRoots(rt
, map
, data
);
1992 JS_PUBLIC_API(JSBool
)
1993 JS_LockGCThing(JSContext
*cx
, void *thing
)
1998 ok
= js_LockGCThingRT(cx
->runtime
, thing
);
2000 JS_ReportOutOfMemory(cx
);
2004 JS_PUBLIC_API(JSBool
)
2005 JS_LockGCThingRT(JSRuntime
*rt
, void *thing
)
2007 return js_LockGCThingRT(rt
, thing
);
2010 JS_PUBLIC_API(JSBool
)
2011 JS_UnlockGCThing(JSContext
*cx
, void *thing
)
2016 ok
= js_UnlockGCThingRT(cx
->runtime
, thing
);
2018 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_CANT_UNLOCK
);
2022 JS_PUBLIC_API(JSBool
)
2023 JS_UnlockGCThingRT(JSRuntime
*rt
, void *thing
)
2025 return js_UnlockGCThingRT(rt
, thing
);
2029 JS_SetExtraGCRoots(JSRuntime
*rt
, JSTraceDataOp traceOp
, void *data
)
2031 rt
->gcExtraRootsTraceOp
= traceOp
;
2032 rt
->gcExtraRootsData
= data
;
2036 JS_TraceRuntime(JSTracer
*trc
)
2038 JSBool allAtoms
= trc
->context
->runtime
->gcKeepAtoms
!= 0;
2040 js_LeaveTrace(trc
->context
);
2041 js_TraceRuntime(trc
, allAtoms
);
2046 #ifdef HAVE_XPCONNECT
2047 #include "dump_xpc.h"
2051 JS_PrintTraceThingInfo(char *buf
, size_t bufsize
, JSTracer
*trc
,
2052 void *thing
, uint32 kind
, JSBool details
)
2061 case JSTRACE_OBJECT
:
2063 JSObject
*obj
= (JSObject
*)thing
;
2064 JSClass
*clasp
= STOBJ_GET_CLASS(obj
);
2067 #ifdef HAVE_XPCONNECT
2068 if (clasp
->flags
& JSCLASS_PRIVATE_IS_NSISUPPORTS
) {
2069 jsval privateValue
= STOBJ_GET_SLOT(obj
, JSSLOT_PRIVATE
);
2071 JS_ASSERT(clasp
->flags
& JSCLASS_HAS_PRIVATE
);
2072 if (!JSVAL_IS_VOID(privateValue
)) {
2073 void *privateThing
= JSVAL_TO_PRIVATE(privateValue
);
2074 const char *xpcClassName
= GetXPCObjectClassName(privateThing
);
2077 name
= xpcClassName
;
2084 case JSTRACE_STRING
:
2085 name
= JSSTRING_IS_DEPENDENT((JSString
*)thing
)
2090 case JSTRACE_DOUBLE
:
2094 #if JS_HAS_XML_SUPPORT
2106 if (n
> bufsize
- 1)
2108 memcpy(buf
, name
, n
+ 1);
2112 if (details
&& bufsize
> 2) {
2117 case JSTRACE_OBJECT
:
2119 JSObject
*obj
= (JSObject
*)thing
;
2120 JSClass
*clasp
= STOBJ_GET_CLASS(obj
);
2121 if (clasp
== &js_FunctionClass
) {
2122 JSFunction
*fun
= (JSFunction
*)
2123 JS_GetPrivate(trc
->context
, obj
);
2126 JS_snprintf(buf
, bufsize
, "<newborn>");
2127 } else if (FUN_OBJECT(fun
) != obj
) {
2128 JS_snprintf(buf
, bufsize
, "%p", fun
);
2130 if (fun
->atom
&& ATOM_IS_STRING(fun
->atom
))
2131 js_PutEscapedString(buf
, bufsize
,
2132 ATOM_TO_STRING(fun
->atom
), 0);
2134 } else if (clasp
->flags
& JSCLASS_HAS_PRIVATE
) {
2135 jsval privateValue
= STOBJ_GET_SLOT(obj
, JSSLOT_PRIVATE
);
2136 void *privateThing
= JSVAL_IS_VOID(privateValue
)
2138 : JSVAL_TO_PRIVATE(privateValue
);
2140 JS_snprintf(buf
, bufsize
, "%p", privateThing
);
2142 JS_snprintf(buf
, bufsize
, "<no private>");
2147 case JSTRACE_STRING
:
2148 js_PutEscapedString(buf
, bufsize
, (JSString
*)thing
, 0);
2151 case JSTRACE_DOUBLE
:
2152 JS_snprintf(buf
, bufsize
, "%g", *(jsdouble
*)thing
);
2155 #if JS_HAS_XML_SUPPORT
2158 extern const char *js_xml_class_str
[];
2159 JSXML
*xml
= (JSXML
*)thing
;
2161 JS_snprintf(buf
, bufsize
, "%s", js_xml_class_str
[xml
->xml_class
]);
2170 buf
[bufsize
- 1] = '\0';
2173 typedef struct JSHeapDumpNode JSHeapDumpNode
;
2175 struct JSHeapDumpNode
{
2178 JSHeapDumpNode
*next
; /* next sibling */
2179 JSHeapDumpNode
*parent
; /* node with the thing that refer to thing
2181 char edgeName
[1]; /* name of the edge from parent->thing
2185 typedef struct JSDumpingTracer
{
2187 JSDHashTable visited
;
2191 void *thingToIgnore
;
2192 JSHeapDumpNode
*parentNode
;
2193 JSHeapDumpNode
**lastNodep
;
2198 DumpNotify(JSTracer
*trc
, void *thing
, uint32 kind
)
2200 JSDumpingTracer
*dtrc
;
2202 JSDHashEntryStub
*entry
;
2203 JSHeapDumpNode
*node
;
2204 const char *edgeName
;
2205 size_t edgeNameSize
;
2207 JS_ASSERT(trc
->callback
== DumpNotify
);
2208 dtrc
= (JSDumpingTracer
*)trc
;
2210 if (!dtrc
->ok
|| thing
== dtrc
->thingToIgnore
)
2216 * Check if we have already seen thing unless it is thingToFind to include
2217 * it to the graph each time we reach it and print all live things that
2218 * refer to thingToFind.
2220 * This does not print all possible paths leading to thingToFind since
2221 * when a thing A refers directly or indirectly to thingToFind and A is
2222 * present several times in the graph, we will print only the first path
2223 * leading to A and thingToFind, other ways to reach A will be ignored.
2225 if (dtrc
->thingToFind
!= thing
) {
2227 * The startThing check allows to avoid putting startThing into the
2228 * hash table before tracing startThing in JS_DumpHeap.
2230 if (thing
== dtrc
->startThing
)
2232 entry
= (JSDHashEntryStub
*)
2233 JS_DHashTableOperate(&dtrc
->visited
, thing
, JS_DHASH_ADD
);
2235 JS_ReportOutOfMemory(cx
);
2236 dtrc
->ok
= JS_FALSE
;
2244 if (dtrc
->base
.debugPrinter
) {
2245 dtrc
->base
.debugPrinter(trc
, dtrc
->buffer
, sizeof(dtrc
->buffer
));
2246 edgeName
= dtrc
->buffer
;
2247 } else if (dtrc
->base
.debugPrintIndex
!= (size_t)-1) {
2248 JS_snprintf(dtrc
->buffer
, sizeof(dtrc
->buffer
), "%s[%lu]",
2249 (const char *)dtrc
->base
.debugPrintArg
,
2250 dtrc
->base
.debugPrintIndex
);
2251 edgeName
= dtrc
->buffer
;
2253 edgeName
= (const char*)dtrc
->base
.debugPrintArg
;
2256 edgeNameSize
= strlen(edgeName
) + 1;
2257 node
= (JSHeapDumpNode
*)
2258 JS_malloc(cx
, offsetof(JSHeapDumpNode
, edgeName
) + edgeNameSize
);
2260 dtrc
->ok
= JS_FALSE
;
2264 node
->thing
= thing
;
2267 node
->parent
= dtrc
->parentNode
;
2268 memcpy(node
->edgeName
, edgeName
, edgeNameSize
);
2270 JS_ASSERT(!*dtrc
->lastNodep
);
2271 *dtrc
->lastNodep
= node
;
2272 dtrc
->lastNodep
= &node
->next
;
2275 /* Dump node and the chain that leads to thing it contains. */
2277 DumpNode(JSDumpingTracer
*dtrc
, FILE* fp
, JSHeapDumpNode
*node
)
2279 JSHeapDumpNode
*prev
, *following
;
2282 enum { MAX_PARENTS_TO_PRINT
= 10 };
2284 JS_PrintTraceThingInfo(dtrc
->buffer
, sizeof dtrc
->buffer
,
2285 &dtrc
->base
, node
->thing
, node
->kind
, JS_TRUE
);
2286 if (fprintf(fp
, "%p %-22s via ", node
->thing
, dtrc
->buffer
) < 0)
2290 * We need to print the parent chain in the reverse order. To do it in
2291 * O(N) time where N is the chain length we first reverse the chain while
2292 * searching for the top and then print each node while restoring the
2295 chainLimit
= MAX_PARENTS_TO_PRINT
;
2298 following
= node
->parent
;
2299 node
->parent
= prev
;
2304 if (chainLimit
== 0) {
2305 if (fputs("...", fp
) < 0)
2316 /* Loop must continue even when !ok to restore the parent chain. */
2319 /* Print edge from some runtime root or startThing. */
2320 if (fputs(node
->edgeName
, fp
) < 0)
2323 JS_PrintTraceThingInfo(dtrc
->buffer
, sizeof dtrc
->buffer
,
2324 &dtrc
->base
, prev
->thing
, prev
->kind
,
2326 if (fprintf(fp
, "(%p %s).%s",
2327 prev
->thing
, dtrc
->buffer
, node
->edgeName
) < 0) {
2332 following
= node
->parent
;
2333 node
->parent
= prev
;
2338 return ok
&& putc('\n', fp
) >= 0;
2341 JS_PUBLIC_API(JSBool
)
2342 JS_DumpHeap(JSContext
*cx
, FILE *fp
, void* startThing
, uint32 startKind
,
2343 void *thingToFind
, size_t maxDepth
, void *thingToIgnore
)
2345 JSDumpingTracer dtrc
;
2346 JSHeapDumpNode
*node
, *children
, *next
, *parent
;
2348 JSBool thingToFindWasTraced
;
2353 JS_TRACER_INIT(&dtrc
.base
, cx
, DumpNotify
);
2354 if (!JS_DHashTableInit(&dtrc
.visited
, JS_DHashGetStubOps(),
2355 NULL
, sizeof(JSDHashEntryStub
),
2356 JS_DHASH_DEFAULT_CAPACITY(100))) {
2357 JS_ReportOutOfMemory(cx
);
2361 dtrc
.startThing
= startThing
;
2362 dtrc
.thingToFind
= thingToFind
;
2363 dtrc
.thingToIgnore
= thingToIgnore
;
2364 dtrc
.parentNode
= NULL
;
2366 dtrc
.lastNodep
= &node
;
2368 JS_ASSERT(startKind
== 0);
2369 JS_TraceRuntime(&dtrc
.base
);
2371 JS_TraceChildren(&dtrc
.base
, startThing
, startKind
);
2378 thingToFindWasTraced
= thingToFind
&& thingToFind
== startThing
;
2381 * Loop must continue even when !dtrc.ok to free all nodes allocated
2385 if (thingToFind
== NULL
|| thingToFind
== node
->thing
)
2386 dtrc
.ok
= DumpNode(&dtrc
, fp
, node
);
2388 /* Descend into children. */
2391 (thingToFind
!= node
->thing
|| !thingToFindWasTraced
)) {
2392 dtrc
.parentNode
= node
;
2394 dtrc
.lastNodep
= &children
;
2395 JS_TraceChildren(&dtrc
.base
, node
->thing
, node
->kind
);
2396 if (thingToFind
== node
->thing
)
2397 thingToFindWasTraced
= JS_TRUE
;
2398 if (children
!= NULL
) {
2406 /* Move to next or parents next and free the node. */
2409 parent
= node
->parent
;
2416 JS_ASSERT(depth
> 1);
2423 JS_ASSERT(depth
== 1);
2424 JS_DHashTableFinish(&dtrc
.visited
);
2431 JS_MarkGCThing(JSContext
*cx
, void *thing
, const char *name
, void *arg
)
2435 trc
= (JSTracer
*)arg
;
2437 trc
= cx
->runtime
->gcMarkingTracer
;
2439 JS_ASSERT(trc
== cx
->runtime
->gcMarkingTracer
);
2441 #ifdef JS_THREADSAFE
2442 JS_ASSERT(cx
->runtime
->gcThread
== trc
->context
->thread
);
2444 JS_SET_TRACING_NAME(trc
, name
? name
: "unknown");
2445 js_CallValueTracerIfGCThing(trc
, (jsval
)thing
);
2448 extern JS_PUBLIC_API(JSBool
)
2449 JS_IsGCMarkingTracer(JSTracer
*trc
)
2451 return IS_GC_MARKING_TRACER(trc
);
2455 JS_GC(JSContext
*cx
)
2459 /* Don't nuke active arenas if executing or compiling. */
2460 if (cx
->stackPool
.current
== &cx
->stackPool
.first
)
2461 JS_FinishArenaPool(&cx
->stackPool
);
2462 if (cx
->tempPool
.current
== &cx
->tempPool
.first
)
2463 JS_FinishArenaPool(&cx
->tempPool
);
2464 js_GC(cx
, GC_NORMAL
);
2468 JS_MaybeGC(JSContext
*cx
)
2471 uint32 bytes
, lastBytes
;
2476 if (rt
->gcZeal
> 0) {
2482 bytes
= rt
->gcBytes
;
2483 lastBytes
= rt
->gcLastBytes
;
2486 * We run the GC if we used all available free GC cells and had to
2487 * allocate extra 1/3 of GC arenas since the last run of GC, or if
2488 * we have malloc'd more bytes through JS_malloc than we were told
2489 * to allocate by JS_NewRuntime.
2492 * bytes > 4/3 lastBytes
2493 * condition is the following. Bug 312238 changed bytes and lastBytes
2494 * to mean the total amount of memory that the GC uses now and right
2495 * after the last GC.
2497 * Before the bug the variables meant the size of allocated GC things
2498 * now and right after the last GC. That size did not include the
2499 * memory taken by free GC cells and the condition was
2500 * bytes > 3/2 lastBytes.
2501 * That is, we run the GC if we have half again as many bytes of
2502 * GC-things as the last time we GC'd. To be compatible we need to
2503 * express that condition through the new meaning of bytes and
2506 * We write the original condition as
2507 * B*(1-F) > 3/2 Bl*(1-Fl)
2508 * where B is the total memory size allocated by GC and F is the free
2509 * cell density currently and Sl and Fl are the size and the density
2510 * right after GC. The density by definition is memory taken by free
2511 * cells divided by total amount of memory. In other words, B and Bl
2512 * are bytes and lastBytes with the new meaning and B*(1-F) and
2513 * Bl*(1-Fl) are bytes and lastBytes with the original meaning.
2515 * Our task is to exclude F and Fl from the last statement. According
2516 * to the stats from bug 331966 comment 23, Fl is about 10-25% for a
2517 * typical run of the browser. It means that the original condition
2518 * implied that we did not run GC unless we exhausted the pool of
2519 * free cells. Indeed if we still have free cells, then B == Bl since
2520 * we did not yet allocated any new arenas and the condition means
2521 * 1 - F > 3/2 (1-Fl) or 3/2Fl > 1/2 + F
2522 * That implies 3/2 Fl > 1/2 or Fl > 1/3. That cannot be fulfilled
2523 * for the state described by the stats. So we can write the original
2525 * F == 0 && B > 3/2 Bl(1-Fl)
2526 * Again using the stats we see that Fl is about 11% when the browser
2527 * starts up and when we are far from hitting rt->gcMaxBytes. With
2529 * F == 0 && B > 3/2 Bl(1-0.11)
2530 * or approximately F == 0 && B > 4/3 Bl.
2532 if ((bytes
> 8192 && bytes
> lastBytes
+ lastBytes
/ 3) ||
2533 rt
->gcMallocBytes
>= rt
->gcMaxMallocBytes
) {
2538 JS_PUBLIC_API(JSGCCallback
)
2539 JS_SetGCCallback(JSContext
*cx
, JSGCCallback cb
)
2542 return JS_SetGCCallbackRT(cx
->runtime
, cb
);
2545 JS_PUBLIC_API(JSGCCallback
)
2546 JS_SetGCCallbackRT(JSRuntime
*rt
, JSGCCallback cb
)
2550 oldcb
= rt
->gcCallback
;
2551 rt
->gcCallback
= cb
;
2555 JS_PUBLIC_API(JSBool
)
2556 JS_IsAboutToBeFinalized(JSContext
*cx
, void *thing
)
2559 return js_IsAboutToBeFinalized(cx
, thing
);
2563 JS_SetGCParameter(JSRuntime
*rt
, JSGCParamKey key
, uint32 value
)
2566 case JSGC_MAX_BYTES
:
2567 rt
->gcMaxBytes
= value
;
2569 case JSGC_MAX_MALLOC_BYTES
:
2570 rt
->gcMaxMallocBytes
= value
;
2572 case JSGC_STACKPOOL_LIFESPAN
:
2573 rt
->gcEmptyArenaPoolLifespan
= value
;
2576 JS_ASSERT(key
== JSGC_TRIGGER_FACTOR
);
2577 JS_ASSERT(value
>= 100);
2578 rt
->gcTriggerFactor
= value
;
2583 JS_PUBLIC_API(uint32
)
2584 JS_GetGCParameter(JSRuntime
*rt
, JSGCParamKey key
)
2587 case JSGC_MAX_BYTES
:
2588 return rt
->gcMaxBytes
;
2589 case JSGC_MAX_MALLOC_BYTES
:
2590 return rt
->gcMaxMallocBytes
;
2591 case JSGC_STACKPOOL_LIFESPAN
:
2592 return rt
->gcEmptyArenaPoolLifespan
;
2593 case JSGC_TRIGGER_FACTOR
:
2594 return rt
->gcTriggerFactor
;
2598 JS_ASSERT(key
== JSGC_NUMBER
);
2599 return rt
->gcNumber
;
2604 JS_AddExternalStringFinalizer(JSStringFinalizeOp finalizer
)
2606 return js_ChangeExternalStringFinalizer(NULL
, finalizer
);
2610 JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer
)
2612 return js_ChangeExternalStringFinalizer(finalizer
, NULL
);
2615 JS_PUBLIC_API(JSString
*)
2616 JS_NewExternalString(JSContext
*cx
, jschar
*chars
, size_t length
, intN type
)
2621 JS_ASSERT((uintN
) type
< (uintN
) (GCX_NTYPES
- GCX_EXTERNAL_STRING
));
2623 str
= (JSString
*) js_NewGCThing(cx
, (uintN
) type
+ GCX_EXTERNAL_STRING
,
2627 JSFLATSTR_INIT(str
, chars
, length
);
2632 JS_GetExternalStringGCType(JSRuntime
*rt
, JSString
*str
)
2634 return js_GetExternalStringGCType(str
);
2638 JS_SetThreadStackLimit(JSContext
*cx
, jsuword limitAddr
)
2640 #if JS_STACK_GROWTH_DIRECTION > 0
2642 limitAddr
= (jsuword
)-1;
2644 cx
->stackLimit
= limitAddr
;
2648 JS_SetScriptStackQuota(JSContext
*cx
, size_t quota
)
2650 cx
->scriptStackQuota
= quota
;
2653 /************************************************************************/
2656 JS_DestroyIdArray(JSContext
*cx
, JSIdArray
*ida
)
2661 JS_PUBLIC_API(JSBool
)
2662 JS_ValueToId(JSContext
*cx
, jsval v
, jsid
*idp
)
2665 if (JSVAL_IS_INT(v
))
2666 *idp
= INT_JSVAL_TO_JSID(v
);
2667 #if JS_HAS_XML_SUPPORT
2668 else if (!JSVAL_IS_PRIMITIVE(v
))
2669 *idp
= OBJECT_JSVAL_TO_JSID(v
);
2672 return js_ValueToStringId(cx
, v
, idp
);
2676 JS_PUBLIC_API(JSBool
)
2677 JS_IdToValue(JSContext
*cx
, jsid id
, jsval
*vp
)
2680 *vp
= ID_TO_VALUE(id
);
2684 JS_PUBLIC_API(JSBool
)
2685 JS_PropertyStub(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
2690 JS_PUBLIC_API(JSBool
)
2691 JS_EnumerateStub(JSContext
*cx
, JSObject
*obj
)
2696 JS_PUBLIC_API(JSBool
)
2697 JS_ResolveStub(JSContext
*cx
, JSObject
*obj
, jsval id
)
2702 JS_PUBLIC_API(JSBool
)
2703 JS_ConvertStub(JSContext
*cx
, JSObject
*obj
, JSType type
, jsval
*vp
)
2705 return js_TryValueOf(cx
, obj
, type
, vp
);
2709 JS_FinalizeStub(JSContext
*cx
, JSObject
*obj
)
2713 JS_PUBLIC_API(JSObject
*)
2714 JS_InitClass(JSContext
*cx
, JSObject
*obj
, JSObject
*parent_proto
,
2715 JSClass
*clasp
, JSNative constructor
, uintN nargs
,
2716 JSPropertySpec
*ps
, JSFunctionSpec
*fs
,
2717 JSPropertySpec
*static_ps
, JSFunctionSpec
*static_fs
)
2720 return js_InitClass(cx
, obj
, parent_proto
, clasp
, constructor
, nargs
,
2721 ps
, fs
, static_ps
, static_fs
, NULL
);
2724 #ifdef JS_THREADSAFE
2725 JS_PUBLIC_API(JSClass
*)
2726 JS_GetClass(JSContext
*cx
, JSObject
*obj
)
2728 return OBJ_GET_CLASS(cx
, obj
);
2731 JS_PUBLIC_API(JSClass
*)
2732 JS_GetClass(JSObject
*obj
)
2734 return LOCKED_OBJ_GET_CLASS(obj
);
2738 JS_PUBLIC_API(JSBool
)
2739 JS_InstanceOf(JSContext
*cx
, JSObject
*obj
, JSClass
*clasp
, jsval
*argv
)
2744 if (obj
&& OBJ_GET_CLASS(cx
, obj
) == clasp
)
2747 fun
= js_ValueToFunction(cx
, &argv
[-2], 0);
2749 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2750 JSMSG_INCOMPATIBLE_PROTO
,
2751 clasp
->name
, JS_GetFunctionName(fun
),
2753 ? OBJ_GET_CLASS(cx
, obj
)->name
2760 JS_PUBLIC_API(JSBool
)
2761 JS_HasInstance(JSContext
*cx
, JSObject
*obj
, jsval v
, JSBool
*bp
)
2763 return js_HasInstance(cx
, obj
, v
, bp
);
2766 JS_PUBLIC_API(void *)
2767 JS_GetPrivate(JSContext
*cx
, JSObject
*obj
)
2771 JS_ASSERT(OBJ_GET_CLASS(cx
, obj
)->flags
& JSCLASS_HAS_PRIVATE
);
2772 v
= obj
->fslots
[JSSLOT_PRIVATE
];
2773 if (!JSVAL_IS_INT(v
))
2775 return JSVAL_TO_PRIVATE(v
);
2778 JS_PUBLIC_API(JSBool
)
2779 JS_SetPrivate(JSContext
*cx
, JSObject
*obj
, void *data
)
2781 JS_ASSERT(OBJ_GET_CLASS(cx
, obj
)->flags
& JSCLASS_HAS_PRIVATE
);
2782 obj
->fslots
[JSSLOT_PRIVATE
] = PRIVATE_TO_JSVAL(data
);
2786 JS_PUBLIC_API(void *)
2787 JS_GetInstancePrivate(JSContext
*cx
, JSObject
*obj
, JSClass
*clasp
,
2790 if (!JS_InstanceOf(cx
, obj
, clasp
, argv
))
2792 return JS_GetPrivate(cx
, obj
);
2795 JS_PUBLIC_API(JSObject
*)
2796 JS_GetPrototype(JSContext
*cx
, JSObject
*obj
)
2801 proto
= OBJ_GET_PROTO(cx
, obj
);
2803 /* Beware ref to dead object (we may be called from obj's finalizer). */
2804 return proto
&& proto
->map
? proto
: NULL
;
2807 JS_PUBLIC_API(JSBool
)
2808 JS_SetPrototype(JSContext
*cx
, JSObject
*obj
, JSObject
*proto
)
2811 JS_ASSERT(obj
!= proto
);
2812 if (OBJ_IS_NATIVE(obj
)) {
2813 JS_LOCK_OBJ(cx
, obj
);
2814 if (!js_GetMutableScope(cx
, obj
)) {
2815 JS_UNLOCK_OBJ(cx
, obj
);
2818 LOCKED_OBJ_SET_PROTO(obj
, proto
);
2819 JS_UNLOCK_OBJ(cx
, obj
);
2822 OBJ_SET_PROTO(cx
, obj
, proto
);
2826 JS_PUBLIC_API(JSObject
*)
2827 JS_GetParent(JSContext
*cx
, JSObject
*obj
)
2831 parent
= OBJ_GET_PARENT(cx
, obj
);
2833 /* Beware ref to dead object (we may be called from obj's finalizer). */
2834 return parent
&& parent
->map
? parent
: NULL
;
2837 JS_PUBLIC_API(JSBool
)
2838 JS_SetParent(JSContext
*cx
, JSObject
*obj
, JSObject
*parent
)
2841 JS_ASSERT(obj
!= parent
);
2842 OBJ_SET_PARENT(cx
, obj
, parent
);
2846 JS_PUBLIC_API(JSObject
*)
2847 JS_GetConstructor(JSContext
*cx
, JSObject
*proto
)
2853 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
);
2855 if (!OBJ_GET_PROPERTY(cx
, proto
,
2856 ATOM_TO_JSID(cx
->runtime
->atomState
.constructorAtom
),
2861 if (!VALUE_IS_FUNCTION(cx
, cval
)) {
2862 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_NO_CONSTRUCTOR
,
2863 OBJ_GET_CLASS(cx
, proto
)->name
);
2866 return JSVAL_TO_OBJECT(cval
);
2869 JS_PUBLIC_API(JSBool
)
2870 JS_GetObjectId(JSContext
*cx
, JSObject
*obj
, jsid
*idp
)
2872 JS_ASSERT(JSID_IS_OBJECT(obj
));
2873 *idp
= OBJECT_TO_JSID(obj
);
2877 JS_PUBLIC_API(JSObject
*)
2878 JS_NewObject(JSContext
*cx
, JSClass
*clasp
, JSObject
*proto
, JSObject
*parent
)
2882 clasp
= &js_ObjectClass
; /* default class is Object */
2883 return js_NewObject(cx
, clasp
, proto
, parent
, 0);
2886 JS_PUBLIC_API(JSObject
*)
2887 JS_NewObjectWithGivenProto(JSContext
*cx
, JSClass
*clasp
, JSObject
*proto
,
2892 clasp
= &js_ObjectClass
; /* default class is Object */
2893 return js_NewObjectWithGivenProto(cx
, clasp
, proto
, parent
, 0);
2896 JS_PUBLIC_API(JSBool
)
2897 JS_SealObject(JSContext
*cx
, JSObject
*obj
, JSBool deep
)
2904 if (OBJ_IS_DENSE_ARRAY(cx
, obj
) && !js_MakeArraySlow(cx
, obj
))
2907 if (!OBJ_IS_NATIVE(obj
)) {
2908 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
2909 JSMSG_CANT_SEAL_OBJECT
,
2910 OBJ_GET_CLASS(cx
, obj
)->name
);
2914 scope
= OBJ_SCOPE(obj
);
2916 #if defined JS_THREADSAFE && defined DEBUG
2917 /* Insist on scope being used exclusively by cx's thread. */
2918 if (scope
->title
.ownercx
!= cx
) {
2919 JS_LOCK_OBJ(cx
, obj
);
2920 JS_ASSERT(OBJ_SCOPE(obj
) == scope
);
2921 JS_ASSERT(scope
->title
.ownercx
== cx
);
2922 JS_UNLOCK_SCOPE(cx
, scope
);
2926 /* Nothing to do if obj's scope is already sealed. */
2927 if (SCOPE_IS_SEALED(scope
))
2930 /* XXX Enumerate lazy properties now, as they can't be added later. */
2931 ida
= JS_Enumerate(cx
, obj
);
2934 JS_DestroyIdArray(cx
, ida
);
2936 /* Ensure that obj has its own, mutable scope, and seal that scope. */
2937 JS_LOCK_OBJ(cx
, obj
);
2938 scope
= js_GetMutableScope(cx
, obj
);
2940 SCOPE_SET_SEALED(scope
);
2941 SCOPE_MAKE_UNIQUE_SHAPE(cx
, scope
);
2943 JS_UNLOCK_OBJ(cx
, obj
);
2947 /* If we are not sealing an entire object graph, we're done. */
2951 /* Walk slots in obj and if any value is a non-null object, seal it. */
2952 nslots
= scope
->map
.freeslot
;
2953 for (i
= 0; i
!= nslots
; ++i
) {
2954 v
= STOBJ_GET_SLOT(obj
, i
);
2955 if (JSVAL_IS_PRIMITIVE(v
))
2957 if (!JS_SealObject(cx
, JSVAL_TO_OBJECT(v
), deep
))
2963 JS_PUBLIC_API(JSObject
*)
2964 JS_ConstructObject(JSContext
*cx
, JSClass
*clasp
, JSObject
*proto
,
2969 clasp
= &js_ObjectClass
; /* default class is Object */
2970 return js_ConstructObject(cx
, clasp
, proto
, parent
, 0, NULL
);
2973 JS_PUBLIC_API(JSObject
*)
2974 JS_ConstructObjectWithArguments(JSContext
*cx
, JSClass
*clasp
, JSObject
*proto
,
2975 JSObject
*parent
, uintN argc
, jsval
*argv
)
2979 clasp
= &js_ObjectClass
; /* default class is Object */
2980 return js_ConstructObject(cx
, clasp
, proto
, parent
, argc
, argv
);
2984 DefinePropertyById(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval value
,
2985 JSPropertyOp getter
, JSPropertyOp setter
, uintN attrs
,
2986 uintN flags
, intN tinyid
)
2988 if (flags
!= 0 && OBJ_IS_NATIVE(obj
)) {
2989 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
| JSRESOLVE_DECLARING
);
2990 return !!js_DefineNativeProperty(cx
, obj
, id
, value
, getter
, setter
,
2991 attrs
, flags
, tinyid
, NULL
);
2993 return OBJ_DEFINE_PROPERTY(cx
, obj
, id
, value
, getter
, setter
, attrs
,
2998 DefineProperty(JSContext
*cx
, JSObject
*obj
, const char *name
, jsval value
,
2999 JSPropertyOp getter
, JSPropertyOp setter
, uintN attrs
,
3000 uintN flags
, intN tinyid
)
3005 if (attrs
& JSPROP_INDEX
) {
3006 id
= INT_TO_JSID(JS_PTR_TO_INT32(name
));
3008 attrs
&= ~JSPROP_INDEX
;
3010 atom
= js_Atomize(cx
, name
, strlen(name
), 0);
3013 id
= ATOM_TO_JSID(atom
);
3015 return DefinePropertyById(cx
, obj
, id
, value
, getter
, setter
, attrs
,
3019 #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
3022 DefineUCProperty(JSContext
*cx
, JSObject
*obj
,
3023 const jschar
*name
, size_t namelen
, jsval value
,
3024 JSPropertyOp getter
, JSPropertyOp setter
, uintN attrs
,
3025 uintN flags
, intN tinyid
)
3029 atom
= js_AtomizeChars(cx
, name
, AUTO_NAMELEN(name
, namelen
), 0);
3032 if (flags
!= 0 && OBJ_IS_NATIVE(obj
)) {
3033 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
| JSRESOLVE_DECLARING
);
3034 return !!js_DefineNativeProperty(cx
, obj
, ATOM_TO_JSID(atom
), value
,
3035 getter
, setter
, attrs
, flags
, tinyid
,
3038 return OBJ_DEFINE_PROPERTY(cx
, obj
, ATOM_TO_JSID(atom
), value
,
3039 getter
, setter
, attrs
, NULL
);
3042 JS_PUBLIC_API(JSObject
*)
3043 JS_DefineObject(JSContext
*cx
, JSObject
*obj
, const char *name
, JSClass
*clasp
,
3044 JSObject
*proto
, uintN attrs
)
3050 clasp
= &js_ObjectClass
; /* default class is Object */
3051 nobj
= js_NewObject(cx
, clasp
, proto
, obj
, 0);
3054 if (!DefineProperty(cx
, obj
, name
, OBJECT_TO_JSVAL(nobj
), NULL
, NULL
, attrs
,
3056 cx
->weakRoots
.newborn
[GCX_OBJECT
] = NULL
;
3062 JS_PUBLIC_API(JSBool
)
3063 JS_DefineConstDoubles(JSContext
*cx
, JSObject
*obj
, JSConstDoubleSpec
*cds
)
3070 for (ok
= JS_TRUE
; cds
->name
; cds
++) {
3071 ok
= js_NewNumberInRootedValue(cx
, cds
->dval
, &value
);
3076 attrs
= JSPROP_READONLY
| JSPROP_PERMANENT
;
3077 ok
= DefineProperty(cx
, obj
, cds
->name
, value
, NULL
, NULL
, attrs
, 0, 0);
3084 JS_PUBLIC_API(JSBool
)
3085 JS_DefineProperties(JSContext
*cx
, JSObject
*obj
, JSPropertySpec
*ps
)
3090 for (ok
= JS_TRUE
; ps
->name
; ps
++) {
3091 ok
= DefineProperty(cx
, obj
, ps
->name
, JSVAL_VOID
,
3092 ps
->getter
, ps
->setter
, ps
->flags
,
3093 SPROP_HAS_SHORTID
, ps
->tinyid
);
3100 JS_PUBLIC_API(JSBool
)
3101 JS_DefineProperty(JSContext
*cx
, JSObject
*obj
, const char *name
, jsval value
,
3102 JSPropertyOp getter
, JSPropertyOp setter
, uintN attrs
)
3105 return DefineProperty(cx
, obj
, name
, value
, getter
, setter
, attrs
, 0, 0);
3108 JS_PUBLIC_API(JSBool
)
3109 JS_DefinePropertyById(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval value
,
3110 JSPropertyOp getter
, JSPropertyOp setter
, uintN attrs
)
3113 return DefinePropertyById(cx
, obj
, id
, value
, getter
, setter
, attrs
, 0, 0);
3116 JS_PUBLIC_API(JSBool
)
3117 JS_DefinePropertyWithTinyId(JSContext
*cx
, JSObject
*obj
, const char *name
,
3118 int8 tinyid
, jsval value
,
3119 JSPropertyOp getter
, JSPropertyOp setter
,
3123 return DefineProperty(cx
, obj
, name
, value
, getter
, setter
, attrs
,
3124 SPROP_HAS_SHORTID
, tinyid
);
3128 LookupPropertyById(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
3129 JSObject
**objp
, JSProperty
**propp
)
3131 JSAutoResolveFlags
rf(cx
, flags
);
3132 CHECK_FOR_STRING_INDEX(id
);
3133 return OBJ_LOOKUP_PROPERTY(cx
, obj
, id
, objp
, propp
);
3137 LookupProperty(JSContext
*cx
, JSObject
*obj
, const char *name
, uintN flags
,
3138 JSObject
**objp
, JSProperty
**propp
)
3142 atom
= js_Atomize(cx
, name
, strlen(name
), 0);
3145 return LookupPropertyById(cx
, obj
, ATOM_TO_JSID(atom
), flags
, objp
, propp
);
3149 LookupUCProperty(JSContext
*cx
, JSObject
*obj
,
3150 const jschar
*name
, size_t namelen
, uintN flags
,
3151 JSObject
**objp
, JSProperty
**propp
)
3155 atom
= js_AtomizeChars(cx
, name
, AUTO_NAMELEN(name
, namelen
), 0);
3158 return LookupPropertyById(cx
, obj
, ATOM_TO_JSID(atom
), flags
, objp
, propp
);
3161 JS_PUBLIC_API(JSBool
)
3162 JS_AliasProperty(JSContext
*cx
, JSObject
*obj
, const char *name
,
3169 JSScopeProperty
*sprop
;
3172 if (!LookupProperty(cx
, obj
, name
, JSRESOLVE_QUALIFIED
, &obj2
, &prop
))
3175 js_ReportIsNotDefined(cx
, name
);
3178 if (obj2
!= obj
|| !OBJ_IS_NATIVE(obj
)) {
3179 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3180 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_CANT_ALIAS
,
3181 alias
, name
, OBJ_GET_CLASS(cx
, obj2
)->name
);
3184 atom
= js_Atomize(cx
, alias
, strlen(alias
), 0);
3188 sprop
= (JSScopeProperty
*)prop
;
3189 ok
= (js_AddNativeProperty(cx
, obj
, ATOM_TO_JSID(atom
),
3190 sprop
->getter
, sprop
->setter
, sprop
->slot
,
3191 sprop
->attrs
, sprop
->flags
| SPROP_IS_ALIAS
,
3195 OBJ_DROP_PROPERTY(cx
, obj
, prop
);
3200 LookupResult(JSContext
*cx
, JSObject
*obj
, JSObject
*obj2
, JSProperty
*prop
,
3204 /* XXX bad API: no way to tell "not defined" from "void value" */
3209 JSBool ok
= JS_TRUE
;
3210 if (OBJ_IS_NATIVE(obj2
)) {
3211 JSScopeProperty
*sprop
= (JSScopeProperty
*) prop
;
3213 /* Peek at the native property's slot value, without doing a Get. */
3214 *vp
= SPROP_HAS_VALID_SLOT(sprop
, OBJ_SCOPE(obj2
))
3215 ? LOCKED_OBJ_GET_SLOT(obj2
, sprop
->slot
)
3217 } else if (OBJ_IS_DENSE_ARRAY(cx
, obj2
)) {
3218 ok
= js_GetDenseArrayElementValue(cx
, obj2
, prop
, vp
);
3220 /* XXX bad API: no way to return "defined but value unknown" */
3223 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3228 GetPropertyAttributesById(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
3229 JSBool own
, JSPropertyDescriptor
*desc
)
3235 if (!LookupPropertyById(cx
, obj
, id
, flags
, &obj2
, &prop
))
3238 if (!prop
|| (own
&& obj
!= obj2
)) {
3241 desc
->getter
= NULL
;
3242 desc
->setter
= NULL
;
3243 desc
->value
= JSVAL_VOID
;
3245 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3251 ok
= OBJ_GET_ATTRIBUTES(cx
, obj2
, id
, prop
, &desc
->attrs
);
3253 if (OBJ_IS_NATIVE(obj2
)) {
3254 JSScopeProperty
*sprop
= (JSScopeProperty
*) prop
;
3256 desc
->getter
= sprop
->getter
;
3257 desc
->setter
= sprop
->setter
;
3258 desc
->value
= SPROP_HAS_VALID_SLOT(sprop
, OBJ_SCOPE(obj2
))
3259 ? LOCKED_OBJ_GET_SLOT(obj2
, sprop
->slot
)
3262 desc
->getter
= NULL
;
3263 desc
->setter
= NULL
;
3264 desc
->value
= JSVAL_VOID
;
3267 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3272 GetPropertyAttributes(JSContext
*cx
, JSObject
*obj
, JSAtom
*atom
,
3273 uintN
*attrsp
, JSBool
*foundp
,
3274 JSPropertyOp
*getterp
, JSPropertyOp
*setterp
)
3280 JSPropertyDescriptor desc
;
3281 if (!GetPropertyAttributesById(cx
, obj
, ATOM_TO_JSID(atom
),
3282 JSRESOLVE_QUALIFIED
, JS_FALSE
, &desc
)) {
3286 *attrsp
= desc
.attrs
;
3287 *foundp
= (desc
.obj
!= NULL
);
3289 *getterp
= desc
.getter
;
3291 *setterp
= desc
.setter
;
3296 SetPropertyAttributes(JSContext
*cx
, JSObject
*obj
, JSAtom
*atom
,
3297 uintN attrs
, JSBool
*foundp
)
3305 if (!LookupPropertyById(cx
, obj
, ATOM_TO_JSID(atom
), JSRESOLVE_QUALIFIED
,
3309 if (!prop
|| obj
!= obj2
) {
3312 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3317 ok
= OBJ_SET_ATTRIBUTES(cx
, obj
, ATOM_TO_JSID(atom
), prop
, &attrs
);
3318 OBJ_DROP_PROPERTY(cx
, obj
, prop
);
3322 JS_PUBLIC_API(JSBool
)
3323 JS_GetPropertyAttributes(JSContext
*cx
, JSObject
*obj
, const char *name
,
3324 uintN
*attrsp
, JSBool
*foundp
)
3327 return GetPropertyAttributes(cx
, obj
,
3328 js_Atomize(cx
, name
, strlen(name
), 0),
3329 attrsp
, foundp
, NULL
, NULL
);
3332 JS_PUBLIC_API(JSBool
)
3333 JS_GetPropertyAttrsGetterAndSetter(JSContext
*cx
, JSObject
*obj
,
3335 uintN
*attrsp
, JSBool
*foundp
,
3336 JSPropertyOp
*getterp
,
3337 JSPropertyOp
*setterp
)
3340 return GetPropertyAttributes(cx
, obj
,
3341 js_Atomize(cx
, name
, strlen(name
), 0),
3342 attrsp
, foundp
, getterp
, setterp
);
3345 JS_PUBLIC_API(JSBool
)
3346 JS_GetPropertyAttrsGetterAndSetterById(JSContext
*cx
, JSObject
*obj
,
3348 uintN
*attrsp
, JSBool
*foundp
,
3349 JSPropertyOp
*getterp
,
3350 JSPropertyOp
*setterp
)
3354 JSPropertyDescriptor desc
;
3355 if (!GetPropertyAttributesById(cx
, obj
, id
, JSRESOLVE_QUALIFIED
, JS_FALSE
, &desc
))
3358 *attrsp
= desc
.attrs
;
3359 *foundp
= (desc
.obj
!= NULL
);
3361 *getterp
= desc
.getter
;
3363 *setterp
= desc
.setter
;
3367 JS_PUBLIC_API(JSBool
)
3368 JS_SetPropertyAttributes(JSContext
*cx
, JSObject
*obj
, const char *name
,
3369 uintN attrs
, JSBool
*foundp
)
3372 return SetPropertyAttributes(cx
, obj
,
3373 js_Atomize(cx
, name
, strlen(name
), 0),
3378 AlreadyHasOwnPropertyHelper(JSContext
*cx
, JSObject
*obj
, jsid id
,
3383 if (!OBJ_IS_NATIVE(obj
)) {
3387 if (!LookupPropertyById(cx
, obj
, id
,
3388 JSRESOLVE_QUALIFIED
| JSRESOLVE_DETECTING
,
3392 *foundp
= (obj
== obj2
);
3394 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3398 JS_LOCK_OBJ(cx
, obj
);
3399 scope
= OBJ_SCOPE(obj
);
3400 *foundp
= (scope
->object
== obj
&& SCOPE_GET_PROPERTY(scope
, id
));
3401 JS_UNLOCK_SCOPE(cx
, scope
);
3405 JS_PUBLIC_API(JSBool
)
3406 JS_AlreadyHasOwnProperty(JSContext
*cx
, JSObject
*obj
, const char *name
,
3412 atom
= js_Atomize(cx
, name
, strlen(name
), 0);
3415 return AlreadyHasOwnPropertyHelper(cx
, obj
, ATOM_TO_JSID(atom
), foundp
);
3418 JS_PUBLIC_API(JSBool
)
3419 JS_AlreadyHasOwnPropertyById(JSContext
*cx
, JSObject
*obj
, jsid id
,
3423 return AlreadyHasOwnPropertyHelper(cx
, obj
, id
, foundp
);
3426 JS_PUBLIC_API(JSBool
)
3427 JS_HasProperty(JSContext
*cx
, JSObject
*obj
, const char *name
, JSBool
*foundp
)
3434 ok
= LookupProperty(cx
, obj
, name
,
3435 JSRESOLVE_QUALIFIED
| JSRESOLVE_DETECTING
,
3438 *foundp
= (prop
!= NULL
);
3440 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3445 JS_PUBLIC_API(JSBool
)
3446 JS_HasPropertyById(JSContext
*cx
, JSObject
*obj
, jsid id
, JSBool
*foundp
)
3453 ok
= LookupPropertyById(cx
, obj
, id
,
3454 JSRESOLVE_QUALIFIED
| JSRESOLVE_DETECTING
,
3457 *foundp
= (prop
!= NULL
);
3459 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3464 JS_PUBLIC_API(JSBool
)
3465 JS_LookupProperty(JSContext
*cx
, JSObject
*obj
, const char *name
, jsval
*vp
)
3471 return LookupProperty(cx
, obj
, name
, JSRESOLVE_QUALIFIED
, &obj2
, &prop
) &&
3472 LookupResult(cx
, obj
, obj2
, prop
, vp
);
3475 JS_PUBLIC_API(JSBool
)
3476 JS_LookupPropertyById(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
3482 return LookupPropertyById(cx
, obj
, id
, JSRESOLVE_QUALIFIED
, &obj2
, &prop
) &&
3483 LookupResult(cx
, obj
, obj2
, prop
, vp
);
3486 JS_PUBLIC_API(JSBool
)
3487 JS_LookupPropertyWithFlags(JSContext
*cx
, JSObject
*obj
, const char *name
,
3488 uintN flags
, jsval
*vp
)
3493 atom
= js_Atomize(cx
, name
, strlen(name
), 0);
3495 JS_LookupPropertyWithFlagsById(cx
, obj
, ATOM_TO_JSID(atom
), flags
,
3499 JS_PUBLIC_API(JSBool
)
3500 JS_LookupPropertyWithFlagsById(JSContext
*cx
, JSObject
*obj
, jsid id
,
3501 uintN flags
, JSObject
**objp
, jsval
*vp
)
3507 ok
= OBJ_IS_NATIVE(obj
)
3508 ? js_LookupPropertyWithFlags(cx
, obj
, id
, flags
, objp
, &prop
) >= 0
3509 : OBJ_LOOKUP_PROPERTY(cx
, obj
, id
, objp
, &prop
);
3511 ok
= LookupResult(cx
, obj
, *objp
, prop
, vp
);
3515 JS_PUBLIC_API(JSBool
)
3516 JS_GetPropertyDescriptorById(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN flags
,
3517 JSPropertyDescriptor
*desc
)
3521 return GetPropertyAttributesById(cx
, obj
, id
, flags
, JS_FALSE
, desc
);
3524 JS_PUBLIC_API(JSBool
)
3525 JS_GetProperty(JSContext
*cx
, JSObject
*obj
, const char *name
, jsval
*vp
)
3530 atom
= js_Atomize(cx
, name
, strlen(name
), 0);
3534 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
);
3535 return OBJ_GET_PROPERTY(cx
, obj
, ATOM_TO_JSID(atom
), vp
);
3538 JS_PUBLIC_API(JSBool
)
3539 JS_GetPropertyById(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
3542 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
);
3543 return OBJ_GET_PROPERTY(cx
, obj
, id
, vp
);
3546 JS_PUBLIC_API(JSBool
)
3547 JS_GetMethodById(JSContext
*cx
, JSObject
*obj
, jsid id
, JSObject
**objp
,
3550 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
);
3553 if (!js_GetMethod(cx
, obj
, id
, false, vp
))
3560 JS_PUBLIC_API(JSBool
)
3561 JS_GetMethod(JSContext
*cx
, JSObject
*obj
, const char *name
, JSObject
**objp
,
3566 atom
= js_Atomize(cx
, name
, strlen(name
), 0);
3569 return JS_GetMethodById(cx
, obj
, ATOM_TO_JSID(atom
), objp
, vp
);
3572 JS_PUBLIC_API(JSBool
)
3573 JS_SetProperty(JSContext
*cx
, JSObject
*obj
, const char *name
, jsval
*vp
)
3578 atom
= js_Atomize(cx
, name
, strlen(name
), 0);
3582 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
| JSRESOLVE_ASSIGNING
);
3583 return OBJ_SET_PROPERTY(cx
, obj
, ATOM_TO_JSID(atom
), vp
);
3586 JS_PUBLIC_API(JSBool
)
3587 JS_SetPropertyById(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*vp
)
3590 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
| JSRESOLVE_ASSIGNING
);
3591 return OBJ_SET_PROPERTY(cx
, obj
, id
, vp
);
3594 JS_PUBLIC_API(JSBool
)
3595 JS_DeleteProperty(JSContext
*cx
, JSObject
*obj
, const char *name
)
3599 return JS_DeleteProperty2(cx
, obj
, name
, &junk
);
3602 JS_PUBLIC_API(JSBool
)
3603 JS_DeleteProperty2(JSContext
*cx
, JSObject
*obj
, const char *name
,
3609 atom
= js_Atomize(cx
, name
, strlen(name
), 0);
3613 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
);
3614 return OBJ_DELETE_PROPERTY(cx
, obj
, ATOM_TO_JSID(atom
), rval
);
3617 JS_PUBLIC_API(JSBool
)
3618 JS_DeletePropertyById(JSContext
*cx
, JSObject
*obj
, jsid id
)
3622 return JS_DeletePropertyById2(cx
, obj
, id
, &junk
);
3625 JS_PUBLIC_API(JSBool
)
3626 JS_DeletePropertyById2(JSContext
*cx
, JSObject
*obj
, jsid id
, jsval
*rval
)
3629 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
);
3630 return OBJ_DELETE_PROPERTY(cx
, obj
, id
, rval
);
3633 JS_PUBLIC_API(JSBool
)
3634 JS_DefineUCProperty(JSContext
*cx
, JSObject
*obj
,
3635 const jschar
*name
, size_t namelen
, jsval value
,
3636 JSPropertyOp getter
, JSPropertyOp setter
,
3640 return DefineUCProperty(cx
, obj
, name
, namelen
, value
, getter
, setter
,
3644 JS_PUBLIC_API(JSBool
)
3645 JS_GetUCPropertyAttributes(JSContext
*cx
, JSObject
*obj
,
3646 const jschar
*name
, size_t namelen
,
3647 uintN
*attrsp
, JSBool
*foundp
)
3650 return GetPropertyAttributes(cx
, obj
,
3651 js_AtomizeChars(cx
, name
, AUTO_NAMELEN(name
, namelen
), 0),
3652 attrsp
, foundp
, NULL
, NULL
);
3655 JS_PUBLIC_API(JSBool
)
3656 JS_GetUCPropertyAttrsGetterAndSetter(JSContext
*cx
, JSObject
*obj
,
3657 const jschar
*name
, size_t namelen
,
3658 uintN
*attrsp
, JSBool
*foundp
,
3659 JSPropertyOp
*getterp
,
3660 JSPropertyOp
*setterp
)
3663 return GetPropertyAttributes(cx
, obj
,
3664 js_AtomizeChars(cx
, name
, AUTO_NAMELEN(name
, namelen
), 0),
3665 attrsp
, foundp
, getterp
, setterp
);
3668 JS_PUBLIC_API(JSBool
)
3669 JS_SetUCPropertyAttributes(JSContext
*cx
, JSObject
*obj
,
3670 const jschar
*name
, size_t namelen
,
3671 uintN attrs
, JSBool
*foundp
)
3674 return SetPropertyAttributes(cx
, obj
,
3675 js_AtomizeChars(cx
, name
, AUTO_NAMELEN(name
, namelen
), 0),
3679 JS_PUBLIC_API(JSBool
)
3680 JS_DefineUCPropertyWithTinyId(JSContext
*cx
, JSObject
*obj
,
3681 const jschar
*name
, size_t namelen
,
3682 int8 tinyid
, jsval value
,
3683 JSPropertyOp getter
, JSPropertyOp setter
,
3687 return DefineUCProperty(cx
, obj
, name
, namelen
, value
, getter
, setter
,
3688 attrs
, SPROP_HAS_SHORTID
, tinyid
);
3691 JS_PUBLIC_API(JSBool
)
3692 JS_AlreadyHasOwnUCProperty(JSContext
*cx
, JSObject
*obj
,
3693 const jschar
*name
, size_t namelen
,
3699 atom
= js_AtomizeChars(cx
, name
, AUTO_NAMELEN(name
, namelen
), 0);
3702 return AlreadyHasOwnPropertyHelper(cx
, obj
, ATOM_TO_JSID(atom
), foundp
);
3705 JS_PUBLIC_API(JSBool
)
3706 JS_HasUCProperty(JSContext
*cx
, JSObject
*obj
,
3707 const jschar
*name
, size_t namelen
,
3715 ok
= LookupUCProperty(cx
, obj
, name
, namelen
,
3716 JSRESOLVE_QUALIFIED
| JSRESOLVE_DETECTING
,
3719 *vp
= (prop
!= NULL
);
3721 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3726 JS_PUBLIC_API(JSBool
)
3727 JS_LookupUCProperty(JSContext
*cx
, JSObject
*obj
,
3728 const jschar
*name
, size_t namelen
,
3735 return LookupUCProperty(cx
, obj
, name
, namelen
, JSRESOLVE_QUALIFIED
,
3737 LookupResult(cx
, obj
, obj2
, prop
, vp
);
3740 JS_PUBLIC_API(JSBool
)
3741 JS_GetUCProperty(JSContext
*cx
, JSObject
*obj
,
3742 const jschar
*name
, size_t namelen
,
3748 atom
= js_AtomizeChars(cx
, name
, AUTO_NAMELEN(name
, namelen
), 0);
3752 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
);
3753 return OBJ_GET_PROPERTY(cx
, obj
, ATOM_TO_JSID(atom
), vp
);
3756 JS_PUBLIC_API(JSBool
)
3757 JS_SetUCProperty(JSContext
*cx
, JSObject
*obj
,
3758 const jschar
*name
, size_t namelen
,
3764 atom
= js_AtomizeChars(cx
, name
, AUTO_NAMELEN(name
, namelen
), 0);
3768 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
| JSRESOLVE_ASSIGNING
);
3769 return OBJ_SET_PROPERTY(cx
, obj
, ATOM_TO_JSID(atom
), vp
);
3772 JS_PUBLIC_API(JSBool
)
3773 JS_DeleteUCProperty2(JSContext
*cx
, JSObject
*obj
,
3774 const jschar
*name
, size_t namelen
,
3780 atom
= js_AtomizeChars(cx
, name
, AUTO_NAMELEN(name
, namelen
), 0);
3784 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
);
3785 return OBJ_DELETE_PROPERTY(cx
, obj
, ATOM_TO_JSID(atom
), rval
);
3788 JS_PUBLIC_API(JSObject
*)
3789 JS_NewArrayObject(JSContext
*cx
, jsint length
, jsval
*vector
)
3792 /* NB: jsuint cast does ToUint32. */
3793 return js_NewArrayObject(cx
, (jsuint
)length
, vector
);
3796 JS_PUBLIC_API(JSBool
)
3797 JS_IsArrayObject(JSContext
*cx
, JSObject
*obj
)
3799 return OBJ_IS_ARRAY(cx
, obj
);
3802 JS_PUBLIC_API(JSBool
)
3803 JS_GetArrayLength(JSContext
*cx
, JSObject
*obj
, jsuint
*lengthp
)
3806 return js_GetLengthProperty(cx
, obj
, lengthp
);
3809 JS_PUBLIC_API(JSBool
)
3810 JS_SetArrayLength(JSContext
*cx
, JSObject
*obj
, jsuint length
)
3813 return js_SetLengthProperty(cx
, obj
, length
);
3816 JS_PUBLIC_API(JSBool
)
3817 JS_HasArrayLength(JSContext
*cx
, JSObject
*obj
, jsuint
*lengthp
)
3820 return js_HasLengthProperty(cx
, obj
, lengthp
);
3823 JS_PUBLIC_API(JSBool
)
3824 JS_DefineElement(JSContext
*cx
, JSObject
*obj
, jsint index
, jsval value
,
3825 JSPropertyOp getter
, JSPropertyOp setter
, uintN attrs
)
3827 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
| JSRESOLVE_DECLARING
);
3830 return OBJ_DEFINE_PROPERTY(cx
, obj
, INT_TO_JSID(index
), value
,
3831 getter
, setter
, attrs
, NULL
);
3834 JS_PUBLIC_API(JSBool
)
3835 JS_AliasElement(JSContext
*cx
, JSObject
*obj
, const char *name
, jsint alias
)
3839 JSScopeProperty
*sprop
;
3843 if (!LookupProperty(cx
, obj
, name
, JSRESOLVE_QUALIFIED
, &obj2
, &prop
))
3846 js_ReportIsNotDefined(cx
, name
);
3849 if (obj2
!= obj
|| !OBJ_IS_NATIVE(obj
)) {
3851 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3852 JS_snprintf(numBuf
, sizeof numBuf
, "%ld", (long)alias
);
3853 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_CANT_ALIAS
,
3854 numBuf
, name
, OBJ_GET_CLASS(cx
, obj2
)->name
);
3857 sprop
= (JSScopeProperty
*)prop
;
3858 ok
= (js_AddNativeProperty(cx
, obj
, INT_TO_JSID(alias
),
3859 sprop
->getter
, sprop
->setter
, sprop
->slot
,
3860 sprop
->attrs
, sprop
->flags
| SPROP_IS_ALIAS
,
3863 OBJ_DROP_PROPERTY(cx
, obj
, prop
);
3867 JS_PUBLIC_API(JSBool
)
3868 JS_AlreadyHasOwnElement(JSContext
*cx
, JSObject
*obj
, jsint index
,
3871 return AlreadyHasOwnPropertyHelper(cx
, obj
, INT_TO_JSID(index
), foundp
);
3874 JS_PUBLIC_API(JSBool
)
3875 JS_HasElement(JSContext
*cx
, JSObject
*obj
, jsint index
, JSBool
*foundp
)
3882 ok
= LookupPropertyById(cx
, obj
, INT_TO_JSID(index
),
3883 JSRESOLVE_QUALIFIED
| JSRESOLVE_DETECTING
,
3886 *foundp
= (prop
!= NULL
);
3888 OBJ_DROP_PROPERTY(cx
, obj2
, prop
);
3893 JS_PUBLIC_API(JSBool
)
3894 JS_LookupElement(JSContext
*cx
, JSObject
*obj
, jsint index
, jsval
*vp
)
3900 return LookupPropertyById(cx
, obj
, INT_TO_JSID(index
), JSRESOLVE_QUALIFIED
,
3902 LookupResult(cx
, obj
, obj2
, prop
, vp
);
3905 JS_PUBLIC_API(JSBool
)
3906 JS_GetElement(JSContext
*cx
, JSObject
*obj
, jsint index
, jsval
*vp
)
3908 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
);
3911 return OBJ_GET_PROPERTY(cx
, obj
, INT_TO_JSID(index
), vp
);
3914 JS_PUBLIC_API(JSBool
)
3915 JS_SetElement(JSContext
*cx
, JSObject
*obj
, jsint index
, jsval
*vp
)
3917 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
| JSRESOLVE_ASSIGNING
);
3920 return OBJ_SET_PROPERTY(cx
, obj
, INT_TO_JSID(index
), vp
);
3923 JS_PUBLIC_API(JSBool
)
3924 JS_DeleteElement(JSContext
*cx
, JSObject
*obj
, jsint index
)
3928 return JS_DeleteElement2(cx
, obj
, index
, &junk
);
3931 JS_PUBLIC_API(JSBool
)
3932 JS_DeleteElement2(JSContext
*cx
, JSObject
*obj
, jsint index
, jsval
*rval
)
3934 JSAutoResolveFlags
rf(cx
, JSRESOLVE_QUALIFIED
);
3937 return OBJ_DELETE_PROPERTY(cx
, obj
, INT_TO_JSID(index
), rval
);
3941 JS_ClearScope(JSContext
*cx
, JSObject
*obj
)
3945 if (obj
->map
->ops
->clear
)
3946 obj
->map
->ops
->clear(cx
, obj
);
3948 /* Clear cached class objects on the global object. */
3949 if (OBJ_GET_CLASS(cx
, obj
)->flags
& JSCLASS_IS_GLOBAL
) {
3952 for (key
= JSProto_Null
; key
< JSProto_LIMIT
; key
++)
3953 JS_SetReservedSlot(cx
, obj
, key
, JSVAL_VOID
);
3957 JS_PUBLIC_API(JSIdArray
*)
3958 JS_Enumerate(JSContext
*cx
, JSObject
*obj
)
3961 jsval iter_state
, num_properties
;
3969 iter_state
= JSVAL_NULL
;
3971 /* Get the number of properties to enumerate. */
3972 if (!OBJ_ENUMERATE(cx
, obj
, JSENUMERATE_INIT
, &iter_state
, &num_properties
))
3974 if (!JSVAL_IS_INT(num_properties
)) {
3979 /* Grow as needed if we don't know the exact amount ahead of time. */
3980 n
= JSVAL_TO_INT(num_properties
);
3984 /* Create an array of jsids large enough to hold all the properties */
3985 ida
= NewIdArray(cx
, n
);
3990 vector
= &ida
->vector
[0];
3992 if (!OBJ_ENUMERATE(cx
, obj
, JSENUMERATE_NEXT
, &iter_state
, &id
))
3995 /* No more jsid's to enumerate ? */
3996 if (iter_state
== JSVAL_NULL
)
3999 if (i
== ida
->length
) {
4000 ida
= SetIdArrayLength(cx
, ida
, ida
->length
* 2);
4003 vector
= &ida
->vector
[0];
4007 return SetIdArrayLength(cx
, ida
, i
);
4010 if (iter_state
!= JSVAL_NULL
)
4011 OBJ_ENUMERATE(cx
, obj
, JSENUMERATE_DESTROY
, &iter_state
, 0);
4013 JS_DestroyIdArray(cx
, ida
);
4018 * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
4019 * prop_iterator_class somehow...
4020 * + preserve the OBJ_ENUMERATE API while optimizing the native object case
4021 * + native case here uses a JSScopeProperty *, but that iterates in reverse!
4022 * + so we make non-native match, by reverse-iterating after JS_Enumerating
4024 #define JSSLOT_ITER_INDEX (JSSLOT_PRIVATE + 1)
4026 #if JSSLOT_ITER_INDEX >= JS_INITIAL_NSLOTS
4027 # error "JSSLOT_ITER_INDEX botch!"
4031 prop_iter_finalize(JSContext
*cx
, JSObject
*obj
)
4037 v
= obj
->fslots
[JSSLOT_ITER_INDEX
];
4038 if (JSVAL_IS_VOID(v
))
4041 i
= JSVAL_TO_INT(v
);
4043 /* Non-native case: destroy the ida enumerated when obj was created. */
4044 ida
= (JSIdArray
*) JS_GetPrivate(cx
, obj
);
4046 JS_DestroyIdArray(cx
, ida
);
4051 prop_iter_trace(JSTracer
*trc
, JSObject
*obj
)
4055 JSScopeProperty
*sprop
;
4059 v
= obj
->fslots
[JSSLOT_PRIVATE
];
4060 JS_ASSERT(!JSVAL_IS_VOID(v
));
4062 i
= JSVAL_TO_INT(obj
->fslots
[JSSLOT_ITER_INDEX
]);
4064 /* Native case: just mark the next property to visit. */
4065 sprop
= (JSScopeProperty
*) JSVAL_TO_PRIVATE(v
);
4067 TRACE_SCOPE_PROPERTY(trc
, sprop
);
4069 /* Non-native case: mark each id in the JSIdArray private. */
4070 ida
= (JSIdArray
*) JSVAL_TO_PRIVATE(v
);
4071 for (i
= 0, n
= ida
->length
; i
< n
; i
++) {
4072 id
= ida
->vector
[i
];
4078 static JSClass prop_iter_class
= {
4080 JSCLASS_HAS_PRIVATE
| JSCLASS_HAS_RESERVED_SLOTS(1) |
4081 JSCLASS_MARK_IS_TRACE
,
4082 JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
,
4083 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, prop_iter_finalize
,
4084 NULL
, NULL
, NULL
, NULL
,
4085 NULL
, NULL
, JS_CLASS_TRACE(prop_iter_trace
), NULL
4088 JS_PUBLIC_API(JSObject
*)
4089 JS_NewPropertyIterator(JSContext
*cx
, JSObject
*obj
)
4098 iterobj
= js_NewObject(cx
, &prop_iter_class
, NULL
, obj
, 0);
4102 if (OBJ_IS_NATIVE(obj
)) {
4103 /* Native case: start with the last property in obj's own scope. */
4104 scope
= OBJ_SCOPE(obj
);
4105 pdata
= (scope
->object
== obj
) ? scope
->lastProp
: NULL
;
4108 JSTempValueRooter tvr
;
4111 * Non-native case: enumerate a JSIdArray and keep it via private.
4113 * Note: we have to make sure that we root obj around the call to
4114 * JS_Enumerate to protect against multiple allocations under it.
4116 JS_PUSH_SINGLE_TEMP_ROOT(cx
, OBJECT_TO_JSVAL(iterobj
), &tvr
);
4117 ida
= JS_Enumerate(cx
, obj
);
4118 JS_POP_TEMP_ROOT(cx
, &tvr
);
4122 index
= ida
->length
;
4125 /* iterobj cannot escape to other threads here. */
4126 STOBJ_SET_SLOT(iterobj
, JSSLOT_PRIVATE
, PRIVATE_TO_JSVAL(pdata
));
4127 STOBJ_SET_SLOT(iterobj
, JSSLOT_ITER_INDEX
, INT_TO_JSVAL(index
));
4131 cx
->weakRoots
.newborn
[GCX_OBJECT
] = NULL
;
4135 JS_PUBLIC_API(JSBool
)
4136 JS_NextProperty(JSContext
*cx
, JSObject
*iterobj
, jsid
*idp
)
4141 JSScopeProperty
*sprop
;
4145 i
= JSVAL_TO_INT(OBJ_GET_SLOT(cx
, iterobj
, JSSLOT_ITER_INDEX
));
4147 /* Native case: private data is a property tree node pointer. */
4148 obj
= OBJ_GET_PARENT(cx
, iterobj
);
4149 JS_ASSERT(OBJ_IS_NATIVE(obj
));
4150 scope
= OBJ_SCOPE(obj
);
4151 JS_ASSERT(scope
->object
== obj
);
4152 sprop
= (JSScopeProperty
*) JS_GetPrivate(cx
, iterobj
);
4155 * If the next property mapped by scope in the property tree ancestor
4156 * line is not enumerable, or it's an alias, or one or more properties
4157 * were deleted from the "middle" of the scope-mapped ancestor line
4158 * and the next property was among those deleted, skip it and keep on
4159 * trying to find an enumerable property that is still in scope.
4162 (!(sprop
->attrs
& JSPROP_ENUMERATE
) ||
4163 (sprop
->flags
& SPROP_IS_ALIAS
) ||
4164 (SCOPE_HAD_MIDDLE_DELETE(scope
) &&
4165 !SCOPE_HAS_PROPERTY(scope
, sprop
)))) {
4166 sprop
= sprop
->parent
;
4172 if (!JS_SetPrivate(cx
, iterobj
, sprop
->parent
))
4177 /* Non-native case: use the ida enumerated when iterobj was created. */
4178 ida
= (JSIdArray
*) JS_GetPrivate(cx
, iterobj
);
4179 JS_ASSERT(i
<= ida
->length
);
4183 *idp
= ida
->vector
[--i
];
4184 STOBJ_SET_SLOT(iterobj
, JSSLOT_ITER_INDEX
, INT_TO_JSVAL(i
));
4190 JS_PUBLIC_API(JSBool
)
4191 JS_CheckAccess(JSContext
*cx
, JSObject
*obj
, jsid id
, JSAccessMode mode
,
4192 jsval
*vp
, uintN
*attrsp
)
4195 return OBJ_CHECK_ACCESS(cx
, obj
, id
, mode
, vp
, attrsp
);
4199 ReservedSlotIndexOK(JSContext
*cx
, JSObject
*obj
, JSClass
*clasp
,
4200 uint32 index
, uint32 limit
)
4202 /* Check the computed, possibly per-instance, upper bound. */
4203 if (clasp
->reserveSlots
)
4204 JS_LOCK_OBJ_VOID(cx
, obj
, limit
+= clasp
->reserveSlots(cx
, obj
));
4205 if (index
>= limit
) {
4206 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4207 JSMSG_RESERVED_SLOT_RANGE
);
4213 JS_PUBLIC_API(JSBool
)
4214 JS_GetReservedSlot(JSContext
*cx
, JSObject
*obj
, uint32 index
, jsval
*vp
)
4220 clasp
= OBJ_GET_CLASS(cx
, obj
);
4221 limit
= JSCLASS_RESERVED_SLOTS(clasp
);
4222 if (index
>= limit
&& !ReservedSlotIndexOK(cx
, obj
, clasp
, index
, limit
))
4224 slot
= JSSLOT_START(clasp
) + index
;
4225 *vp
= OBJ_GET_REQUIRED_SLOT(cx
, obj
, slot
);
4229 JS_PUBLIC_API(JSBool
)
4230 JS_SetReservedSlot(JSContext
*cx
, JSObject
*obj
, uint32 index
, jsval v
)
4236 clasp
= OBJ_GET_CLASS(cx
, obj
);
4237 limit
= JSCLASS_RESERVED_SLOTS(clasp
);
4238 if (index
>= limit
&& !ReservedSlotIndexOK(cx
, obj
, clasp
, index
, limit
))
4240 slot
= JSSLOT_START(clasp
) + index
;
4241 return OBJ_SET_REQUIRED_SLOT(cx
, obj
, slot
, v
);
4244 #ifdef JS_THREADSAFE
4245 JS_PUBLIC_API(jsrefcount
)
4246 JS_HoldPrincipals(JSContext
*cx
, JSPrincipals
*principals
)
4248 return JS_ATOMIC_INCREMENT(&principals
->refcount
);
4251 JS_PUBLIC_API(jsrefcount
)
4252 JS_DropPrincipals(JSContext
*cx
, JSPrincipals
*principals
)
4254 jsrefcount rc
= JS_ATOMIC_DECREMENT(&principals
->refcount
);
4256 principals
->destroy(cx
, principals
);
4261 JS_PUBLIC_API(JSSecurityCallbacks
*)
4262 JS_SetRuntimeSecurityCallbacks(JSRuntime
*rt
, JSSecurityCallbacks
*callbacks
)
4264 JSSecurityCallbacks
*oldcallbacks
;
4266 oldcallbacks
= rt
->securityCallbacks
;
4267 rt
->securityCallbacks
= callbacks
;
4268 return oldcallbacks
;
4271 JS_PUBLIC_API(JSSecurityCallbacks
*)
4272 JS_GetRuntimeSecurityCallbacks(JSRuntime
*rt
)
4274 return rt
->securityCallbacks
;
4277 JS_PUBLIC_API(JSSecurityCallbacks
*)
4278 JS_SetContextSecurityCallbacks(JSContext
*cx
, JSSecurityCallbacks
*callbacks
)
4280 JSSecurityCallbacks
*oldcallbacks
;
4282 oldcallbacks
= cx
->securityCallbacks
;
4283 cx
->securityCallbacks
= callbacks
;
4284 return oldcallbacks
;
4287 JS_PUBLIC_API(JSSecurityCallbacks
*)
4288 JS_GetSecurityCallbacks(JSContext
*cx
)
4290 return cx
->securityCallbacks
4291 ? cx
->securityCallbacks
4292 : cx
->runtime
->securityCallbacks
;
4295 JS_PUBLIC_API(JSFunction
*)
4296 JS_NewFunction(JSContext
*cx
, JSNative native
, uintN nargs
, uintN flags
,
4297 JSObject
*parent
, const char *name
)
4306 atom
= js_Atomize(cx
, name
, strlen(name
), 0);
4310 return js_NewFunction(cx
, NULL
, native
, nargs
, flags
, parent
, atom
);
4313 JS_PUBLIC_API(JSObject
*)
4314 JS_CloneFunctionObject(JSContext
*cx
, JSObject
*funobj
, JSObject
*parent
)
4317 if (OBJ_GET_CLASS(cx
, funobj
) != &js_FunctionClass
) {
4319 * We cannot clone this object, so fail (we used to return funobj, bad
4320 * idea, but we changed incompatibly to teach any abusers a lesson!).
4322 jsval v
= OBJECT_TO_JSVAL(funobj
);
4323 js_ReportIsNotFunction(cx
, &v
, 0);
4327 JSFunction
*fun
= GET_FUNCTION_PRIVATE(cx
, funobj
);
4328 JSObject
*clone
= js_CloneFunctionObject(cx
, fun
, parent
);
4333 * A flat closure carries its own environment, so why clone it? In case
4334 * someone wants to mutate its fixed slots or add ad-hoc properties. API
4335 * compatibility suggests we not return funobj and let callers mutate the
4336 * returned object at will.
4338 * But it's worse than that: API compatibility according to the test for
4339 * bug 300079 requires we get "upvars" from parent and its ancestors! So
4340 * we do that (grudgingly!). The scope chain ancestors are searched as if
4341 * they were activations, respecting the skip field in each upvar's cookie
4342 * but looking up the property by name instead of frame slot.
4344 if (FUN_FLAT_CLOSURE(fun
)) {
4345 JS_ASSERT(funobj
->dslots
);
4346 JS_ASSERT(JSSLOT_FREE(&js_FunctionClass
) == JS_INITIAL_NSLOTS
);
4348 uint32 nslots
= JSSLOT_FREE(&js_FunctionClass
);
4349 JS_ASSERT(nslots
== JS_INITIAL_NSLOTS
);
4350 nslots
+= js_FunctionClass
.reserveSlots(cx
, clone
);
4351 if (!js_ReallocSlots(cx
, clone
, nslots
, JS_TRUE
))
4354 JSUpvarArray
*uva
= JS_SCRIPT_UPVARS(fun
->u
.i
.script
);
4355 JS_ASSERT(uva
->length
<= size_t(clone
->dslots
[-1]));
4357 void *mark
= JS_ARENA_MARK(&cx
->tempPool
);
4358 jsuword
*names
= js_GetLocalNameArray(cx
, fun
, &cx
->tempPool
);
4362 uint32 i
= 0, n
= uva
->length
;
4363 for (; i
< n
; i
++) {
4364 JSObject
*obj
= parent
;
4365 int skip
= UPVAR_FRAME_SKIP(uva
->vector
[i
]);
4366 while (--skip
> 0) {
4368 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
4369 JSMSG_BAD_CLONE_FUNOBJ_SCOPE
);
4372 obj
= OBJ_GET_PARENT(cx
, obj
);
4375 JSAtom
*atom
= JS_LOCAL_NAME_TO_ATOM(names
[i
]);
4376 if (!OBJ_GET_PROPERTY(cx
, obj
, ATOM_TO_JSID(atom
), &clone
->dslots
[i
]))
4381 JS_ARENA_RELEASE(&cx
->tempPool
, mark
);
4389 JS_PUBLIC_API(JSObject
*)
4390 JS_GetFunctionObject(JSFunction
*fun
)
4392 return FUN_OBJECT(fun
);
4395 JS_PUBLIC_API(const char *)
4396 JS_GetFunctionName(JSFunction
*fun
)
4399 ? JS_GetStringBytes(ATOM_TO_STRING(fun
->atom
))
4403 JS_PUBLIC_API(JSString
*)
4404 JS_GetFunctionId(JSFunction
*fun
)
4406 return fun
->atom
? ATOM_TO_STRING(fun
->atom
) : NULL
;
4409 JS_PUBLIC_API(uintN
)
4410 JS_GetFunctionFlags(JSFunction
*fun
)
4415 JS_PUBLIC_API(uint16
)
4416 JS_GetFunctionArity(JSFunction
*fun
)
4421 JS_PUBLIC_API(JSBool
)
4422 JS_ObjectIsFunction(JSContext
*cx
, JSObject
*obj
)
4424 return OBJ_GET_CLASS(cx
, obj
) == &js_FunctionClass
;
4429 js_generic_fast_native_method_dispatcher(JSContext
*cx
, uintN argc
, jsval
*vp
)
4434 JSFastNative native
;
4436 if (!JS_GetReservedSlot(cx
, JSVAL_TO_OBJECT(*vp
), 0, &fsv
))
4438 fs
= (JSFunctionSpec
*) JSVAL_TO_PRIVATE(fsv
);
4439 JS_ASSERT((~fs
->flags
& (JSFUN_FAST_NATIVE
| JSFUN_GENERIC_NATIVE
)) == 0);
4442 * We know that vp[2] is valid because JS_DefineFunctions, which is our
4443 * only (indirect) referrer, defined us as requiring at least one argument
4444 * (notice how it passes fs->nargs + 1 as the next-to-last argument to
4445 * JS_DefineFunction).
4447 if (JSVAL_IS_PRIMITIVE(vp
[2])) {
4449 * Make sure that this is an object or null, as required by the generic
4452 if (!js_ValueToObject(cx
, vp
[2], &tmp
))
4454 vp
[2] = OBJECT_TO_JSVAL(tmp
);
4458 * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
4459 * which is almost always the class constructor object, e.g. Array. Then
4460 * call the corresponding prototype native method with our first argument
4463 memmove(vp
+ 1, vp
+ 2, argc
* sizeof(jsval
));
4466 * Follow Function.prototype.apply and .call by using the global object as
4467 * the 'this' param if no args.
4469 if (!js_ComputeThis(cx
, JS_FALSE
, vp
+ 2))
4472 * Protect against argc underflowing. By calling js_ComputeThis, we made
4473 * it as if the static was called with one parameter, the explicit |this|
4477 /* Clear the last parameter in case too few arguments were passed. */
4478 vp
[2 + --argc
] = JSVAL_VOID
;
4483 (fs
->flags
& JSFUN_TRACEABLE
)
4484 ? JS_FUNC_TO_DATA_PTR(JSTraceableNative
*, fs
->call
)->native
4487 (JSFastNative
) fs
->call
;
4488 return native(cx
, argc
, vp
);
4492 js_generic_native_method_dispatcher(JSContext
*cx
, JSObject
*obj
,
4493 uintN argc
, jsval
*argv
, jsval
*rval
)
4499 if (!JS_GetReservedSlot(cx
, JSVAL_TO_OBJECT(argv
[-2]), 0, &fsv
))
4501 fs
= (JSFunctionSpec
*) JSVAL_TO_PRIVATE(fsv
);
4502 JS_ASSERT((fs
->flags
& (JSFUN_FAST_NATIVE
| JSFUN_GENERIC_NATIVE
)) ==
4503 JSFUN_GENERIC_NATIVE
);
4506 * We know that argv[0] is valid because JS_DefineFunctions, which is our
4507 * only (indirect) referrer, defined us as requiring at least one argument
4508 * (notice how it passes fs->nargs + 1 as the next-to-last argument to
4509 * JS_DefineFunction).
4511 if (JSVAL_IS_PRIMITIVE(argv
[0])) {
4513 * Make sure that this is an object or null, as required by the generic
4516 if (!js_ValueToObject(cx
, argv
[0], &tmp
))
4518 argv
[0] = OBJECT_TO_JSVAL(tmp
);
4522 * Copy all actual (argc) arguments down over our |this| parameter,
4523 * argv[-1], which is almost always the class constructor object, e.g.
4524 * Array. Then call the corresponding prototype native method with our
4525 * first argument passed as |this|.
4527 memmove(argv
- 1, argv
, argc
* sizeof(jsval
));
4530 * Follow Function.prototype.apply and .call by using the global object as
4531 * the 'this' param if no args.
4533 if (!js_ComputeThis(cx
, JS_TRUE
, argv
))
4535 js_GetTopStackFrame(cx
)->thisp
= JSVAL_TO_OBJECT(argv
[-1]);
4536 JS_ASSERT(cx
->fp
->argv
== argv
);
4539 * Protect against argc underflowing. By calling js_ComputeThis, we made
4540 * it as if the static was called with one parameter, the explicit |this|
4544 /* Clear the last parameter in case too few arguments were passed. */
4545 argv
[--argc
] = JSVAL_VOID
;
4548 return fs
->call(cx
, JSVAL_TO_OBJECT(argv
[-1]), argc
, argv
, rval
);
4552 JS_PUBLIC_API(JSBool
)
4553 JS_DefineFunctions(JSContext
*cx
, JSObject
*obj
, JSFunctionSpec
*fs
)
4561 for (; fs
->name
; fs
++) {
4565 * Define a generic arity N+1 static method for the arity N prototype
4566 * method if flags contains JSFUN_GENERIC_NATIVE.
4568 if (flags
& JSFUN_GENERIC_NATIVE
) {
4570 ctor
= JS_GetConstructor(cx
, obj
);
4575 flags
&= ~JSFUN_GENERIC_NATIVE
;
4576 fun
= JS_DefineFunction(cx
, ctor
, fs
->name
,
4577 (flags
& JSFUN_FAST_NATIVE
)
4579 js_generic_fast_native_method_dispatcher
4580 : js_generic_native_method_dispatcher
,
4582 flags
& ~JSFUN_TRACEABLE
);
4585 fun
->u
.n
.extra
= (uint16
)fs
->extra
;
4588 * As jsapi.h notes, fs must point to storage that lives as long
4589 * as fun->object lives.
4591 if (!JS_SetReservedSlot(cx
, FUN_OBJECT(fun
), 0, PRIVATE_TO_JSVAL(fs
)))
4595 JS_ASSERT(!(flags
& JSFUN_FAST_NATIVE
) ||
4596 (uint16
)(fs
->extra
>> 16) <= fs
->nargs
);
4597 fun
= JS_DefineFunction(cx
, obj
, fs
->name
, fs
->call
, fs
->nargs
, flags
);
4600 fun
->u
.n
.extra
= (uint16
)fs
->extra
;
4605 JS_PUBLIC_API(JSFunction
*)
4606 JS_DefineFunction(JSContext
*cx
, JSObject
*obj
, const char *name
, JSNative call
,
4607 uintN nargs
, uintN attrs
)
4612 atom
= js_Atomize(cx
, name
, strlen(name
), 0);
4615 return js_DefineFunction(cx
, obj
, atom
, call
, nargs
, attrs
);
4618 JS_PUBLIC_API(JSFunction
*)
4619 JS_DefineUCFunction(JSContext
*cx
, JSObject
*obj
,
4620 const jschar
*name
, size_t namelen
, JSNative call
,
4621 uintN nargs
, uintN attrs
)
4625 atom
= js_AtomizeChars(cx
, name
, AUTO_NAMELEN(name
, namelen
), 0);
4628 return js_DefineFunction(cx
, obj
, atom
, call
, nargs
, attrs
);
4631 JS_PUBLIC_API(JSScript
*)
4632 JS_CompileScript(JSContext
*cx
, JSObject
*obj
,
4633 const char *bytes
, size_t length
,
4634 const char *filename
, uintN lineno
)
4640 chars
= js_InflateString(cx
, bytes
, &length
);
4643 script
= JS_CompileUCScript(cx
, obj
, chars
, length
, filename
, lineno
);
4648 JS_PUBLIC_API(JSScript
*)
4649 JS_CompileScriptForPrincipals(JSContext
*cx
, JSObject
*obj
,
4650 JSPrincipals
*principals
,
4651 const char *bytes
, size_t length
,
4652 const char *filename
, uintN lineno
)
4658 chars
= js_InflateString(cx
, bytes
, &length
);
4661 script
= JS_CompileUCScriptForPrincipals(cx
, obj
, principals
,
4662 chars
, length
, filename
, lineno
);
4667 JS_PUBLIC_API(JSScript
*)
4668 JS_CompileUCScript(JSContext
*cx
, JSObject
*obj
,
4669 const jschar
*chars
, size_t length
,
4670 const char *filename
, uintN lineno
)
4673 return JS_CompileUCScriptForPrincipals(cx
, obj
, NULL
, chars
, length
,
4677 #define LAST_FRAME_EXCEPTION_CHECK(cx,result) \
4679 if (!(result) && !((cx)->options & JSOPTION_DONT_REPORT_UNCAUGHT)) \
4680 js_ReportUncaughtException(cx); \
4683 #define LAST_FRAME_CHECKS(cx,result) \
4685 if (!JS_IsRunning(cx)) { \
4686 (cx)->weakRoots.lastInternalResult = JSVAL_NULL; \
4687 LAST_FRAME_EXCEPTION_CHECK(cx, result); \
4691 #define JS_OPTIONS_TO_TCFLAGS(cx) \
4692 ((((cx)->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) | \
4693 (((cx)->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0))
4695 JS_PUBLIC_API(JSScript
*)
4696 JS_CompileUCScriptForPrincipals(JSContext
*cx
, JSObject
*obj
,
4697 JSPrincipals
*principals
,
4698 const jschar
*chars
, size_t length
,
4699 const char *filename
, uintN lineno
)
4705 tcflags
= JS_OPTIONS_TO_TCFLAGS(cx
);
4706 script
= JSCompiler::compileScript(cx
, obj
, NULL
, principals
, tcflags
,
4707 chars
, length
, NULL
, filename
, lineno
);
4708 LAST_FRAME_CHECKS(cx
, script
);
4712 JS_PUBLIC_API(JSBool
)
4713 JS_BufferIsCompilableUnit(JSContext
*cx
, JSObject
*obj
,
4714 const char *bytes
, size_t length
)
4718 JSExceptionState
*exnState
;
4719 JSErrorReporter older
;
4722 chars
= js_InflateString(cx
, bytes
, &length
);
4727 * Return true on any out-of-memory error, so our caller doesn't try to
4728 * collect more buffered source.
4731 exnState
= JS_SaveExceptionState(cx
);
4734 if (jsc
.init(chars
, length
, NULL
, NULL
, 1)) {
4735 older
= JS_SetErrorReporter(cx
, NULL
);
4736 if (!jsc
.parse(obj
) &&
4737 (jsc
.tokenStream
.flags
& TSF_UNEXPECTED_EOF
)) {
4739 * We ran into an error. If it was because we ran out of
4740 * source, we return false so our caller knows to try to
4741 * collect more buffered source.
4745 JS_SetErrorReporter(cx
, older
);
4749 JS_RestoreExceptionState(cx
, exnState
);
4753 JS_PUBLIC_API(JSScript
*)
4754 JS_CompileFile(JSContext
*cx
, JSObject
*obj
, const char *filename
)
4761 if (!filename
|| strcmp(filename
, "-") == 0) {
4764 fp
= fopen(filename
, "r");
4766 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_CANT_OPEN
,
4767 filename
, "No such file or directory");
4772 tcflags
= JS_OPTIONS_TO_TCFLAGS(cx
);
4773 script
= JSCompiler::compileScript(cx
, obj
, NULL
, NULL
, tcflags
,
4774 NULL
, 0, fp
, filename
, 1);
4777 LAST_FRAME_CHECKS(cx
, script
);
4781 JS_PUBLIC_API(JSScript
*)
4782 JS_CompileFileHandle(JSContext
*cx
, JSObject
*obj
, const char *filename
,
4785 return JS_CompileFileHandleForPrincipals(cx
, obj
, filename
, file
, NULL
);
4788 JS_PUBLIC_API(JSScript
*)
4789 JS_CompileFileHandleForPrincipals(JSContext
*cx
, JSObject
*obj
,
4790 const char *filename
, FILE *file
,
4791 JSPrincipals
*principals
)
4797 tcflags
= JS_OPTIONS_TO_TCFLAGS(cx
);
4798 script
= JSCompiler::compileScript(cx
, obj
, NULL
, principals
, tcflags
,
4799 NULL
, 0, file
, filename
, 1);
4800 LAST_FRAME_CHECKS(cx
, script
);
4804 JS_PUBLIC_API(JSObject
*)
4805 JS_NewScriptObject(JSContext
*cx
, JSScript
*script
)
4807 JSTempValueRooter tvr
;
4812 return js_NewObject(cx
, &js_ScriptClass
, NULL
, NULL
, 0);
4814 JS_ASSERT(!script
->u
.object
);
4816 JS_PUSH_TEMP_ROOT_SCRIPT(cx
, script
, &tvr
);
4817 obj
= js_NewObject(cx
, &js_ScriptClass
, NULL
, NULL
, 0);
4819 JS_SetPrivate(cx
, obj
, script
);
4820 script
->u
.object
= obj
;
4821 #ifdef CHECK_SCRIPT_OWNER
4822 script
->owner
= NULL
;
4825 JS_POP_TEMP_ROOT(cx
, &tvr
);
4829 JS_PUBLIC_API(JSObject
*)
4830 JS_GetScriptObject(JSScript
*script
)
4832 return script
->u
.object
;
4836 JS_DestroyScript(JSContext
*cx
, JSScript
*script
)
4839 js_DestroyScript(cx
, script
);
4842 JS_PUBLIC_API(JSFunction
*)
4843 JS_CompileFunction(JSContext
*cx
, JSObject
*obj
, const char *name
,
4844 uintN nargs
, const char **argnames
,
4845 const char *bytes
, size_t length
,
4846 const char *filename
, uintN lineno
)
4852 chars
= js_InflateString(cx
, bytes
, &length
);
4855 fun
= JS_CompileUCFunction(cx
, obj
, name
, nargs
, argnames
, chars
, length
,
4861 JS_PUBLIC_API(JSFunction
*)
4862 JS_CompileFunctionForPrincipals(JSContext
*cx
, JSObject
*obj
,
4863 JSPrincipals
*principals
, const char *name
,
4864 uintN nargs
, const char **argnames
,
4865 const char *bytes
, size_t length
,
4866 const char *filename
, uintN lineno
)
4872 chars
= js_InflateString(cx
, bytes
, &length
);
4875 fun
= JS_CompileUCFunctionForPrincipals(cx
, obj
, principals
, name
,
4876 nargs
, argnames
, chars
, length
,
4882 JS_PUBLIC_API(JSFunction
*)
4883 JS_CompileUCFunction(JSContext
*cx
, JSObject
*obj
, const char *name
,
4884 uintN nargs
, const char **argnames
,
4885 const jschar
*chars
, size_t length
,
4886 const char *filename
, uintN lineno
)
4889 return JS_CompileUCFunctionForPrincipals(cx
, obj
, NULL
, name
,
4895 JS_PUBLIC_API(JSFunction
*)
4896 JS_CompileUCFunctionForPrincipals(JSContext
*cx
, JSObject
*obj
,
4897 JSPrincipals
*principals
, const char *name
,
4898 uintN nargs
, const char **argnames
,
4899 const jschar
*chars
, size_t length
,
4900 const char *filename
, uintN lineno
)
4903 JSTempValueRooter tvr
;
4904 JSAtom
*funAtom
, *argAtom
;
4911 funAtom
= js_Atomize(cx
, name
, strlen(name
), 0);
4917 fun
= js_NewFunction(cx
, NULL
, NULL
, 0, JSFUN_INTERPRETED
, obj
, funAtom
);
4921 MUST_FLOW_THROUGH("out");
4922 JS_PUSH_TEMP_ROOT_OBJECT(cx
, FUN_OBJECT(fun
), &tvr
);
4923 for (i
= 0; i
< nargs
; i
++) {
4924 argAtom
= js_Atomize(cx
, argnames
[i
], strlen(argnames
[i
]), 0);
4929 if (!js_AddLocal(cx
, fun
, argAtom
, JSLOCAL_ARG
)) {
4935 if (!JSCompiler::compileFunctionBody(cx
, fun
, principals
,
4936 chars
, length
, filename
, lineno
)) {
4943 !OBJ_DEFINE_PROPERTY(cx
, obj
, ATOM_TO_JSID(funAtom
),
4944 OBJECT_TO_JSVAL(FUN_OBJECT(fun
)),
4945 NULL
, NULL
, JSPROP_ENUMERATE
, NULL
)) {
4949 #ifdef JS_SCOPE_DEPTH_METER
4951 JSObject
*pobj
= obj
;
4954 while ((pobj
= OBJ_GET_PARENT(cx
, pobj
)) != NULL
)
4956 JS_BASIC_STATS_ACCUM(&cx
->runtime
->hostenvScopeDepthStats
, depth
);
4961 cx
->weakRoots
.newborn
[JSTRACE_OBJECT
] = FUN_OBJECT(fun
);
4962 JS_POP_TEMP_ROOT(cx
, &tvr
);
4965 LAST_FRAME_CHECKS(cx
, fun
);
4969 JS_PUBLIC_API(JSString
*)
4970 JS_DecompileScript(JSContext
*cx
, JSScript
*script
, const char *name
,
4977 jp
= JS_NEW_PRINTER(cx
, name
, NULL
,
4978 indent
& ~JS_DONT_PRETTY_PRINT
,
4979 !(indent
& JS_DONT_PRETTY_PRINT
));
4982 if (js_DecompileScript(jp
, script
))
4983 str
= js_GetPrinterOutput(jp
);
4986 js_DestroyPrinter(jp
);
4990 JS_PUBLIC_API(JSString
*)
4991 JS_DecompileFunction(JSContext
*cx
, JSFunction
*fun
, uintN indent
)
4997 jp
= JS_NEW_PRINTER(cx
, "JS_DecompileFunction", fun
,
4998 indent
& ~JS_DONT_PRETTY_PRINT
,
4999 !(indent
& JS_DONT_PRETTY_PRINT
));
5002 if (js_DecompileFunction(jp
))
5003 str
= js_GetPrinterOutput(jp
);
5006 js_DestroyPrinter(jp
);
5010 JS_PUBLIC_API(JSString
*)
5011 JS_DecompileFunctionBody(JSContext
*cx
, JSFunction
*fun
, uintN indent
)
5017 jp
= JS_NEW_PRINTER(cx
, "JS_DecompileFunctionBody", fun
,
5018 indent
& ~JS_DONT_PRETTY_PRINT
,
5019 !(indent
& JS_DONT_PRETTY_PRINT
));
5022 if (js_DecompileFunctionBody(jp
))
5023 str
= js_GetPrinterOutput(jp
);
5026 js_DestroyPrinter(jp
);
5030 JS_PUBLIC_API(JSBool
)
5031 JS_ExecuteScript(JSContext
*cx
, JSObject
*obj
, JSScript
*script
, jsval
*rval
)
5036 ok
= js_Execute(cx
, obj
, script
, NULL
, 0, rval
);
5037 LAST_FRAME_CHECKS(cx
, ok
);
5041 JS_PUBLIC_API(JSBool
)
5042 JS_ExecuteScriptPart(JSContext
*cx
, JSObject
*obj
, JSScript
*script
,
5043 JSExecPart part
, jsval
*rval
)
5046 JSDebugHooks
*hooks
;
5049 /* Make a temporary copy of the JSScript structure and farble it a bit. */
5051 if (part
== JSEXEC_PROLOG
) {
5052 tmp
.length
= tmp
.main
- tmp
.code
;
5054 tmp
.length
-= tmp
.main
- tmp
.code
;
5055 tmp
.code
= tmp
.main
;
5058 /* Tell the debugger about our temporary copy of the script structure. */
5059 hooks
= cx
->debugHooks
;
5060 if (hooks
->newScriptHook
) {
5061 hooks
->newScriptHook(cx
, tmp
.filename
, tmp
.lineno
, &tmp
, NULL
,
5062 hooks
->newScriptHookData
);
5065 /* Execute the farbled struct and tell the debugger to forget about it. */
5066 ok
= JS_ExecuteScript(cx
, obj
, &tmp
, rval
);
5067 if (hooks
->destroyScriptHook
)
5068 hooks
->destroyScriptHook(cx
, &tmp
, hooks
->destroyScriptHookData
);
5072 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
5073 JS_PUBLIC_API(JSBool
)
5074 JS_EvaluateScript(JSContext
*cx
, JSObject
*obj
,
5075 const char *bytes
, uintN nbytes
,
5076 const char *filename
, uintN lineno
,
5079 size_t length
= nbytes
;
5084 chars
= js_InflateString(cx
, bytes
, &length
);
5087 ok
= JS_EvaluateUCScript(cx
, obj
, chars
, length
, filename
, lineno
, rval
);
5092 /* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
5093 JS_PUBLIC_API(JSBool
)
5094 JS_EvaluateScriptForPrincipals(JSContext
*cx
, JSObject
*obj
,
5095 JSPrincipals
*principals
,
5096 const char *bytes
, uintN nbytes
,
5097 const char *filename
, uintN lineno
,
5100 size_t length
= nbytes
;
5105 chars
= js_InflateString(cx
, bytes
, &length
);
5108 ok
= JS_EvaluateUCScriptForPrincipals(cx
, obj
, principals
, chars
, length
,
5109 filename
, lineno
, rval
);
5114 JS_PUBLIC_API(JSBool
)
5115 JS_EvaluateUCScript(JSContext
*cx
, JSObject
*obj
,
5116 const jschar
*chars
, uintN length
,
5117 const char *filename
, uintN lineno
,
5121 return JS_EvaluateUCScriptForPrincipals(cx
, obj
, NULL
, chars
, length
,
5122 filename
, lineno
, rval
);
5125 JS_PUBLIC_API(JSBool
)
5126 JS_EvaluateUCScriptForPrincipals(JSContext
*cx
, JSObject
*obj
,
5127 JSPrincipals
*principals
,
5128 const jschar
*chars
, uintN length
,
5129 const char *filename
, uintN lineno
,
5136 script
= JSCompiler::compileScript(cx
, obj
, NULL
, principals
,
5138 ? TCF_COMPILE_N_GO
| TCF_NO_SCRIPT_RVAL
5140 chars
, length
, NULL
, filename
, lineno
);
5142 LAST_FRAME_CHECKS(cx
, script
);
5145 ok
= js_Execute(cx
, obj
, script
, NULL
, 0, rval
);
5146 LAST_FRAME_CHECKS(cx
, ok
);
5147 JS_DestroyScript(cx
, script
);
5151 JS_PUBLIC_API(JSBool
)
5152 JS_CallFunction(JSContext
*cx
, JSObject
*obj
, JSFunction
*fun
, uintN argc
,
5153 jsval
*argv
, jsval
*rval
)
5158 ok
= js_InternalCall(cx
, obj
, OBJECT_TO_JSVAL(FUN_OBJECT(fun
)), argc
, argv
,
5160 LAST_FRAME_CHECKS(cx
, ok
);
5164 JS_PUBLIC_API(JSBool
)
5165 JS_CallFunctionName(JSContext
*cx
, JSObject
*obj
, const char *name
, uintN argc
,
5166 jsval
*argv
, jsval
*rval
)
5170 JSAutoTempValueRooter
tvr(cx
);
5171 JSAtom
*atom
= js_Atomize(cx
, name
, strlen(name
), 0);
5173 JS_GetMethodById(cx
, obj
, ATOM_TO_JSID(atom
), NULL
,
5175 js_InternalCall(cx
, obj
, tvr
.value(), argc
, argv
, rval
);
5176 LAST_FRAME_CHECKS(cx
, ok
);
5180 JS_PUBLIC_API(JSBool
)
5181 JS_CallFunctionValue(JSContext
*cx
, JSObject
*obj
, jsval fval
, uintN argc
,
5182 jsval
*argv
, jsval
*rval
)
5187 ok
= js_InternalCall(cx
, obj
, fval
, argc
, argv
, rval
);
5188 LAST_FRAME_CHECKS(cx
, ok
);
5192 JS_PUBLIC_API(JSOperationCallback
)
5193 JS_SetOperationCallback(JSContext
*cx
, JSOperationCallback callback
)
5195 #ifdef JS_THREADSAFE
5196 JS_ASSERT(CURRENT_THREAD_IS_ME(cx
->thread
));
5198 JSOperationCallback old
= cx
->operationCallback
;
5199 cx
->operationCallback
= callback
;
5203 JS_PUBLIC_API(JSOperationCallback
)
5204 JS_GetOperationCallback(JSContext
*cx
)
5206 return cx
->operationCallback
;
5210 JS_TriggerOperationCallback(JSContext
*cx
)
5213 * Use JS_ATOMIC_SET in the hope that it will make sure the write
5214 * will become immediately visible to other processors polling
5215 * cx->operationCallbackFlag. Note that we only care about
5216 * visibility here, not read/write ordering.
5218 JS_ATOMIC_SET(&cx
->operationCallbackFlag
, 1);
5222 JS_TriggerAllOperationCallbacks(JSRuntime
*rt
)
5224 js_TriggerAllOperationCallbacks(rt
, JS_FALSE
);
5227 JS_PUBLIC_API(JSBool
)
5228 JS_IsRunning(JSContext
*cx
)
5230 /* The use of cx->fp below is safe: if we're on trace, it is skipped. */
5231 VOUCH_DOES_NOT_REQUIRE_STACK();
5233 return JS_ON_TRACE(cx
) || cx
->fp
!= NULL
;
5236 JS_PUBLIC_API(JSBool
)
5237 JS_IsConstructing(JSContext
*cx
)
5241 fp
= js_GetTopStackFrame(cx
);
5242 return fp
&& (fp
->flags
& JSFRAME_CONSTRUCTING
);
5245 JS_FRIEND_API(JSBool
)
5246 JS_IsAssigning(JSContext
*cx
)
5250 fp
= js_GetScriptedCaller(cx
, NULL
);
5251 if (!fp
|| !fp
->regs
)
5253 return (js_CodeSpec
[*fp
->regs
->pc
].format
& JOF_ASSIGNING
) != 0;
5257 JS_SetCallReturnValue2(JSContext
*cx
, jsval v
)
5259 #if JS_HAS_LVALUE_RETURN
5261 cx
->rval2set
= JS_TRUE
;
5265 JS_PUBLIC_API(JSStackFrame
*)
5266 JS_SaveFrameChain(JSContext
*cx
)
5270 fp
= js_GetTopStackFrame(cx
);
5274 JS_ASSERT(!fp
->dormantNext
);
5275 fp
->dormantNext
= cx
->dormantFrameChain
;
5276 cx
->dormantFrameChain
= fp
;
5282 JS_RestoreFrameChain(JSContext
*cx
, JSStackFrame
*fp
)
5284 JS_ASSERT_NOT_ON_TRACE(cx
);
5289 JS_ASSERT(fp
== cx
->dormantFrameChain
);
5291 cx
->dormantFrameChain
= fp
->dormantNext
;
5292 fp
->dormantNext
= NULL
;
5295 /************************************************************************/
5297 JS_PUBLIC_API(JSString
*)
5298 JS_NewString(JSContext
*cx
, char *bytes
, size_t nbytes
)
5300 size_t length
= nbytes
;
5306 /* Make a UTF-16 vector from the 8-bit char codes in bytes. */
5307 chars
= js_InflateString(cx
, bytes
, &length
);
5311 /* Free chars (but not bytes, which caller frees on error) if we fail. */
5312 str
= js_NewString(cx
, chars
, length
);
5318 /* Hand off bytes to the deflated string cache, if possible. */
5319 if (!js_SetStringBytes(cx
, str
, bytes
, nbytes
))
5324 JS_PUBLIC_API(JSString
*)
5325 JS_NewStringCopyN(JSContext
*cx
, const char *s
, size_t n
)
5331 js
= js_InflateString(cx
, s
, &n
);
5334 str
= js_NewString(cx
, js
, n
);
5340 JS_PUBLIC_API(JSString
*)
5341 JS_NewStringCopyZ(JSContext
*cx
, const char *s
)
5349 return cx
->runtime
->emptyString
;
5351 js
= js_InflateString(cx
, s
, &n
);
5354 str
= js_NewString(cx
, js
, n
);
5360 JS_PUBLIC_API(JSString
*)
5361 JS_InternString(JSContext
*cx
, const char *s
)
5366 atom
= js_Atomize(cx
, s
, strlen(s
), ATOM_INTERNED
);
5369 return ATOM_TO_STRING(atom
);
5372 JS_PUBLIC_API(JSString
*)
5373 JS_NewUCString(JSContext
*cx
, jschar
*chars
, size_t length
)
5376 return js_NewString(cx
, chars
, length
);
5379 JS_PUBLIC_API(JSString
*)
5380 JS_NewUCStringCopyN(JSContext
*cx
, const jschar
*s
, size_t n
)
5383 return js_NewStringCopyN(cx
, s
, n
);
5386 JS_PUBLIC_API(JSString
*)
5387 JS_NewUCStringCopyZ(JSContext
*cx
, const jschar
*s
)
5391 return cx
->runtime
->emptyString
;
5392 return js_NewStringCopyZ(cx
, s
);
5395 JS_PUBLIC_API(JSString
*)
5396 JS_InternUCStringN(JSContext
*cx
, const jschar
*s
, size_t length
)
5401 atom
= js_AtomizeChars(cx
, s
, length
, ATOM_INTERNED
);
5404 return ATOM_TO_STRING(atom
);
5407 JS_PUBLIC_API(JSString
*)
5408 JS_InternUCString(JSContext
*cx
, const jschar
*s
)
5410 return JS_InternUCStringN(cx
, s
, js_strlen(s
));
5413 JS_PUBLIC_API(char *)
5414 JS_GetStringBytes(JSString
*str
)
5418 bytes
= js_GetStringBytes(NULL
, str
);
5419 return (char *)(bytes
? bytes
: "");
5422 JS_PUBLIC_API(jschar
*)
5423 JS_GetStringChars(JSString
*str
)
5429 * API botch (again, shades of JS_GetStringBytes): we have no cx to report
5430 * out-of-memory when undepending strings, so we replace js_UndependString
5431 * with explicit malloc call and ignore its errors.
5433 * If we fail to convert a dependent string into an independent one, our
5434 * caller will not be guaranteed a \u0000 terminator as a backstop. This
5435 * may break some clients who already misbehave on embedded NULs.
5437 * The gain of dependent strings, which cure quadratic and cubic growth
5438 * rate bugs in string concatenation, is worth this slight loss in API
5441 if (JSSTRING_IS_DEPENDENT(str
)) {
5442 n
= JSSTRDEP_LENGTH(str
);
5443 size
= (n
+ 1) * sizeof(jschar
);
5444 s
= (jschar
*) malloc(size
);
5446 memcpy(s
, JSSTRDEP_CHARS(str
), n
* sizeof *s
);
5448 JSFLATSTR_REINIT(str
, s
, n
);
5450 s
= JSSTRDEP_CHARS(str
);
5453 JSFLATSTR_CLEAR_MUTABLE(str
);
5454 s
= JSFLATSTR_CHARS(str
);
5459 JS_PUBLIC_API(size_t)
5460 JS_GetStringLength(JSString
*str
)
5462 return JSSTRING_LENGTH(str
);
5466 JS_CompareStrings(JSString
*str1
, JSString
*str2
)
5468 return js_CompareStrings(str1
, str2
);
5471 JS_PUBLIC_API(JSString
*)
5472 JS_NewGrowableString(JSContext
*cx
, jschar
*chars
, size_t length
)
5477 str
= js_NewString(cx
, chars
, length
);
5480 JSFLATSTR_SET_MUTABLE(str
);
5484 JS_PUBLIC_API(JSString
*)
5485 JS_NewDependentString(JSContext
*cx
, JSString
*str
, size_t start
,
5489 return js_NewDependentString(cx
, str
, start
, length
);
5492 JS_PUBLIC_API(JSString
*)
5493 JS_ConcatStrings(JSContext
*cx
, JSString
*left
, JSString
*right
)
5496 return js_ConcatStrings(cx
, left
, right
);
5499 JS_PUBLIC_API(const jschar
*)
5500 JS_UndependString(JSContext
*cx
, JSString
*str
)
5503 return js_UndependString(cx
, str
);
5506 JS_PUBLIC_API(JSBool
)
5507 JS_MakeStringImmutable(JSContext
*cx
, JSString
*str
)
5510 return js_MakeStringImmutable(cx
, str
);
5513 JS_PUBLIC_API(JSBool
)
5514 JS_EncodeCharacters(JSContext
*cx
, const jschar
*src
, size_t srclen
, char *dst
,
5520 n
= js_GetDeflatedStringLength(cx
, src
, srclen
);
5521 if (n
== (size_t)-1) {
5529 return js_DeflateStringToBuffer(cx
, src
, srclen
, dst
, dstlenp
);
5532 JS_PUBLIC_API(JSBool
)
5533 JS_DecodeBytes(JSContext
*cx
, const char *src
, size_t srclen
, jschar
*dst
,
5536 return js_InflateStringToBuffer(cx
, src
, srclen
, dst
, dstlenp
);
5539 JS_PUBLIC_API(char *)
5540 JS_EncodeString(JSContext
*cx
, JSString
*str
)
5542 return js_DeflateString(cx
, JSSTRING_CHARS(str
), JSSTRING_LENGTH(str
));
5545 JS_PUBLIC_API(JSBool
)
5546 JS_Stringify(JSContext
*cx
, jsval
*vp
, JSObject
*replacer
,
5547 JSONWriteCallback callback
, void *data
)
5550 return js_Stringify(cx
, vp
, replacer
, callback
, data
, 0);
5553 JS_PUBLIC_API(JSBool
)
5554 JS_TryJSON(JSContext
*cx
, jsval
*vp
)
5557 return js_TryJSON(cx
, vp
);
5560 JS_PUBLIC_API(JSONParser
*)
5561 JS_BeginJSONParse(JSContext
*cx
, jsval
*vp
)
5564 return js_BeginJSONParse(cx
, vp
);
5567 JS_PUBLIC_API(JSBool
)
5568 JS_ConsumeJSONText(JSContext
*cx
, JSONParser
*jp
, const jschar
*data
, uint32 len
)
5571 return js_ConsumeJSONText(cx
, jp
, data
, len
);
5574 JS_PUBLIC_API(JSBool
)
5575 JS_FinishJSONParse(JSContext
*cx
, JSONParser
*jp
, jsval reviver
)
5578 return js_FinishJSONParse(cx
, jp
, reviver
);
5582 * The following determines whether C Strings are to be treated as UTF-8
5583 * or ISO-8859-1. For correct operation, it must be set prior to the
5584 * first call to JS_NewRuntime.
5586 #ifndef JS_C_STRINGS_ARE_UTF8
5587 JSBool js_CStringsAreUTF8
= JS_FALSE
;
5590 JS_PUBLIC_API(JSBool
)
5591 JS_CStringsAreUTF8()
5593 return js_CStringsAreUTF8
;
5597 JS_SetCStringsAreUTF8()
5599 JS_ASSERT(!js_NewRuntimeWasCalled
);
5601 #ifndef JS_C_STRINGS_ARE_UTF8
5602 js_CStringsAreUTF8
= JS_TRUE
;
5606 /************************************************************************/
5609 JS_ReportError(JSContext
*cx
, const char *format
, ...)
5613 va_start(ap
, format
);
5614 js_ReportErrorVA(cx
, JSREPORT_ERROR
, format
, ap
);
5619 JS_ReportErrorNumber(JSContext
*cx
, JSErrorCallback errorCallback
,
5620 void *userRef
, const uintN errorNumber
, ...)
5624 va_start(ap
, errorNumber
);
5625 js_ReportErrorNumberVA(cx
, JSREPORT_ERROR
, errorCallback
, userRef
,
5626 errorNumber
, JS_TRUE
, ap
);
5631 JS_ReportErrorNumberUC(JSContext
*cx
, JSErrorCallback errorCallback
,
5632 void *userRef
, const uintN errorNumber
, ...)
5636 va_start(ap
, errorNumber
);
5637 js_ReportErrorNumberVA(cx
, JSREPORT_ERROR
, errorCallback
, userRef
,
5638 errorNumber
, JS_FALSE
, ap
);
5642 JS_PUBLIC_API(JSBool
)
5643 JS_ReportWarning(JSContext
*cx
, const char *format
, ...)
5648 va_start(ap
, format
);
5649 ok
= js_ReportErrorVA(cx
, JSREPORT_WARNING
, format
, ap
);
5654 JS_PUBLIC_API(JSBool
)
5655 JS_ReportErrorFlagsAndNumber(JSContext
*cx
, uintN flags
,
5656 JSErrorCallback errorCallback
, void *userRef
,
5657 const uintN errorNumber
, ...)
5662 va_start(ap
, errorNumber
);
5663 ok
= js_ReportErrorNumberVA(cx
, flags
, errorCallback
, userRef
,
5664 errorNumber
, JS_TRUE
, ap
);
5669 JS_PUBLIC_API(JSBool
)
5670 JS_ReportErrorFlagsAndNumberUC(JSContext
*cx
, uintN flags
,
5671 JSErrorCallback errorCallback
, void *userRef
,
5672 const uintN errorNumber
, ...)
5677 va_start(ap
, errorNumber
);
5678 ok
= js_ReportErrorNumberVA(cx
, flags
, errorCallback
, userRef
,
5679 errorNumber
, JS_FALSE
, ap
);
5685 JS_ReportOutOfMemory(JSContext
*cx
)
5687 js_ReportOutOfMemory(cx
);
5691 JS_ReportAllocationOverflow(JSContext
*cx
)
5693 js_ReportAllocationOverflow(cx
);
5696 JS_PUBLIC_API(JSErrorReporter
)
5697 JS_SetErrorReporter(JSContext
*cx
, JSErrorReporter er
)
5699 JSErrorReporter older
;
5701 older
= cx
->errorReporter
;
5702 cx
->errorReporter
= er
;
5706 /************************************************************************/
5709 * Regular Expressions.
5711 JS_PUBLIC_API(JSObject
*)
5712 JS_NewRegExpObject(JSContext
*cx
, char *bytes
, size_t length
, uintN flags
)
5718 chars
= js_InflateString(cx
, bytes
, &length
);
5721 obj
= js_NewRegExpObject(cx
, NULL
, chars
, length
, flags
);
5726 JS_PUBLIC_API(JSObject
*)
5727 JS_NewUCRegExpObject(JSContext
*cx
, jschar
*chars
, size_t length
, uintN flags
)
5730 return js_NewRegExpObject(cx
, NULL
, chars
, length
, flags
);
5734 JS_SetRegExpInput(JSContext
*cx
, JSString
*input
, JSBool multiline
)
5736 JSRegExpStatics
*res
;
5739 /* No locking required, cx is thread-private and input must be live. */
5740 res
= &cx
->regExpStatics
;
5742 res
->multiline
= multiline
;
5743 cx
->runtime
->gcPoke
= JS_TRUE
;
5747 JS_ClearRegExpStatics(JSContext
*cx
)
5749 JSRegExpStatics
*res
;
5751 /* No locking required, cx is thread-private and input must be live. */
5752 res
= &cx
->regExpStatics
;
5754 res
->multiline
= JS_FALSE
;
5755 res
->parenCount
= 0;
5756 res
->lastMatch
= res
->lastParen
= js_EmptySubString
;
5757 res
->leftContext
= res
->rightContext
= js_EmptySubString
;
5758 cx
->runtime
->gcPoke
= JS_TRUE
;
5762 JS_ClearRegExpRoots(JSContext
*cx
)
5764 JSRegExpStatics
*res
;
5766 /* No locking required, cx is thread-private and input must be live. */
5767 res
= &cx
->regExpStatics
;
5769 cx
->runtime
->gcPoke
= JS_TRUE
;
5772 /* TODO: compile, execute, get/set other statics... */
5774 /************************************************************************/
5777 JS_SetLocaleCallbacks(JSContext
*cx
, JSLocaleCallbacks
*callbacks
)
5779 cx
->localeCallbacks
= callbacks
;
5782 JS_PUBLIC_API(JSLocaleCallbacks
*)
5783 JS_GetLocaleCallbacks(JSContext
*cx
)
5785 return cx
->localeCallbacks
;
5788 /************************************************************************/
5790 JS_PUBLIC_API(JSBool
)
5791 JS_IsExceptionPending(JSContext
*cx
)
5793 return (JSBool
) cx
->throwing
;
5796 JS_PUBLIC_API(JSBool
)
5797 JS_GetPendingException(JSContext
*cx
, jsval
*vp
)
5802 *vp
= cx
->exception
;
5807 JS_SetPendingException(JSContext
*cx
, jsval v
)
5810 cx
->throwing
= JS_TRUE
;
5815 JS_ClearPendingException(JSContext
*cx
)
5817 cx
->throwing
= JS_FALSE
;
5818 cx
->exception
= JSVAL_VOID
;
5821 JS_PUBLIC_API(JSBool
)
5822 JS_ReportPendingException(JSContext
*cx
)
5829 * Set cx->generatingError to suppress the standard error-to-exception
5830 * conversion done by all {js,JS}_Report* functions except for OOM. The
5831 * cx->generatingError flag was added to suppress recursive divergence
5832 * under js_ErrorToException, but it serves for our purposes here too.
5834 save
= cx
->generatingError
;
5835 cx
->generatingError
= JS_TRUE
;
5836 ok
= js_ReportUncaughtException(cx
);
5837 cx
->generatingError
= save
;
5841 struct JSExceptionState
{
5846 JS_PUBLIC_API(JSExceptionState
*)
5847 JS_SaveExceptionState(JSContext
*cx
)
5849 JSExceptionState
*state
;
5852 state
= (JSExceptionState
*) JS_malloc(cx
, sizeof(JSExceptionState
));
5854 state
->throwing
= JS_GetPendingException(cx
, &state
->exception
);
5855 if (state
->throwing
&& JSVAL_IS_GCTHING(state
->exception
))
5856 js_AddRoot(cx
, &state
->exception
, "JSExceptionState.exception");
5862 JS_RestoreExceptionState(JSContext
*cx
, JSExceptionState
*state
)
5866 if (state
->throwing
)
5867 JS_SetPendingException(cx
, state
->exception
);
5869 JS_ClearPendingException(cx
);
5870 JS_DropExceptionState(cx
, state
);
5875 JS_DropExceptionState(JSContext
*cx
, JSExceptionState
*state
)
5879 if (state
->throwing
&& JSVAL_IS_GCTHING(state
->exception
))
5880 JS_RemoveRoot(cx
, &state
->exception
);
5885 JS_PUBLIC_API(JSErrorReport
*)
5886 JS_ErrorFromException(JSContext
*cx
, jsval v
)
5889 return js_ErrorFromException(cx
, v
);
5892 JS_PUBLIC_API(JSBool
)
5893 JS_ThrowReportedError(JSContext
*cx
, const char *message
,
5894 JSErrorReport
*reportp
)
5896 return JS_IsRunning(cx
) && js_ErrorToException(cx
, message
, reportp
);
5899 JS_PUBLIC_API(JSBool
)
5900 JS_ThrowStopIteration(JSContext
*cx
)
5902 return js_ThrowStopIteration(cx
);
5906 * Get the owning thread id of a context. Returns 0 if the context is not
5907 * owned by any thread.
5909 JS_PUBLIC_API(jsword
)
5910 JS_GetContextThread(JSContext
*cx
)
5912 #ifdef JS_THREADSAFE
5913 return JS_THREAD_ID(cx
);
5920 * Set the current thread as the owning thread of a context. Returns the
5921 * old owning thread id, or -1 if the operation failed.
5923 JS_PUBLIC_API(jsword
)
5924 JS_SetContextThread(JSContext
*cx
)
5926 #ifdef JS_THREADSAFE
5927 JS_ASSERT(cx
->requestDepth
== 0);
5929 JS_ASSERT(CURRENT_THREAD_IS_ME(cx
->thread
));
5930 return cx
->thread
->id
;
5933 if (!js_InitContextThread(cx
)) {
5934 js_ReportOutOfMemory(cx
);
5938 /* Here the GC lock is still held after js_InitContextThread took it. */
5939 JS_UNLOCK_GC(cx
->runtime
);
5944 JS_PUBLIC_API(jsword
)
5945 JS_ClearContextThread(JSContext
*cx
)
5947 #ifdef JS_THREADSAFE
5949 * This must be called outside a request and, if cx is associated with a
5950 * thread, this must be called only from that thread. If not, this is a
5953 JS_ASSERT(cx
->requestDepth
== 0);
5956 JS_ASSERT(CURRENT_THREAD_IS_ME(cx
->thread
));
5957 jsword old
= cx
->thread
->id
;
5960 * We must not race with a GC that accesses cx->thread for all threads,
5963 JSRuntime
*rt
= cx
->runtime
;
5966 js_ClearContextThread(cx
);
5976 JS_SetGCZeal(JSContext
*cx
, uint8 zeal
)
5978 cx
->runtime
->gcZeal
= zeal
;
5982 /************************************************************************/
5984 #if !defined(STATIC_JS_API) && defined(XP_WIN) && !defined (WINCE)
5986 #include <windows.h>
5989 * Initialization routine for the JS DLL.
5991 BOOL WINAPI
DllMain (HINSTANCE hDLL
, DWORD dwReason
, LPVOID lpReserved
)