1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=80:
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 ***** */
42 * JS execution context.
50 #include "jsarena.h" /* Added by JSIFY */
51 #include "jsutil.h" /* Added by JSIFY */
56 #include "jsversion.h"
70 #include "jsstaticcheck.h"
76 static const size_t ARENA_HEADER_SIZE_HACK
= 40;
77 static const size_t TEMP_POOL_CHUNK_SIZE
= 4096 - ARENA_HEADER_SIZE_HACK
;
80 FreeContext(JSContext
*cx
);
83 MarkLocalRoots(JSTracer
*trc
, JSLocalRootStack
*lrs
);
87 CallStack::contains(JSStackFrame
*fp
)
92 start
= suspendedFrame
;
93 stop
= initialFrame
->down
;
96 stop
= cx
->activeCallStack()->initialFrame
->down
;
98 for (JSStackFrame
*f
= start
; f
!= stop
; f
= f
->down
) {
110 /* The data must be already zeroed. */
111 for (size_t i
= 0; i
!= sizeof(*this); ++i
)
112 JS_ASSERT(reinterpret_cast<uint8
*>(this)[i
] == 0);
115 InitJIT(&traceMonitor
);
117 dtoaState
= js_NewDtoaState();
126 JSThreadData::finish()
129 /* All GC-related things must be already removed at this point. */
130 JS_ASSERT(gcFreeLists
.isEmpty());
131 for (size_t i
= 0; i
!= JS_ARRAY_LENGTH(scriptsToGC
); ++i
)
132 JS_ASSERT(!scriptsToGC
[i
]);
133 for (size_t i
= 0; i
!= JS_ARRAY_LENGTH(nativeEnumCache
); ++i
)
134 JS_ASSERT(!nativeEnumCache
[i
]);
135 JS_ASSERT(!localRootStack
);
139 js_DestroyDtoaState(dtoaState
);
141 js_FinishGSNCache(&gsnCache
);
142 propertyCache
.~PropertyCache();
143 #if defined JS_TRACER
144 FinishJIT(&traceMonitor
);
149 JSThreadData::mark(JSTracer
*trc
)
152 traceMonitor
.mark(trc
);
155 MarkLocalRoots(trc
, localRootStack
);
159 JSThreadData::purge(JSContext
*cx
)
161 cachedIteratorObject
= NULL
;
165 js_PurgeGSNCache(&gsnCache
);
167 /* FIXME: bug 506341. */
168 propertyCache
.purge(cx
);
172 * If we are about to regenerate shapes, we have to flush the JIT cache,
173 * which will eventually abort any current recording.
175 if (cx
->runtime
->gcRegenShapes
)
176 traceMonitor
.needFlush
= JS_TRUE
;
179 /* Destroy eval'ed scripts. */
180 js_DestroyScriptsToGC(cx
, this);
182 js_PurgeCachedNativeEnumerators(cx
, this);
186 JSThreadData::purgeGCFreeLists()
188 if (!localRootStack
) {
191 JS_ASSERT(gcFreeLists
.isEmpty());
192 localRootStack
->gcFreeLists
.purge();
201 JS_ASSERT(js_CurrentThreadId() == id
);
202 JSThread
*thread
= (JSThread
*) js_calloc(sizeof(JSThread
));
205 JS_INIT_CLIST(&thread
->contextList
);
207 if (!thread
->data
.init()) {
215 DestroyThread(JSThread
*thread
)
217 /* The thread must have zero contexts. */
218 JS_ASSERT(JS_CLIST_IS_EMPTY(&thread
->contextList
));
219 JS_ASSERT(!thread
->titleToShare
);
220 thread
->data
.finish();
225 js_CurrentThread(JSRuntime
*rt
)
227 jsword id
= js_CurrentThreadId();
231 * We must not race with a GC that accesses cx->thread for JSContext
232 * instances on all threads, see bug 476934.
235 JSThreadsHashEntry
*entry
= (JSThreadsHashEntry
*)
236 JS_DHashTableOperate(&rt
->threads
,
240 if (JS_DHASH_ENTRY_IS_BUSY(&entry
->base
)) {
241 thread
= entry
->thread
;
242 JS_ASSERT(thread
->id
== id
);
245 thread
= NewThread(id
);
250 entry
= (JSThreadsHashEntry
*)
251 JS_DHashTableOperate(&rt
->threads
, (const void *) id
,
255 DestroyThread(thread
);
259 /* Another thread cannot initialize entry->thread. */
260 JS_ASSERT(!entry
->thread
);
261 entry
->thread
= thread
;
268 js_InitContextThread(JSContext
*cx
)
270 JSThread
*thread
= js_CurrentThread(cx
->runtime
);
274 JS_APPEND_LINK(&cx
->threadLinks
, &thread
->contextList
);
280 js_ClearContextThread(JSContext
*cx
)
282 JS_ASSERT(CURRENT_THREAD_IS_ME(cx
->thread
));
283 JS_REMOVE_AND_INIT_LINK(&cx
->threadLinks
);
288 thread_matchEntry(JSDHashTable
*table
,
289 const JSDHashEntryHdr
*hdr
,
292 const JSThreadsHashEntry
*entry
= (const JSThreadsHashEntry
*) hdr
;
294 return entry
->thread
->id
== (jsword
) key
;
297 static const JSDHashTableOps threads_ops
= {
300 JS_DHashVoidPtrKeyStub
,
302 JS_DHashMoveEntryStub
,
303 JS_DHashClearEntryStub
,
304 JS_DHashFinalizeStub
,
308 static JSDHashOperator
309 thread_destroyer(JSDHashTable
*table
, JSDHashEntryHdr
*hdr
, uint32
/* index */,
312 JSThreadsHashEntry
*entry
= (JSThreadsHashEntry
*) hdr
;
313 JSThread
*thread
= entry
->thread
;
315 JS_ASSERT(JS_CLIST_IS_EMPTY(&thread
->contextList
));
316 DestroyThread(thread
);
317 return JS_DHASH_REMOVE
;
320 static JSDHashOperator
321 thread_purger(JSDHashTable
*table
, JSDHashEntryHdr
*hdr
, uint32
/* index */,
324 JSContext
* cx
= (JSContext
*) arg
;
325 JSThread
*thread
= ((JSThreadsHashEntry
*) hdr
)->thread
;
327 if (JS_CLIST_IS_EMPTY(&thread
->contextList
)) {
328 JS_ASSERT(cx
->thread
!= thread
);
329 js_DestroyScriptsToGC(cx
, &thread
->data
);
332 * The following is potentially suboptimal as it also zeros the caches
333 * in data, but the code simplicity wins here.
335 thread
->data
.purgeGCFreeLists();
336 js_PurgeCachedNativeEnumerators(cx
, &thread
->data
);
337 DestroyThread(thread
);
338 return JS_DHASH_REMOVE
;
340 thread
->data
.purge(cx
);
341 thread
->gcThreadMallocBytes
= JS_GC_THREAD_MALLOC_LIMIT
;
342 return JS_DHASH_NEXT
;
345 static JSDHashOperator
346 thread_marker(JSDHashTable
*table
, JSDHashEntryHdr
*hdr
, uint32
/* index */,
349 JSThread
*thread
= ((JSThreadsHashEntry
*) hdr
)->thread
;
350 thread
->data
.mark((JSTracer
*) arg
);
351 return JS_DHASH_NEXT
;
354 #endif /* JS_THREADSAFE */
357 js_CurrentThreadData(JSRuntime
*rt
)
360 JSThread
*thread
= js_CurrentThread(rt
);
364 return &thread
->data
;
366 return &rt
->threadData
;
371 js_InitThreads(JSRuntime
*rt
)
374 if (!JS_DHashTableInit(&rt
->threads
, &threads_ops
, NULL
,
375 sizeof(JSThreadsHashEntry
), 4)) {
376 rt
->threads
.ops
= NULL
;
380 rt
->threadData
.init();
386 js_FinishThreads(JSRuntime
*rt
)
389 if (!rt
->threads
.ops
)
391 JS_DHashTableEnumerate(&rt
->threads
, thread_destroyer
, NULL
);
392 JS_DHashTableFinish(&rt
->threads
);
393 rt
->threads
.ops
= NULL
;
395 rt
->threadData
.finish();
400 js_PurgeThreads(JSContext
*cx
)
403 JS_DHashTableEnumerate(&cx
->runtime
->threads
, thread_purger
, cx
);
405 cx
->runtime
->threadData
.purge(cx
);
410 js_TraceThreads(JSRuntime
*rt
, JSTracer
*trc
)
413 JS_DHashTableEnumerate(&rt
->threads
, thread_marker
, trc
);
415 rt
->threadData
.mark(trc
);
420 * JSOPTION_XML and JSOPTION_ANONFUNFIX must be part of the JS version
421 * associated with scripts, so in addition to storing them in cx->options we
422 * duplicate them in cx->version (script->version, etc.) and ensure each bit
423 * remains synchronized between the two through these two functions.
426 js_SyncOptionsToVersion(JSContext
* cx
)
428 if (cx
->options
& JSOPTION_XML
)
429 cx
->version
|= JSVERSION_HAS_XML
;
431 cx
->version
&= ~JSVERSION_HAS_XML
;
432 if (cx
->options
& JSOPTION_ANONFUNFIX
)
433 cx
->version
|= JSVERSION_ANONFUNFIX
;
435 cx
->version
&= ~JSVERSION_ANONFUNFIX
;
439 js_SyncVersionToOptions(JSContext
* cx
)
441 if (cx
->version
& JSVERSION_HAS_XML
)
442 cx
->options
|= JSOPTION_XML
;
444 cx
->options
&= ~JSOPTION_XML
;
445 if (cx
->version
& JSVERSION_ANONFUNFIX
)
446 cx
->options
|= JSOPTION_ANONFUNFIX
;
448 cx
->options
&= ~JSOPTION_ANONFUNFIX
;
452 js_OnVersionChange(JSContext
*cx
)
455 JSVersion version
= JSVERSION_NUMBER(cx
);
457 JS_ASSERT(version
== JSVERSION_DEFAULT
|| version
>= JSVERSION_ECMA_3
);
462 js_SetVersion(JSContext
*cx
, JSVersion version
)
464 cx
->version
= version
;
465 js_SyncVersionToOptions(cx
);
466 js_OnVersionChange(cx
);
470 js_NewContext(JSRuntime
*rt
, size_t stackChunkSize
)
474 JSContextCallback cxCallback
;
477 * We need to initialize the new context fully before adding it to the
478 * runtime list. After that it can be accessed from another thread via
479 * js_ContextIterator.
481 void *mem
= js_calloc(sizeof *cx
);
485 cx
= new (mem
) JSContext(rt
);
486 cx
->debugHooks
= &rt
->globalDebugHooks
;
487 #if JS_STACK_GROWTH_DIRECTION > 0
488 cx
->stackLimit
= (jsuword
) -1;
490 cx
->scriptStackQuota
= JS_DEFAULT_SCRIPT_STACK_QUOTA
;
491 JS_STATIC_ASSERT(JSVERSION_DEFAULT
== 0);
492 JS_ASSERT(cx
->version
== JSVERSION_DEFAULT
);
493 VOUCH_DOES_NOT_REQUIRE_STACK();
494 JS_InitArenaPool(&cx
->stackPool
, "stack", stackChunkSize
, sizeof(jsval
),
495 &cx
->scriptStackQuota
);
497 JS_InitArenaPool(&cx
->tempPool
, "temp", TEMP_POOL_CHUNK_SIZE
, sizeof(jsdouble
),
498 &cx
->scriptStackQuota
);
500 js_InitRegExpStatics(cx
);
501 JS_ASSERT(cx
->resolveFlags
== 0);
504 if (!js_InitContextThread(cx
)) {
511 * Here the GC lock is still held after js_InitContextThread took it and
512 * the GC is not running on another thread.
515 if (rt
->state
== JSRTS_UP
) {
516 JS_ASSERT(!JS_CLIST_IS_EMPTY(&rt
->contextList
));
520 if (rt
->state
== JSRTS_DOWN
) {
521 JS_ASSERT(JS_CLIST_IS_EMPTY(&rt
->contextList
));
523 rt
->state
= JSRTS_LAUNCHING
;
526 JS_WAIT_CONDVAR(rt
->stateChange
, JS_NO_TIMEOUT
);
529 * During the above wait after we are notified about the state change
530 * but before we wake up, another thread could enter the GC from
531 * js_DestroyContext, bug 478336. So we must wait here to ensure that
532 * when we exit the loop with the first flag set to true, that GC is
537 JS_APPEND_LINK(&cx
->link
, &rt
->contextList
);
543 * If cx is the first context on this runtime, initialize well-known atoms,
544 * keywords, numbers, and strings. If one of these steps should fail, the
545 * runtime will be left in a partially initialized state, with zeroes and
546 * nulls stored in the default-initialized remainder of the struct. We'll
547 * clean the runtime up under js_DestroyContext, because cx will be "last"
548 * as well as "first".
554 ok
= js_InitCommonAtoms(cx
);
557 * scriptFilenameTable may be left over from a previous episode of
558 * non-zero contexts alive in rt, so don't re-init the table if it's
561 if (ok
&& !rt
->scriptFilenameTable
)
562 ok
= js_InitRuntimeScriptState(rt
);
564 ok
= js_InitRuntimeNumberState(cx
);
566 ok
= JSScope::initRuntimeState(cx
);
572 js_DestroyContext(cx
, JSDCM_NEW_FAILED
);
577 rt
->state
= JSRTS_UP
;
578 JS_NOTIFY_ALL_CONDVAR(rt
->stateChange
);
581 cxCallback
= rt
->cxCallback
;
582 if (cxCallback
&& !cxCallback(cx
, JSCONTEXT_NEW
)) {
583 js_DestroyContext(cx
, JSDCM_NEW_FAILED
);
587 /* Using ContextAllocPolicy, so init after JSContext is ready. */
588 if (!cx
->busyArrays
.init()) {
596 #if defined DEBUG && defined XP_UNIX
601 JSAutoFile() : mFile(NULL
) {}
608 FILE *open(const char *fname
, const char *mode
) {
609 return mFile
= fopen(fname
, mode
);
619 #ifdef JS_EVAL_CACHE_METERING
621 DumpEvalCacheMeter(JSContext
*cx
)
627 #define frob(x) { #x, offsetof(JSEvalCacheMeter, x) }
628 EVAL_CACHE_METER_LIST(frob
)
631 JSEvalCacheMeter
*ecm
= &JS_THREAD_DATA(cx
)->evalCacheMeter
;
633 static JSAutoFile fp
;
635 fp
.open("/tmp/evalcache.stats", "w");
640 fprintf(fp
, "eval cache meter (%p):\n",
647 for (uintN i
= 0; i
< JS_ARRAY_LENGTH(table
); ++i
) {
648 fprintf(fp
, "%-8.8s %llu\n",
650 (unsigned long long int) *(uint64
*)((uint8
*)ecm
+ table
[i
].offset
));
652 fprintf(fp
, "hit ratio %g%%\n", ecm
->hit
* 100. / ecm
->probe
);
653 fprintf(fp
, "avg steps %g\n", double(ecm
->step
) / ecm
->probe
);
656 # define DUMP_EVAL_CACHE_METER(cx) DumpEvalCacheMeter(cx)
659 #ifdef JS_FUNCTION_METERING
661 DumpFunctionMeter(JSContext
*cx
)
667 #define frob(x) { #x, offsetof(JSFunctionMeter, x) }
668 FUNCTION_KIND_METER_LIST(frob
)
671 JSFunctionMeter
*fm
= &cx
->runtime
->functionMeter
;
673 static JSAutoFile fp
;
675 fp
.open("/tmp/function.stats", "a");
680 fprintf(fp
, "function meter (%s):\n", cx
->runtime
->lastScriptFilename
);
681 for (uintN i
= 0; i
< JS_ARRAY_LENGTH(table
); ++i
) {
682 fprintf(fp
, "%-11.11s %d\n",
683 table
[i
].name
, *(int32
*)((uint8
*)fm
+ table
[i
].offset
));
687 # define DUMP_FUNCTION_METER(cx) DumpFunctionMeter(cx)
690 #endif /* DEBUG && XP_UNIX */
692 #ifndef DUMP_EVAL_CACHE_METER
693 # define DUMP_EVAL_CACHE_METER(cx) ((void) 0)
696 #ifndef DUMP_FUNCTION_METER
697 # define DUMP_FUNCTION_METER(cx) ((void) 0)
700 #ifdef JS_PROTO_CACHE_METERING
702 DumpProtoCacheMeter(JSContext
*cx
)
704 JSClassProtoCache::Stats
*stats
= &cx
->runtime
->classProtoCacheStats
;
705 FILE *fp
= fopen("/tmp/protocache.stats", "a");
708 double(stats
->hit
) * 100.0 / double(stats
->probe
));
712 # define DUMP_PROTO_CACHE_METER(cx) DumpProtoCacheMeter(cx)
714 # define DUMP_PROTO_CACHE_METER(cx) ((void) 0)
719 js_DestroyContext(JSContext
*cx
, JSDestroyContextMode mode
)
722 JSContextCallback cxCallback
;
728 * For API compatibility we allow to destroy contexts without a thread in
729 * optimized builds. We assume that the embedding knows that an OOM error
730 * cannot happen in JS_SetContextThread.
732 JS_ASSERT(cx
->thread
&& CURRENT_THREAD_IS_ME(cx
->thread
));
734 JS_SetContextThread(cx
);
736 JS_ASSERT_IF(rt
->gcRunning
, cx
->outstandingRequests
== 0);
739 if (mode
!= JSDCM_NEW_FAILED
) {
740 cxCallback
= rt
->cxCallback
;
743 * JSCONTEXT_DESTROY callback is not allowed to fail and must
747 JSBool callbackStatus
=
749 cxCallback(cx
, JSCONTEXT_DESTROY
);
750 JS_ASSERT(callbackStatus
);
755 JS_ASSERT(rt
->state
== JSRTS_UP
|| rt
->state
== JSRTS_LAUNCHING
);
758 * Typically we are called outside a request, so ensure that the GC is not
759 * running before removing the context from rt->contextList, see bug 477021.
761 if (cx
->requestDepth
== 0)
764 JS_REMOVE_LINK(&cx
->link
);
765 last
= (rt
->contextList
.next
== &rt
->contextList
);
767 rt
->state
= JSRTS_LANDING
;
768 if (last
|| mode
== JSDCM_FORCE_GC
|| mode
== JSDCM_MAYBE_GC
770 || cx
->requestDepth
!= 0
773 JS_ASSERT(!rt
->gcRunning
);
780 * If cx is not in a request already, begin one now so that we wait
781 * for any racing GC started on a not-last context to finish, before
782 * we plow ahead and unpin atoms. Note that even though we begin a
783 * request here if necessary, we end all requests on cx below before
784 * forcing a final GC. This lets any not-last context destruction
785 * racing in another thread try to force or maybe run the GC, but by
786 * that point, rt->state will not be JSRTS_UP, and that GC attempt
789 if (cx
->requestDepth
== 0)
793 JSScope::finishRuntimeState(cx
);
794 js_FinishRuntimeNumberState(cx
);
796 /* Unpin all common atoms before final GC. */
797 js_FinishCommonAtoms(cx
);
799 /* Clear debugging state to remove GC roots. */
800 JS_ClearAllTraps(cx
);
801 JS_ClearAllWatchPoints(cx
);
804 /* Remove more GC roots in regExpStatics, then collect garbage. */
805 JS_ClearRegExpRoots(cx
);
809 * Destroying a context implicitly calls JS_EndRequest(). Also, we must
810 * end our request here in case we are "last" -- in that event, another
811 * js_DestroyContext that was not last might be waiting in the GC for our
812 * request to end. We'll let it run below, just before we do the truly
813 * final GC and then free atom state.
815 while (cx
->requestDepth
!= 0)
820 js_GC(cx
, GC_LAST_CONTEXT
);
821 DUMP_EVAL_CACHE_METER(cx
);
822 DUMP_FUNCTION_METER(cx
);
823 DUMP_PROTO_CACHE_METER(cx
);
825 /* Take the runtime down, now that it has no contexts or atoms. */
827 rt
->state
= JSRTS_DOWN
;
828 JS_NOTIFY_ALL_CONDVAR(rt
->stateChange
);
830 if (mode
== JSDCM_FORCE_GC
)
831 js_GC(cx
, GC_NORMAL
);
832 else if (mode
== JSDCM_MAYBE_GC
)
839 js_ClearContextThread(cx
);
846 FreeContext(JSContext
*cx
)
849 JS_ASSERT(!cx
->thread
);
852 /* Free the stuff hanging off of cx. */
853 js_FreeRegExpStatics(cx
);
854 VOUCH_DOES_NOT_REQUIRE_STACK();
855 JS_FinishArenaPool(&cx
->stackPool
);
856 JS_FinishArenaPool(&cx
->tempPool
);
859 js_free(cx
->lastMessage
);
861 /* Remove any argument formatters. */
862 JSArgumentFormatMap
*map
= cx
->argumentFormatMap
;
864 JSArgumentFormatMap
*temp
= map
;
869 /* Destroy the resolve recursion damper. */
870 if (cx
->resolvingTable
) {
871 JS_DHashTableDestroy(cx
->resolvingTable
);
872 cx
->resolvingTable
= NULL
;
875 /* Finally, free cx itself. */
881 js_ValidContextPointer(JSRuntime
*rt
, JSContext
*cx
)
885 for (cl
= rt
->contextList
.next
; cl
!= &rt
->contextList
; cl
= cl
->next
) {
889 JS_RUNTIME_METER(rt
, deadContexts
);
894 js_ContextIterator(JSRuntime
*rt
, JSBool unlocked
, JSContext
**iterp
)
896 JSContext
*cx
= *iterp
;
898 Conditionally
<AutoLockGC
> lockIf(!!unlocked
, rt
);
899 cx
= js_ContextFromLinkField(cx
? cx
->link
.next
: rt
->contextList
.next
);
900 if (&cx
->link
== &rt
->contextList
)
906 JS_FRIEND_API(JSContext
*)
907 js_NextActiveContext(JSRuntime
*rt
, JSContext
*cx
)
909 JSContext
*iter
= cx
;
911 while ((cx
= js_ContextIterator(rt
, JS_FALSE
, &iter
)) != NULL
) {
912 if (cx
->requestDepth
)
917 return js_ContextIterator(rt
, JS_FALSE
, &iter
);
924 js_CountThreadRequests(JSContext
*cx
)
926 JSCList
*head
, *link
;
929 JS_ASSERT(CURRENT_THREAD_IS_ME(cx
->thread
));
930 head
= &cx
->thread
->contextList
;
932 for (link
= head
->next
; link
!= head
; link
= link
->next
) {
933 JSContext
*acx
= CX_FROM_THREAD_LINKS(link
);
934 JS_ASSERT(acx
->thread
== cx
->thread
);
935 if (acx
->requestDepth
)
942 * If the GC is running and we're called on another thread, wait for this GC
943 * activation to finish. We can safely wait here without fear of deadlock (in
944 * the case where we are called within a request on another thread's context)
945 * because the GC doesn't set rt->gcRunning until after it has waited for all
946 * active requests to end.
948 * We call here js_CurrentThreadId() after checking for rt->gcRunning to avoid
949 * expensive calls when the GC is not running.
952 js_WaitForGC(JSRuntime
*rt
)
954 JS_ASSERT_IF(rt
->gcRunning
, rt
->gcLevel
> 0);
955 if (rt
->gcRunning
&& rt
->gcThread
->id
!= js_CurrentThreadId()) {
957 JS_AWAIT_GC_DONE(rt
);
958 } while (rt
->gcRunning
);
965 resolving_HashKey(JSDHashTable
*table
, const void *ptr
)
967 const JSResolvingKey
*key
= (const JSResolvingKey
*)ptr
;
969 return (JSDHashNumber(uintptr_t(key
->obj
)) >> JSVAL_TAGBITS
) ^ key
->id
;
972 JS_PUBLIC_API(JSBool
)
973 resolving_MatchEntry(JSDHashTable
*table
,
974 const JSDHashEntryHdr
*hdr
,
977 const JSResolvingEntry
*entry
= (const JSResolvingEntry
*)hdr
;
978 const JSResolvingKey
*key
= (const JSResolvingKey
*)ptr
;
980 return entry
->key
.obj
== key
->obj
&& entry
->key
.id
== key
->id
;
983 static const JSDHashTableOps resolving_dhash_ops
= {
987 resolving_MatchEntry
,
988 JS_DHashMoveEntryStub
,
989 JS_DHashClearEntryStub
,
990 JS_DHashFinalizeStub
,
995 js_StartResolving(JSContext
*cx
, JSResolvingKey
*key
, uint32 flag
,
996 JSResolvingEntry
**entryp
)
999 JSResolvingEntry
*entry
;
1001 table
= cx
->resolvingTable
;
1003 table
= JS_NewDHashTable(&resolving_dhash_ops
, NULL
,
1004 sizeof(JSResolvingEntry
),
1008 cx
->resolvingTable
= table
;
1011 entry
= (JSResolvingEntry
*)
1012 JS_DHashTableOperate(table
, key
, JS_DHASH_ADD
);
1016 if (entry
->flags
& flag
) {
1017 /* An entry for (key, flag) exists already -- dampen recursion. */
1020 /* Fill in key if we were the first to add entry, then set flag. */
1021 if (!entry
->key
.obj
)
1023 entry
->flags
|= flag
;
1029 JS_ReportOutOfMemory(cx
);
1034 js_StopResolving(JSContext
*cx
, JSResolvingKey
*key
, uint32 flag
,
1035 JSResolvingEntry
*entry
, uint32 generation
)
1037 JSDHashTable
*table
;
1040 * Clear flag from entry->flags and return early if other flags remain.
1041 * We must take care to re-lookup entry if the table has changed since
1042 * it was found by js_StartResolving.
1044 table
= cx
->resolvingTable
;
1045 if (!entry
|| table
->generation
!= generation
) {
1046 entry
= (JSResolvingEntry
*)
1047 JS_DHashTableOperate(table
, key
, JS_DHASH_LOOKUP
);
1049 JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&entry
->hdr
));
1050 entry
->flags
&= ~flag
;
1055 * Do a raw remove only if fewer entries were removed than would cause
1056 * alpha to be less than .5 (alpha is at most .75). Otherwise, we just
1057 * call JS_DHashTableOperate to re-lookup the key and remove its entry,
1058 * compressing or shrinking the table as needed.
1060 if (table
->removedCount
< JS_DHASH_TABLE_SIZE(table
) >> 2)
1061 JS_DHashTableRawRemove(table
, &entry
->hdr
);
1063 JS_DHashTableOperate(table
, key
, JS_DHASH_REMOVE
);
1067 js_EnterLocalRootScope(JSContext
*cx
)
1069 JSThreadData
*td
= JS_THREAD_DATA(cx
);
1070 JSLocalRootStack
*lrs
= td
->localRootStack
;
1072 lrs
= (JSLocalRootStack
*) js_malloc(sizeof *lrs
);
1074 js_ReportOutOfMemory(cx
);
1077 lrs
->scopeMark
= JSLRS_NULL_MARK
;
1079 lrs
->topChunk
= &lrs
->firstChunk
;
1080 lrs
->firstChunk
.down
= NULL
;
1081 td
->gcFreeLists
.moveTo(&lrs
->gcFreeLists
);
1082 td
->localRootStack
= lrs
;
1085 /* Push lrs->scopeMark to save it for restore when leaving. */
1086 int mark
= js_PushLocalRoot(cx
, lrs
, INT_TO_JSVAL(lrs
->scopeMark
));
1089 lrs
->scopeMark
= (uint32
) mark
;
1094 js_LeaveLocalRootScopeWithResult(JSContext
*cx
, jsval rval
)
1096 JSLocalRootStack
*lrs
;
1098 JSLocalRootChunk
*lrc
;
1100 /* Defend against buggy native callers. */
1101 lrs
= JS_THREAD_DATA(cx
)->localRootStack
;
1102 JS_ASSERT(lrs
&& lrs
->rootCount
!= 0);
1103 if (!lrs
|| lrs
->rootCount
== 0)
1106 mark
= lrs
->scopeMark
;
1107 JS_ASSERT(mark
!= JSLRS_NULL_MARK
);
1108 if (mark
== JSLRS_NULL_MARK
)
1111 /* Free any chunks being popped by this leave operation. */
1112 m
= mark
>> JSLRS_CHUNK_SHIFT
;
1113 n
= (lrs
->rootCount
- 1) >> JSLRS_CHUNK_SHIFT
;
1115 lrc
= lrs
->topChunk
;
1116 JS_ASSERT(lrc
!= &lrs
->firstChunk
);
1117 lrs
->topChunk
= lrc
->down
;
1123 * Pop the scope, restoring lrs->scopeMark. If rval is a GC-thing, push
1124 * it on the caller's scope, or store it in lastInternalResult if we are
1125 * leaving the outermost scope. We don't need to allocate a new lrc
1126 * because we can overwrite the old mark's slot with rval.
1128 lrc
= lrs
->topChunk
;
1129 m
= mark
& JSLRS_CHUNK_MASK
;
1130 lrs
->scopeMark
= (uint32
) JSVAL_TO_INT(lrc
->roots
[m
]);
1131 if (JSVAL_IS_GCTHING(rval
) && !JSVAL_IS_NULL(rval
)) {
1133 cx
->weakRoots
.lastInternalResult
= rval
;
1136 * Increment m to avoid the "else if (m == 0)" case below. If
1137 * rval is not a GC-thing, that case would take care of freeing
1138 * any chunk that contained only the old mark. Since rval *is*
1139 * a GC-thing here, we want to reuse that old mark's slot.
1141 lrc
->roots
[m
++] = rval
;
1145 lrs
->rootCount
= (uint32
) mark
;
1148 * Free the stack eagerly, risking malloc churn. The alternative would
1149 * require an lrs->entryCount member, maintained by Enter and Leave, and
1150 * tested by the GC in addition to the cx->localRootStack non-null test.
1152 * That approach would risk hoarding 264 bytes (net) per context. Right
1153 * now it seems better to give fresh (dirty in CPU write-back cache, and
1154 * the data is no longer needed) memory back to the malloc heap.
1157 JSThreadData
*td
= JS_THREAD_DATA(cx
);
1158 JS_ASSERT(td
->gcFreeLists
.isEmpty());
1159 lrs
->gcFreeLists
.moveTo(&td
->gcFreeLists
);
1160 td
->localRootStack
= NULL
;
1162 } else if (m
== 0) {
1163 lrs
->topChunk
= lrc
->down
;
1169 js_ForgetLocalRoot(JSContext
*cx
, jsval v
)
1171 JSLocalRootStack
*lrs
;
1172 uint32 i
, j
, m
, n
, mark
;
1173 JSLocalRootChunk
*lrc
, *lrc2
;
1176 lrs
= JS_THREAD_DATA(cx
)->localRootStack
;
1177 JS_ASSERT(lrs
&& lrs
->rootCount
);
1178 if (!lrs
|| lrs
->rootCount
== 0)
1181 /* Prepare to pop the top-most value from the stack. */
1182 n
= lrs
->rootCount
- 1;
1183 m
= n
& JSLRS_CHUNK_MASK
;
1184 lrc
= lrs
->topChunk
;
1185 top
= lrc
->roots
[m
];
1187 /* Be paranoid about calls on an empty scope. */
1188 mark
= lrs
->scopeMark
;
1189 JS_ASSERT(mark
< n
);
1193 /* If v was not the last root pushed in the top scope, find it. */
1195 /* Search downward in case v was recently pushed. */
1199 while (--i
> mark
) {
1202 j
= i
& JSLRS_CHUNK_MASK
;
1203 if (lrc2
->roots
[j
] == v
)
1207 /* If we didn't find v in this scope, assert and bail out. */
1208 JS_ASSERT(i
!= mark
);
1212 /* Swap top and v so common tail code can pop v. */
1213 lrc2
->roots
[j
] = top
;
1216 /* Pop the last value from the stack. */
1217 lrc
->roots
[m
] = JSVAL_NULL
;
1221 JS_ASSERT(lrc
!= &lrs
->firstChunk
);
1222 lrs
->topChunk
= lrc
->down
;
1228 js_PushLocalRoot(JSContext
*cx
, JSLocalRootStack
*lrs
, jsval v
)
1231 JSLocalRootChunk
*lrc
;
1234 m
= n
& JSLRS_CHUNK_MASK
;
1235 if (n
== 0 || m
!= 0) {
1237 * At start of first chunk, or not at start of a non-first top chunk.
1238 * Check for lrs->rootCount overflow.
1240 if ((uint32
)(n
+ 1) == 0) {
1241 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1242 JSMSG_TOO_MANY_LOCAL_ROOTS
);
1245 lrc
= lrs
->topChunk
;
1246 JS_ASSERT(n
!= 0 || lrc
== &lrs
->firstChunk
);
1249 * After lrs->firstChunk, trying to index at a power-of-two chunk
1250 * boundary: need a new chunk.
1252 lrc
= (JSLocalRootChunk
*) js_malloc(sizeof *lrc
);
1254 js_ReportOutOfMemory(cx
);
1257 lrc
->down
= lrs
->topChunk
;
1258 lrs
->topChunk
= lrc
;
1260 lrs
->rootCount
= n
+ 1;
1266 MarkLocalRoots(JSTracer
*trc
, JSLocalRootStack
*lrs
)
1269 JSLocalRootChunk
*lrc
;
1276 mark
= lrs
->scopeMark
;
1277 lrc
= lrs
->topChunk
;
1279 while (--n
> mark
) {
1280 m
= n
& JSLRS_CHUNK_MASK
;
1282 JS_ASSERT(JSVAL_IS_GCTHING(v
) && v
!= JSVAL_NULL
);
1283 JS_SET_TRACING_INDEX(trc
, "local_root", n
);
1284 js_CallValueTracerIfGCThing(trc
, v
);
1288 m
= n
& JSLRS_CHUNK_MASK
;
1289 mark
= JSVAL_TO_INT(lrc
->roots
[m
]);
1297 ReportError(JSContext
*cx
, const char *message
, JSErrorReport
*reportp
,
1298 JSErrorCallback callback
, void *userRef
)
1301 * Check the error report, and set a JavaScript-catchable exception
1302 * if the error is defined to have an associated exception. If an
1303 * exception is thrown, then the JSREPORT_EXCEPTION flag will be set
1304 * on the error report, and exception-aware hosts should ignore it.
1307 if ((!callback
|| callback
== js_GetErrorMessage
) &&
1308 reportp
->errorNumber
== JSMSG_UNCAUGHT_EXCEPTION
)
1309 reportp
->flags
|= JSREPORT_EXCEPTION
;
1312 * Call the error reporter only if an exception wasn't raised.
1314 * If an exception was raised, then we call the debugErrorHook
1315 * (if present) to give it a chance to see the error before it
1316 * propagates out of scope. This is needed for compatability
1317 * with the old scheme.
1319 if (!JS_IsRunning(cx
) ||
1320 !js_ErrorToException(cx
, message
, reportp
, callback
, userRef
)) {
1321 js_ReportErrorAgain(cx
, message
, reportp
);
1322 } else if (cx
->debugHooks
->debugErrorHook
&& cx
->errorReporter
) {
1323 JSDebugErrorHook hook
= cx
->debugHooks
->debugErrorHook
;
1324 /* test local in case debugErrorHook changed on another thread */
1326 hook(cx
, message
, reportp
, cx
->debugHooks
->debugErrorHookData
);
1330 /* The report must be initially zeroed. */
1332 PopulateReportBlame(JSContext
*cx
, JSErrorReport
*report
)
1337 * Walk stack until we find a frame that is associated with some script
1338 * rather than a native frame.
1340 for (fp
= js_GetTopStackFrame(cx
); fp
; fp
= fp
->down
) {
1342 report
->filename
= fp
->script
->filename
;
1343 report
->lineno
= js_FramePCToLineNumber(cx
, fp
);
1350 * We don't post an exception in this case, since doing so runs into
1351 * complications of pre-allocating an exception object which required
1352 * running the Exception class initializer early etc.
1353 * Instead we just invoke the errorReporter with an "Out Of Memory"
1354 * type message, and then hope the process ends swiftly.
1357 js_ReportOutOfMemory(JSContext
*cx
)
1361 * If we are in a builtin called directly from trace, don't report an
1362 * error. We will retry in the interpreter instead.
1364 if (JS_ON_TRACE(cx
) && !cx
->bailExit
)
1368 JSErrorReport report
;
1369 JSErrorReporter onError
= cx
->errorReporter
;
1371 /* Get the message for this error, but we won't expand any arguments. */
1372 const JSErrorFormatString
*efs
=
1373 js_GetLocalizedErrorMessage(cx
, NULL
, NULL
, JSMSG_OUT_OF_MEMORY
);
1374 const char *msg
= efs
? efs
->format
: "Out of memory";
1376 /* Fill out the report, but don't do anything that requires allocation. */
1378 report
.flags
= JSREPORT_ERROR
;
1379 report
.errorNumber
= JSMSG_OUT_OF_MEMORY
;
1380 PopulateReportBlame(cx
, &report
);
1383 * If debugErrorHook is present then we give it a chance to veto sending
1384 * the error on to the regular ErrorReporter. We also clear a pending
1385 * exception if any now so the hooks can replace the out-of-memory error
1386 * by a script-catchable exception.
1388 cx
->throwing
= JS_FALSE
;
1390 JSDebugErrorHook hook
= cx
->debugHooks
->debugErrorHook
;
1392 !hook(cx
, msg
, &report
, cx
->debugHooks
->debugErrorHookData
)) {
1398 onError(cx
, msg
, &report
);
1402 js_ReportOutOfScriptQuota(JSContext
*cx
)
1404 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1405 JSMSG_SCRIPT_STACK_QUOTA
);
1409 js_ReportOverRecursed(JSContext
*cx
)
1411 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_OVER_RECURSED
);
1415 js_ReportAllocationOverflow(JSContext
*cx
)
1417 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_ALLOC_OVERFLOW
);
1421 * Given flags and the state of cx, decide whether we should report an
1422 * error, a warning, or just continue execution normally. Return
1423 * true if we should continue normally, without reporting anything;
1424 * otherwise, adjust *flags as appropriate and return false.
1427 checkReportFlags(JSContext
*cx
, uintN
*flags
)
1429 if (JSREPORT_IS_STRICT_MODE_ERROR(*flags
)) {
1431 * Error in strict code; warning with strict option; okay otherwise.
1432 * We assume that if the top frame is a native, then it is strict if
1433 * the nearest scripted frame is strict, see bug 536306.
1435 JSStackFrame
*fp
= js_GetScriptedCaller(cx
, NULL
);
1436 if (fp
&& fp
->script
->strictModeCode
)
1437 *flags
&= ~JSREPORT_WARNING
;
1438 else if (JS_HAS_STRICT_OPTION(cx
))
1439 *flags
|= JSREPORT_WARNING
;
1442 } else if (JSREPORT_IS_STRICT(*flags
)) {
1443 /* Warning/error only when JSOPTION_STRICT is set. */
1444 if (!JS_HAS_STRICT_OPTION(cx
))
1448 /* Warnings become errors when JSOPTION_WERROR is set. */
1449 if (JSREPORT_IS_WARNING(*flags
) && JS_HAS_WERROR_OPTION(cx
))
1450 *flags
&= ~JSREPORT_WARNING
;
1456 js_ReportErrorVA(JSContext
*cx
, uintN flags
, const char *format
, va_list ap
)
1461 JSErrorReport report
;
1464 if (checkReportFlags(cx
, &flags
))
1467 message
= JS_vsmprintf(format
, ap
);
1470 messagelen
= strlen(message
);
1473 report
.flags
= flags
;
1474 report
.errorNumber
= JSMSG_USER_DEFINED_ERROR
;
1475 report
.ucmessage
= ucmessage
= js_InflateString(cx
, message
, &messagelen
);
1476 PopulateReportBlame(cx
, &report
);
1478 warning
= JSREPORT_IS_WARNING(report
.flags
);
1480 ReportError(cx
, message
, &report
, NULL
, NULL
);
1482 cx
->free(ucmessage
);
1487 * The arguments from ap need to be packaged up into an array and stored
1488 * into the report struct.
1490 * The format string addressed by the error number may contain operands
1491 * identified by the format {N}, where N is a decimal digit. Each of these
1492 * is to be replaced by the Nth argument from the va_list. The complete
1493 * message is placed into reportp->ucmessage converted to a JSString.
1495 * Returns true if the expansion succeeds (can fail if out of memory).
1498 js_ExpandErrorArguments(JSContext
*cx
, JSErrorCallback callback
,
1499 void *userRef
, const uintN errorNumber
,
1500 char **messagep
, JSErrorReport
*reportp
,
1501 bool charArgs
, va_list ap
)
1503 const JSErrorFormatString
*efs
;
1509 /* Most calls supply js_GetErrorMessage; if this is so, assume NULL. */
1510 if (!callback
|| callback
== js_GetErrorMessage
)
1511 efs
= js_GetLocalizedErrorMessage(cx
, userRef
, NULL
, errorNumber
);
1513 efs
= callback(userRef
, NULL
, errorNumber
);
1515 size_t totalArgsLength
= 0;
1516 size_t argLengths
[10]; /* only {0} thru {9} supported */
1517 argCount
= efs
->argCount
;
1518 JS_ASSERT(argCount
<= 10);
1521 * Gather the arguments into an array, and accumulate
1522 * their sizes. We allocate 1 more than necessary and
1523 * null it out to act as the caboose when we free the
1526 reportp
->messageArgs
= (const jschar
**)
1527 cx
->malloc(sizeof(jschar
*) * (argCount
+ 1));
1528 if (!reportp
->messageArgs
)
1530 reportp
->messageArgs
[argCount
] = NULL
;
1531 for (i
= 0; i
< argCount
; i
++) {
1533 char *charArg
= va_arg(ap
, char *);
1534 size_t charArgLength
= strlen(charArg
);
1535 reportp
->messageArgs
[i
]
1536 = js_InflateString(cx
, charArg
, &charArgLength
);
1537 if (!reportp
->messageArgs
[i
])
1540 reportp
->messageArgs
[i
] = va_arg(ap
, jschar
*);
1542 argLengths
[i
] = js_strlen(reportp
->messageArgs
[i
]);
1543 totalArgsLength
+= argLengths
[i
];
1545 /* NULL-terminate for easy copying. */
1546 reportp
->messageArgs
[i
] = NULL
;
1549 * Parse the error format, substituting the argument X
1550 * for {X} in the format.
1554 jschar
*buffer
, *fmt
, *out
;
1555 int expandedArgs
= 0;
1556 size_t expandedLength
;
1557 size_t len
= strlen(efs
->format
);
1559 buffer
= fmt
= js_InflateString (cx
, efs
->format
, &len
);
1562 expandedLength
= len
1563 - (3 * argCount
) /* exclude the {n} */
1567 * Note - the above calculation assumes that each argument
1568 * is used once and only once in the expansion !!!
1570 reportp
->ucmessage
= out
= (jschar
*)
1571 cx
->malloc((expandedLength
+ 1) * sizeof(jschar
));
1578 if (isdigit(fmt
[1])) {
1579 int d
= JS7_UNDEC(fmt
[1]);
1580 JS_ASSERT(d
< argCount
);
1581 js_strncpy(out
, reportp
->messageArgs
[d
],
1583 out
+= argLengths
[d
];
1591 JS_ASSERT(expandedArgs
== argCount
);
1595 js_DeflateString(cx
, reportp
->ucmessage
,
1596 (size_t)(out
- reportp
->ucmessage
));
1602 * Zero arguments: the format string (if it exists) is the
1607 *messagep
= JS_strdup(cx
, efs
->format
);
1610 len
= strlen(*messagep
);
1611 reportp
->ucmessage
= js_InflateString(cx
, *messagep
, &len
);
1612 if (!reportp
->ucmessage
)
1617 if (*messagep
== NULL
) {
1618 /* where's the right place for this ??? */
1619 const char *defaultErrorMessage
1620 = "No error message available for error number %d";
1621 size_t nbytes
= strlen(defaultErrorMessage
) + 16;
1622 *messagep
= (char *)cx
->malloc(nbytes
);
1625 JS_snprintf(*messagep
, nbytes
, defaultErrorMessage
, errorNumber
);
1630 if (reportp
->messageArgs
) {
1631 /* free the arguments only if we allocated them */
1634 while (reportp
->messageArgs
[i
])
1635 cx
->free((void *)reportp
->messageArgs
[i
++]);
1637 cx
->free((void *)reportp
->messageArgs
);
1638 reportp
->messageArgs
= NULL
;
1640 if (reportp
->ucmessage
) {
1641 cx
->free((void *)reportp
->ucmessage
);
1642 reportp
->ucmessage
= NULL
;
1645 cx
->free((void *)*messagep
);
1652 js_ReportErrorNumberVA(JSContext
*cx
, uintN flags
, JSErrorCallback callback
,
1653 void *userRef
, const uintN errorNumber
,
1654 JSBool charArgs
, va_list ap
)
1656 JSErrorReport report
;
1660 if (checkReportFlags(cx
, &flags
))
1662 warning
= JSREPORT_IS_WARNING(flags
);
1665 report
.flags
= flags
;
1666 report
.errorNumber
= errorNumber
;
1667 PopulateReportBlame(cx
, &report
);
1669 if (!js_ExpandErrorArguments(cx
, callback
, userRef
, errorNumber
,
1670 &message
, &report
, !!charArgs
, ap
)) {
1674 ReportError(cx
, message
, &report
, callback
, userRef
);
1678 if (report
.messageArgs
) {
1680 * js_ExpandErrorArguments owns its messageArgs only if it had to
1681 * inflate the arguments (from regular |char *|s).
1685 while (report
.messageArgs
[i
])
1686 cx
->free((void *)report
.messageArgs
[i
++]);
1688 cx
->free((void *)report
.messageArgs
);
1690 if (report
.ucmessage
)
1691 cx
->free((void *)report
.ucmessage
);
1697 js_ReportErrorAgain(JSContext
*cx
, const char *message
, JSErrorReport
*reportp
)
1699 JSErrorReporter onError
;
1704 if (cx
->lastMessage
)
1705 js_free(cx
->lastMessage
);
1706 cx
->lastMessage
= JS_strdup(cx
, message
);
1707 if (!cx
->lastMessage
)
1709 onError
= cx
->errorReporter
;
1712 * If debugErrorHook is present then we give it a chance to veto
1713 * sending the error on to the regular ErrorReporter.
1716 JSDebugErrorHook hook
= cx
->debugHooks
->debugErrorHook
;
1718 !hook(cx
, cx
->lastMessage
, reportp
,
1719 cx
->debugHooks
->debugErrorHookData
)) {
1724 onError(cx
, cx
->lastMessage
, reportp
);
1728 js_ReportIsNotDefined(JSContext
*cx
, const char *name
)
1730 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_NOT_DEFINED
, name
);
1734 js_ReportIsNullOrUndefined(JSContext
*cx
, intN spindex
, jsval v
,
1740 bytes
= js_DecompileValueGenerator(cx
, spindex
, v
, fallback
);
1744 if (strcmp(bytes
, js_undefined_str
) == 0 ||
1745 strcmp(bytes
, js_null_str
) == 0) {
1746 ok
= JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
,
1747 js_GetErrorMessage
, NULL
,
1748 JSMSG_NO_PROPERTIES
, bytes
,
1750 } else if (JSVAL_IS_VOID(v
)) {
1751 ok
= JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
,
1752 js_GetErrorMessage
, NULL
,
1753 JSMSG_UNEXPECTED_TYPE
, bytes
,
1754 js_undefined_str
, NULL
);
1756 JS_ASSERT(JSVAL_IS_NULL(v
));
1757 ok
= JS_ReportErrorFlagsAndNumber(cx
, JSREPORT_ERROR
,
1758 js_GetErrorMessage
, NULL
,
1759 JSMSG_UNEXPECTED_TYPE
, bytes
,
1768 js_ReportMissingArg(JSContext
*cx
, jsval
*vp
, uintN arg
)
1774 JS_snprintf(argbuf
, sizeof argbuf
, "%u", arg
);
1776 if (VALUE_IS_FUNCTION(cx
, *vp
)) {
1777 atom
= GET_FUNCTION_PRIVATE(cx
, JSVAL_TO_OBJECT(*vp
))->atom
;
1778 bytes
= js_DecompileValueGenerator(cx
, JSDVG_SEARCH_STACK
, *vp
,
1779 ATOM_TO_STRING(atom
));
1783 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
1784 JSMSG_MISSING_FUN_ARG
, argbuf
,
1785 bytes
? bytes
: "");
1790 js_ReportValueErrorFlags(JSContext
*cx
, uintN flags
, const uintN errorNumber
,
1791 intN spindex
, jsval v
, JSString
*fallback
,
1792 const char *arg1
, const char *arg2
)
1797 JS_ASSERT(js_ErrorFormatString
[errorNumber
].argCount
>= 1);
1798 JS_ASSERT(js_ErrorFormatString
[errorNumber
].argCount
<= 3);
1799 bytes
= js_DecompileValueGenerator(cx
, spindex
, v
, fallback
);
1803 ok
= JS_ReportErrorFlagsAndNumber(cx
, flags
, js_GetErrorMessage
,
1804 NULL
, errorNumber
, bytes
, arg1
, arg2
);
1809 #if defined DEBUG && defined XP_UNIX
1810 /* For gdb usage. */
1811 void js_traceon(JSContext
*cx
) { cx
->tracefp
= stderr
; cx
->tracePrevPc
= NULL
; }
1812 void js_traceoff(JSContext
*cx
) { cx
->tracefp
= NULL
; }
1815 JSErrorFormatString js_ErrorFormatString
[JSErr_Limit
] = {
1816 #define MSG_DEF(name, number, count, exception, format) \
1817 { format, count, exception } ,
1822 JS_FRIEND_API(const JSErrorFormatString
*)
1823 js_GetErrorMessage(void *userRef
, const char *locale
, const uintN errorNumber
)
1825 if ((errorNumber
> 0) && (errorNumber
< JSErr_Limit
))
1826 return &js_ErrorFormatString
[errorNumber
];
1831 js_InvokeOperationCallback(JSContext
*cx
)
1833 JS_ASSERT(cx
->operationCallbackFlag
);
1836 * Reset the callback flag first, then yield. If another thread is racing
1837 * us here we will accumulate another callback request which will be
1838 * serviced at the next opportunity.
1840 cx
->operationCallbackFlag
= 0;
1843 * Unless we are going to run the GC, we automatically yield the current
1844 * context every time the operation callback is hit since we might be
1845 * called as a result of an impending GC, which would deadlock if we do
1846 * not yield. Operation callbacks are supposed to happen rarely (seconds,
1847 * not milliseconds) so it is acceptable to yield at every callback.
1849 JSRuntime
*rt
= cx
->runtime
;
1850 if (rt
->gcIsNeeded
) {
1851 js_GC(cx
, GC_NORMAL
);
1854 * On trace we can exceed the GC quota, see comments in NewGCArena. So
1855 * we check the quota and report OOM here when we are off trace.
1857 bool delayedOutOfMemory
;
1859 delayedOutOfMemory
= (rt
->gcBytes
> rt
->gcMaxBytes
);
1861 if (delayedOutOfMemory
) {
1862 js_ReportOutOfMemory(cx
);
1866 #ifdef JS_THREADSAFE
1868 JS_YieldRequest(cx
);
1872 JSOperationCallback cb
= cx
->operationCallback
;
1875 * Important: Additional callbacks can occur inside the callback handler
1876 * if it re-enters the JS engine. The embedding must ensure that the
1877 * callback is disconnected before attempting such re-entry.
1880 return !cb
|| cb(cx
);
1884 js_TriggerAllOperationCallbacks(JSRuntime
*rt
, JSBool gcLocked
)
1886 #ifdef JS_THREADSAFE
1887 Conditionally
<AutoLockGC
> lockIf(!gcLocked
, rt
);
1889 JSContext
*iter
= NULL
;
1890 while (JSContext
*acx
= js_ContextIterator(rt
, JS_FALSE
, &iter
))
1891 JS_TriggerOperationCallback(acx
);
1895 js_GetScriptedCaller(JSContext
*cx
, JSStackFrame
*fp
)
1898 fp
= js_GetTopStackFrame(cx
);
1908 js_GetCurrentBytecodePC(JSContext
* cx
)
1910 jsbytecode
*pc
, *imacpc
;
1913 if (JS_ON_TRACE(cx
)) {
1914 pc
= cx
->bailExit
->pc
;
1915 imacpc
= cx
->bailExit
->imacpc
;
1919 JS_ASSERT_NOT_ON_TRACE(cx
); /* for static analysis */
1920 JSStackFrame
* fp
= cx
->fp
;
1921 if (fp
&& fp
->regs
) {
1923 imacpc
= fp
->imacpc
;
1930 * If we are inside GetProperty_tn or similar, return a pointer to the
1931 * current instruction in the script, not the CALL instruction in the
1932 * imacro, for the benefit of callers doing bytecode inspection.
1934 return (*pc
== JSOP_CALL
&& imacpc
) ? imacpc
: pc
;
1938 js_CurrentPCIsInImacro(JSContext
*cx
)
1941 VOUCH_DOES_NOT_REQUIRE_STACK();
1942 return (JS_ON_TRACE(cx
) ? cx
->bailExit
->imacpc
: cx
->fp
->imacpc
) != NULL
;
1949 JSContext::containingCallStack(JSStackFrame
*target
)
1951 /* The context may have nothing running. */
1952 CallStack
*cs
= currentCallStack
;
1956 /* The active callstack's top frame is cx->fp. */
1958 JS_ASSERT(activeCallStack() == cs
);
1959 JSStackFrame
*f
= fp
;
1960 JSStackFrame
*stop
= cs
->getInitialFrame()->down
;
1961 for (; f
!= stop
; f
= f
->down
) {
1965 cs
= cs
->getPrevious();
1968 /* A suspended callstack's top frame is its suspended frame. */
1969 for (; cs
; cs
= cs
->getPrevious()) {
1970 JSStackFrame
*f
= cs
->getSuspendedFrame();
1971 JSStackFrame
*stop
= cs
->getInitialFrame()->down
;
1972 for (; f
!= stop
; f
= f
->down
) {
1982 JSContext::checkMallocGCPressure(void *p
)
1985 js_ReportOutOfMemory(this);
1989 #ifdef JS_THREADSAFE
1990 JS_ASSERT(thread
->gcThreadMallocBytes
<= 0);
1991 ptrdiff_t n
= JS_GC_THREAD_MALLOC_LIMIT
- thread
->gcThreadMallocBytes
;
1992 thread
->gcThreadMallocBytes
= JS_GC_THREAD_MALLOC_LIMIT
;
1994 AutoLockGC
lock(runtime
);
1995 runtime
->gcMallocBytes
-= n
;
1996 if (runtime
->isGCMallocLimitReached())
1999 JS_ASSERT(runtime
->isGCMallocLimitReached());
2000 runtime
->gcMallocBytes
= -1;
2003 * Empty the GC free lists to trigger a last-ditch GC when allocating
2004 * any GC thing later on this thread. This minimizes the amount of
2005 * checks on the fast path of the GC allocator. Note that we cannot
2006 * touch the free lists on other threads as their manipulation is not
2009 JS_THREAD_DATA(this)->purgeGCFreeLists();
2010 js_TriggerGC(this, true);
2016 JSContext::isConstructing()
2019 if (JS_ON_TRACE(this)) {
2020 JS_ASSERT(bailExit
);
2021 return *bailExit
->pc
== JSOP_NEW
;
2024 JSStackFrame
*fp
= js_GetTopStackFrame(this);
2025 return fp
&& (fp
->flags
& JSFRAME_CONSTRUCTING
);
2029 * Release pool's arenas if the stackPool has existed for longer than the
2030 * limit specified by gcEmptyArenaPoolLifespan.
2033 FreeOldArenas(JSRuntime
*rt
, JSArenaPool
*pool
)
2035 JSArena
*a
= pool
->current
;
2036 if (a
== pool
->first
.next
&& a
->avail
== a
->base
+ sizeof(int64
)) {
2037 int64 age
= JS_Now() - *(int64
*) a
->base
;
2038 if (age
> int64(rt
->gcEmptyArenaPoolLifespan
) * 1000)
2039 JS_FreeArenaPool(pool
);
2046 FreeOldArenas(runtime
, &stackPool
);
2047 FreeOldArenas(runtime
, ®expPool
);
2048 classProtoCache
.purge();