void XPCRootSetElem::AddToRootSet(JSRuntime* rt, XPCRootSetElem** listHead) { NS_ASSERTION(!mSelfp, "Must be not linked"); JS_LOCK_GC(rt); mSelfp = listHead; mNext = *listHead; if(mNext) { NS_ASSERTION(mNext->mSelfp == listHead, "Must be list start"); mNext->mSelfp = &mNext; } *listHead = this; JS_UNLOCK_GC(rt); }
void XPCRootSetElem::RemoveFromRootSet(JSRuntime* rt) { NS_ASSERTION(mSelfp, "Must be linked"); JS_LOCK_GC(rt); NS_ASSERTION(*mSelfp == this, "Link invariant"); *mSelfp = mNext; if(mNext) mNext->mSelfp = mSelfp; JS_UNLOCK_GC(rt); #ifdef DEBUG mSelfp = nsnull; mNext = nsnull; #endif }
JSContext * js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp) { JSContext *cx = *iterp; if (unlocked) JS_LOCK_GC(rt); if (!cx) cx = (JSContext *)&rt->contextList; cx = (JSContext *)cx->links.next; if (&cx->links == &rt->contextList) cx = NULL; *iterp = cx; if (unlocked) JS_UNLOCK_GC(rt); return cx; }
AutoLockJSGC(JSRuntime* rt) : mJSRuntime(rt) { JS_LOCK_GC(mJSRuntime); }
JSContext * js_NewContext(JSRuntime *rt, size_t stackChunkSize) { JSContext *cx; JSBool ok, first; cx = (JSContext *) malloc(sizeof *cx); if (!cx) return NULL; memset(cx, 0, sizeof *cx); cx->runtime = rt; #if JS_STACK_GROWTH_DIRECTION > 0 cx->stackLimit = (jsuword)-1; #endif #ifdef JS_THREADSAFE js_InitContextForLocking(cx); #endif JS_LOCK_GC(rt); for (;;) { first = (rt->contextList.next == &rt->contextList); if (rt->state == JSRTS_UP) { JS_ASSERT(!first); break; } if (rt->state == JSRTS_DOWN) { JS_ASSERT(first); rt->state = JSRTS_LAUNCHING; break; } JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT); } JS_APPEND_LINK(&cx->links, &rt->contextList); JS_UNLOCK_GC(rt); /* * First we do the infallible, every-time per-context initializations. * Should a later, fallible initialization (js_InitRegExpStatics, e.g., * or the stuff under 'if (first)' below) fail, at least the version * and arena-pools will be valid and safe to use (say, from the last GC * done by js_DestroyContext). */ cx->version = JSVERSION_DEFAULT; cx->jsop_eq = JSOP_EQ; cx->jsop_ne = JSOP_NE; JS_InitArenaPool(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval)); JS_InitArenaPool(&cx->tempPool, "temp", 1024, sizeof(jsdouble)); #if JS_HAS_REGEXPS if (!js_InitRegExpStatics(cx, &cx->regExpStatics)) { js_DestroyContext(cx, JS_NO_GC); return NULL; } #endif #if JS_HAS_EXCEPTIONS cx->throwing = JS_FALSE; #endif /* * If cx is the first context on this runtime, initialize well-known atoms, * keywords, numbers, and strings. If one of these steps should fail, the * runtime will be left in a partially initialized state, with zeroes and * nulls stored in the default-initialized remainder of the struct. We'll * clean the runtime up under js_DestroyContext, because cx will be "last" * as well as "first". */ if (first) { ok = (rt->atomState.liveAtoms == 0) ? js_InitAtomState(cx, &rt->atomState) : js_InitPinnedAtoms(cx, &rt->atomState); if (ok) ok = js_InitScanner(cx); if (ok) ok = js_InitRuntimeNumberState(cx); if (ok) ok = js_InitRuntimeScriptState(cx); if (ok) ok = js_InitRuntimeStringState(cx); if (!ok) { js_DestroyContext(cx, JS_NO_GC); return NULL; } JS_LOCK_GC(rt); rt->state = JSRTS_UP; JS_NOTIFY_ALL_CONDVAR(rt->stateChange); JS_UNLOCK_GC(rt); } return cx; }
void js_DestroyContext(JSContext *cx, JSGCMode gcmode) { JSRuntime *rt; JSBool last; JSArgumentFormatMap *map; JSLocalRootStack *lrs; JSLocalRootChunk *lrc; rt = cx->runtime; /* Remove cx from context list first. */ JS_LOCK_GC(rt); JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING); JS_REMOVE_LINK(&cx->links); last = (rt->contextList.next == &rt->contextList); if (last) rt->state = JSRTS_LANDING; JS_UNLOCK_GC(rt); if (last) { #ifdef JS_THREADSAFE /* * If cx is not in a request already, begin one now so that we wait * for any racing GC started on a not-last context to finish, before * we plow ahead and unpin atoms. Note that even though we begin a * request here if necessary, we end all requests on cx below before * forcing a final GC. This lets any not-last context destruction * racing in another thread try to force or maybe run the GC, but by * that point, rt->state will not be JSRTS_UP, and that GC attempt * will return early. */ if (cx->requestDepth == 0) JS_BeginRequest(cx); #endif /* Unpin all pinned atoms before final GC. */ js_UnpinPinnedAtoms(&rt->atomState); /* Unlock and clear GC things held by runtime pointers. */ js_FinishRuntimeNumberState(cx); js_FinishRuntimeStringState(cx); /* Clear debugging state to remove GC roots. */ JS_ClearAllTraps(cx); JS_ClearAllWatchPoints(cx); } #if JS_HAS_REGEXPS /* * Remove more GC roots in regExpStatics, then collect garbage. * XXX anti-modularity alert: we rely on the call to js_RemoveRoot within * XXX this function call to wait for any racing GC to complete, in the * XXX case where JS_DestroyContext is called outside of a request on cx */ js_FreeRegExpStatics(cx, &cx->regExpStatics); #endif #ifdef JS_THREADSAFE /* * Destroying a context implicitly calls JS_EndRequest(). Also, we must * end our request here in case we are "last" -- in that event, another * js_DestroyContext that was not last might be waiting in the GC for our * request to end. We'll let it run below, just before we do the truly * final GC and then free atom state. * * At this point, cx must be inaccessible to other threads. It's off the * rt->contextList, and it should not be reachable via any object private * data structure. */ while (cx->requestDepth != 0) JS_EndRequest(cx); #endif if (last) { /* Always force, so we wait for any racing GC to finish. */ js_ForceGC(cx, GC_LAST_CONTEXT); /* Iterate until no finalizer removes a GC root or lock. */ while (rt->gcPoke) js_GC(cx, GC_LAST_CONTEXT); /* Try to free atom state, now that no unrooted scripts survive. */ if (rt->atomState.liveAtoms == 0) js_FreeAtomState(cx, &rt->atomState); /* Now after the last GC can we free the script filename table. */ js_FinishRuntimeScriptState(cx); /* Take the runtime down, now that it has no contexts or atoms. */ JS_LOCK_GC(rt); rt->state = JSRTS_DOWN; JS_NOTIFY_ALL_CONDVAR(rt->stateChange); JS_UNLOCK_GC(rt); } else { if (gcmode == JS_FORCE_GC) js_ForceGC(cx, 0); else if (gcmode == JS_MAYBE_GC) JS_MaybeGC(cx); } /* Free the stuff hanging off of cx. */ JS_FinishArenaPool(&cx->stackPool); JS_FinishArenaPool(&cx->tempPool); if (cx->lastMessage) free(cx->lastMessage); /* Remove any argument formatters. */ map = cx->argumentFormatMap; while (map) { JSArgumentFormatMap *temp = map; map = map->next; JS_free(cx, temp); } /* Destroy the resolve recursion damper. */ if (cx->resolvingTable) { JS_DHashTableDestroy(cx->resolvingTable); cx->resolvingTable = NULL; } lrs = cx->localRootStack; if (lrs) { while ((lrc = lrs->topChunk) != &lrs->firstChunk) { lrs->topChunk = lrc->down; JS_free(cx, lrc); } JS_free(cx, lrs); } /* Destroy the lint information */ if (cx->lint) { JS_free(cx, cx->lint); } /* Finally, free cx itself. */ free(cx); }
JSContext * js_NewContext(JSRuntime *rt, size_t stackChunkSize) { JSContext *cx; JSBool ok, first; JSContextCallback cxCallback; cx = (JSContext *) malloc(sizeof *cx); if (!cx) return NULL; memset(cx, 0, sizeof *cx); cx->runtime = rt; JS_ClearOperationCallback(cx); cx->debugHooks = &rt->globalDebugHooks; #if JS_STACK_GROWTH_DIRECTION > 0 cx->stackLimit = (jsuword)-1; #endif cx->scriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA; #ifdef JS_THREADSAFE JS_INIT_CLIST(&cx->threadLinks); js_SetContextThread(cx); #endif JS_LOCK_GC(rt); for (;;) { first = (rt->contextList.next == &rt->contextList); if (rt->state == JSRTS_UP) { JS_ASSERT(!first); break; } if (rt->state == JSRTS_DOWN) { JS_ASSERT(first); rt->state = JSRTS_LAUNCHING; break; } JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT); } JS_APPEND_LINK(&cx->links, &rt->contextList); JS_UNLOCK_GC(rt); /* * First we do the infallible, every-time per-context initializations. * Should a later, fallible initialization (js_InitRegExpStatics, e.g., * or the stuff under 'if (first)' below) fail, at least the version * and arena-pools will be valid and safe to use (say, from the last GC * done by js_DestroyContext). */ cx->version = JSVERSION_DEFAULT; JS_INIT_ARENA_POOL(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval), &cx->scriptStackQuota); JS_INIT_ARENA_POOL(&cx->tempPool, "temp", 1024, sizeof(jsdouble), &cx->scriptStackQuota); if (!js_InitRegExpStatics(cx, &cx->regExpStatics)) { js_DestroyContext(cx, JSDCM_NEW_FAILED); return NULL; } /* * If cx is the first context on this runtime, initialize well-known atoms, * keywords, numbers, and strings. If one of these steps should fail, the * runtime will be left in a partially initialized state, with zeroes and * nulls stored in the default-initialized remainder of the struct. We'll * clean the runtime up under js_DestroyContext, because cx will be "last" * as well as "first". */ if (first) { #ifdef JS_THREADSAFE JS_BeginRequest(cx); #endif ok = js_InitCommonAtoms(cx); /* * scriptFilenameTable may be left over from a previous episode of * non-zero contexts alive in rt, so don't re-init the table if it's * not necessary. */ if (ok && !rt->scriptFilenameTable) ok = js_InitRuntimeScriptState(rt); if (ok) ok = js_InitRuntimeNumberState(cx); if (ok) ok = js_InitRuntimeStringState(cx); #ifdef JS_THREADSAFE JS_EndRequest(cx); #endif if (!ok) { js_DestroyContext(cx, JSDCM_NEW_FAILED); return NULL; } JS_LOCK_GC(rt); rt->state = JSRTS_UP; JS_NOTIFY_ALL_CONDVAR(rt->stateChange); JS_UNLOCK_GC(rt); } cxCallback = rt->cxCallback; if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW)) { js_DestroyContext(cx, JSDCM_NEW_FAILED); return NULL; } return cx; }