diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 239b6b90854b..b8151bf741fa 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -774,7 +774,7 @@ JS_BeginRequest(JSContext *cx) JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread)); if (!cx->requestDepth) { JSRuntime *rt = cx->runtime; - JS_LOCK_GC(rt); + AutoLockGC lock(rt); /* Wait until the GC is finished. */ if (rt->gcThread != cx->thread) { @@ -786,7 +786,6 @@ JS_BeginRequest(JSContext *cx) rt->requestCount++; cx->requestDepth = 1; cx->outstandingRequests++; - JS_UNLOCK_GC(rt); return; } cx->requestDepth++; @@ -809,7 +808,7 @@ JS_EndRequest(JSContext *cx) /* Lock before clearing to interlock with ClaimScope, in jslock.c. */ rt = cx->runtime; - JS_LOCK_GC(rt); + AutoLockGC lock(rt); cx->requestDepth = 0; cx->outstandingRequests--; @@ -820,8 +819,6 @@ JS_EndRequest(JSContext *cx) rt->requestCount--; if (rt->requestCount == 0) JS_NOTIFY_REQUEST_DONE(rt); - - JS_UNLOCK_GC(rt); return; } @@ -882,10 +879,9 @@ JS_TransferRequest(JSContext *cx, JSContext *another) JS_ASSERT(another->requestDepth == 0); /* Serialize access to JSContext::requestDepth from other threads. */ - JS_LOCK_GC(cx->runtime); + AutoLockGC lock(cx->runtime); another->requestDepth = cx->requestDepth; cx->requestDepth = 0; - JS_UNLOCK_GC(cx->runtime); #endif } @@ -1036,24 +1032,22 @@ JS_GetOptions(JSContext *cx) JS_PUBLIC_API(uint32) JS_SetOptions(JSContext *cx, uint32 options) { - JS_LOCK_GC(cx->runtime); + AutoLockGC lock(cx->runtime); uint32 oldopts = cx->options; cx->options = options; js_SyncOptionsToVersion(cx); cx->updateJITEnabled(); - JS_UNLOCK_GC(cx->runtime); return oldopts; } JS_PUBLIC_API(uint32) JS_ToggleOptions(JSContext *cx, uint32 options) { - JS_LOCK_GC(cx->runtime); + AutoLockGC lock(cx->runtime); uint32 oldopts = cx->options; cx->options ^= options; js_SyncOptionsToVersion(cx); cx->updateJITEnabled(); - JS_UNLOCK_GC(cx->runtime); return oldopts; } @@ -5749,10 +5743,9 @@ JS_ClearContextThread(JSContext *cx) * see bug 476934. */ JSRuntime *rt = cx->runtime; - JS_LOCK_GC(rt); + AutoLockGC lock(rt); js_WaitForGC(rt); js_ClearContextThread(cx); - JS_UNLOCK_GC(rt); return old; #else return 0; diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index d76fd6fc1dd2..ba64e8e232d1 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -569,10 +569,9 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize) return NULL; } - JS_LOCK_GC(rt); + AutoLockGC lock(rt); rt->state = JSRTS_UP; JS_NOTIFY_ALL_CONDVAR(rt->stateChange); - JS_UNLOCK_GC(rt); } cxCallback = rt->cxCallback; @@ -892,14 +891,11 @@ js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp) { JSContext *cx = *iterp; - if (unlocked) - JS_LOCK_GC(rt); + Conditionally lockIf(unlocked, rt); cx = js_ContextFromLinkField(cx ? cx->link.next : rt->contextList.next); if (&cx->link == &rt->contextList) cx = NULL; *iterp = cx; - if (unlocked) - JS_UNLOCK_GC(rt); return cx; } @@ -1867,18 +1863,12 @@ js_InvokeOperationCallback(JSContext *cx) void js_TriggerAllOperationCallbacks(JSRuntime *rt, JSBool gcLocked) { - JSContext *acx, *iter; #ifdef JS_THREADSAFE - if (!gcLocked) - JS_LOCK_GC(rt); + Conditionally lockIf(!gcLocked, rt); #endif - iter = NULL; - while ((acx = js_ContextIterator(rt, JS_FALSE, &iter))) + JSContext *iter = NULL; + while (JSContext *acx = js_ContextIterator(rt, JS_FALSE, &iter)) JS_TriggerOperationCallback(acx); -#ifdef JS_THREADSAFE - if (!gcLocked) - JS_UNLOCK_GC(rt); -#endif } JSStackFrame * @@ -1981,7 +1971,7 @@ JSContext::checkMallocGCPressure(void *p) ptrdiff_t n = JS_GC_THREAD_MALLOC_LIMIT - thread->gcThreadMallocBytes; thread->gcThreadMallocBytes = JS_GC_THREAD_MALLOC_LIMIT; - JS_LOCK_GC(runtime); + AutoLockGC lock(runtime); runtime->gcMallocBytes -= n; if (runtime->isGCMallocLimitReached()) #endif @@ -1999,7 +1989,6 @@ JSContext::checkMallocGCPressure(void *p) JS_THREAD_DATA(this)->purgeGCFreeLists(); js_TriggerGC(this, true); } - JS_UNLOCK_GC(runtime); } diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 38175a5bca57..77245703fc8a 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1947,6 +1947,29 @@ class AutoXMLRooter : private AutoGCRooter { }; #endif /* JS_HAS_XML_SUPPORT */ +class AutoLockGC { +private: + JSRuntime *rt; +public: + explicit AutoLockGC(JSRuntime *rt) : rt(rt) { JS_LOCK_GC(rt); } + ~AutoLockGC() { JS_UNLOCK_GC(rt); } +}; + +class AutoUnlockGC { +private: + JSRuntime *rt; +public: + explicit AutoUnlockGC(JSRuntime *rt) : rt(rt) { JS_UNLOCK_GC(rt); } + ~AutoUnlockGC() { JS_LOCK_GC(rt); } +}; + +class AutoKeepAtoms { + JSRuntime *rt; + public: + explicit AutoKeepAtoms(JSRuntime *rt) : rt(rt) { JS_KEEP_ATOMS(rt); } + ~AutoKeepAtoms() { JS_UNKEEP_ATOMS(rt); } +}; + } /* namespace js */ class JSAutoResolveFlags diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 35be394d3492..186d66f28c62 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -378,14 +378,15 @@ JS_PUBLIC_API(JSBool) JS_SetInterrupt(JSRuntime *rt, JSTrapHandler handler, void *closure) { #ifdef JS_TRACER - JS_LOCK_GC(rt); - bool wasInhibited = rt->debuggerInhibitsJIT(); + { + AutoLockGC lock(rt); + bool wasInhibited = rt->debuggerInhibitsJIT(); #endif - rt->globalDebugHooks.interruptHandler = handler; - rt->globalDebugHooks.interruptHandlerData = closure; + rt->globalDebugHooks.interruptHandler = handler; + rt->globalDebugHooks.interruptHandlerData = closure; #ifdef JS_TRACER - JITInhibitingHookChange(rt, wasInhibited); - JS_UNLOCK_GC(rt); + JITInhibitingHookChange(rt, wasInhibited); + } LeaveTraceRT(rt); #endif return JS_TRUE; @@ -395,7 +396,7 @@ JS_PUBLIC_API(JSBool) JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep) { #ifdef JS_TRACER - JS_LOCK_GC(rt); + AutoLockGC lock(rt); bool wasInhibited = rt->debuggerInhibitsJIT(); #endif if (handlerp) @@ -406,7 +407,6 @@ JS_ClearInterrupt(JSRuntime *rt, JSTrapHandler *handlerp, void **closurep) rt->globalDebugHooks.interruptHandlerData = 0; #ifdef JS_TRACER JITInhibitingHookChange(rt, wasInhibited); - JS_UNLOCK_GC(rt); #endif return JS_TRUE; } @@ -1591,14 +1591,15 @@ JS_PUBLIC_API(JSBool) JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure) { #ifdef JS_TRACER - JS_LOCK_GC(rt); - bool wasInhibited = rt->debuggerInhibitsJIT(); + { + AutoLockGC lock(rt); + bool wasInhibited = rt->debuggerInhibitsJIT(); #endif - rt->globalDebugHooks.callHook = hook; - rt->globalDebugHooks.callHookData = closure; + rt->globalDebugHooks.callHook = hook; + rt->globalDebugHooks.callHookData = closure; #ifdef JS_TRACER - JITInhibitingHookChange(rt, wasInhibited); - JS_UNLOCK_GC(rt); + JITInhibitingHookChange(rt, wasInhibited); + } if (hook) LeaveTraceRT(rt); #endif @@ -1609,14 +1610,15 @@ JS_PUBLIC_API(JSBool) JS_SetObjectHook(JSRuntime *rt, JSObjectHook hook, void *closure) { #ifdef JS_TRACER - JS_LOCK_GC(rt); - bool wasInhibited = rt->debuggerInhibitsJIT(); + { + AutoLockGC lock(rt); + bool wasInhibited = rt->debuggerInhibitsJIT(); #endif - rt->globalDebugHooks.objectHook = hook; - rt->globalDebugHooks.objectHookData = closure; + rt->globalDebugHooks.objectHook = hook; + rt->globalDebugHooks.objectHookData = closure; #ifdef JS_TRACER - JITInhibitingHookChange(rt, wasInhibited); - JS_UNLOCK_GC(rt); + JITInhibitingHookChange(rt, wasInhibited); + } if (hook) LeaveTraceRT(rt); #endif @@ -1820,13 +1822,12 @@ JS_SetContextDebugHooks(JSContext *cx, const JSDebugHooks *hooks) LeaveTrace(cx); #ifdef JS_TRACER - JS_LOCK_GC(cx->runtime); + AutoLockGC lock(cx->runtime); #endif JSDebugHooks *old = const_cast(cx->debugHooks); cx->debugHooks = hooks; #ifdef JS_TRACER cx->updateJITEnabled(); - JS_UNLOCK_GC(cx->runtime); #endif return old; } diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 2ce094dc7ac8..33bc911df18a 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1187,7 +1187,7 @@ js_AddRootRT(JSRuntime *rt, void *rp, const char *name) * We have to preserve API compatibility here, now that we avoid holding * rt->gcLock across the mark phase (including the root hashtable mark). */ - JS_LOCK_GC(rt); + AutoLockGC lock(rt); js_WaitForGC(rt); rhe = (JSGCRootHashEntry *) JS_DHashTableOperate(&rt->gcRootsHash, rp, JS_DHASH_ADD); @@ -1198,7 +1198,6 @@ js_AddRootRT(JSRuntime *rt, void *rp, const char *name) } else { ok = JS_FALSE; } - JS_UNLOCK_GC(rt); return ok; } @@ -1209,11 +1208,10 @@ js_RemoveRoot(JSRuntime *rt, void *rp) * Due to the JS_RemoveRootRT API, we may be called outside of a request. * Same synchronization drill as above in js_AddRoot. */ - JS_LOCK_GC(rt); + AutoLockGC lock(rt); js_WaitForGC(rt); (void) JS_DHashTableOperate(&rt->gcRootsHash, rp, JS_DHASH_REMOVE); rt->gcPoke = JS_TRUE; - JS_UNLOCK_GC(rt); return JS_TRUE; } @@ -1325,30 +1323,19 @@ js_gcroot_mapper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, uint32 js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data) { - GCRootMapArgs args; - uint32 rv; - - args.map = map; - args.data = data; - JS_LOCK_GC(rt); - rv = JS_DHashTableEnumerate(&rt->gcRootsHash, js_gcroot_mapper, &args); - JS_UNLOCK_GC(rt); - return rv; + GCRootMapArgs args = {map, data}; + AutoLockGC lock(rt); + return JS_DHashTableEnumerate(&rt->gcRootsHash, js_gcroot_mapper, &args); } JSBool js_RegisterCloseableIterator(JSContext *cx, JSObject *obj) { - JSRuntime *rt; - JSBool ok; - - rt = cx->runtime; + JSRuntime *rt = cx->runtime; JS_ASSERT(!rt->gcRunning); - JS_LOCK_GC(rt); - ok = rt->gcIteratorTable.append(obj); - JS_UNLOCK_GC(rt); - return ok; + AutoLockGC lock(rt); + return rt->gcIteratorTable.append(obj); } static void @@ -1447,77 +1434,75 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind) { JS_ASSERT(!GetGCFreeLists(cx)->finalizables[thingKind]); JSRuntime *rt = cx->runtime; - JS_LOCK_GC(rt); - JS_ASSERT(!rt->gcRunning); - if (rt->gcRunning) { - METER(rt->gcStats.finalfail++); - JS_UNLOCK_GC(rt); - return NULL; - } - - bool canGC = !JS_ON_TRACE(cx) && !JS_THREAD_DATA(cx)->waiveGCQuota; - bool doGC = canGC && IsGCThresholdReached(rt); - JSGCArenaList *arenaList = &rt->gcArenaList[thingKind]; + JSGCArenaList *arenaList; JSGCArena *a; - for (;;) { - if (doGC) { - /* - * Keep rt->gcLock across the call into js_GC so we don't starve - * and lose to racing threads who deplete the heap just after - * js_GC has replenished it (or has synchronized with a racing - * GC that collected a bunch of garbage). This unfair scheduling - * can happen on certain operating systems. For the gory details, - * see bug 162779 at https://bugzilla.mozilla.org/. - */ - js_GC(cx, GC_LAST_DITCH); - METER(cx->runtime->gcStats.arenaStats[thingKind].retry++); - canGC = false; - /* - * The JSGC_END callback can legitimately allocate new GC things - * and populate the free list. If that happens, just return that - * list head. - */ - JSGCThing *freeList = GetGCFreeLists(cx)->finalizables[thingKind]; - if (freeList) { - JS_UNLOCK_GC(rt); - return freeList; - } - } - - while ((a = arenaList->cursor) != NULL) { - arenaList->cursor = a->info.prev; - JSGCThing *freeList = a->info.freeList; - if (freeList) { - a->info.freeList = NULL; - JS_UNLOCK_GC(rt); - return freeList; - } - } - - a = NewGCArena(cx); - if (a) - break; - if (!canGC) { - METER(cx->runtime->gcStats.arenaStats[thingKind].fail++); - JS_UNLOCK_GC(rt); + { + AutoLockGC lock(rt); + JS_ASSERT(!rt->gcRunning); + if (rt->gcRunning) { + METER(rt->gcStats.finalfail++); return NULL; } - doGC = true; - } - /* - * Do only minimal initialization of the arena inside the GC lock. We - * can do the rest outside the lock because no other threads will see - * the arena until the GC is run. - */ - a->info.list = arenaList; - a->info.prev = arenaList->head; - a->clearPrevUnmarked(); - a->info.freeList = NULL; - a->info.unmarkedChildren = 0; - arenaList->head = a; - JS_UNLOCK_GC(rt); + bool canGC = !JS_ON_TRACE(cx) && !JS_THREAD_DATA(cx)->waiveGCQuota; + bool doGC = canGC && IsGCThresholdReached(rt); + arenaList = &rt->gcArenaList[thingKind]; + for (;;) { + if (doGC) { + /* + * Keep rt->gcLock across the call into js_GC so we don't + * starve and lose to racing threads who deplete the heap just + * after js_GC has replenished it (or has synchronized with a + * racing GC that collected a bunch of garbage). This unfair + * scheduling can happen on certain operating systems. For the + * gory details, see bug 162779. + */ + js_GC(cx, GC_LAST_DITCH); + METER(cx->runtime->gcStats.arenaStats[thingKind].retry++); + canGC = false; + + /* + * The JSGC_END callback can legitimately allocate new GC + * things and populate the free list. If that happens, just + * return that list head. + */ + JSGCThing *freeList = GetGCFreeLists(cx)->finalizables[thingKind]; + if (freeList) + return freeList; + } + + while ((a = arenaList->cursor) != NULL) { + arenaList->cursor = a->info.prev; + JSGCThing *freeList = a->info.freeList; + if (freeList) { + a->info.freeList = NULL; + return freeList; + } + } + + a = NewGCArena(cx); + if (a) + break; + if (!canGC) { + METER(cx->runtime->gcStats.arenaStats[thingKind].fail++); + return NULL; + } + doGC = true; + } + + /* + * Do only minimal initialization of the arena inside the GC lock. We + * can do the rest outside the lock because no other threads will see + * the arena until the GC is run. + */ + a->info.list = arenaList; + a->info.prev = arenaList->head; + a->clearPrevUnmarked(); + a->info.freeList = NULL; + a->info.unmarkedChildren = 0; + arenaList->head = a; + } a->clearMarkBitmap(); return MakeNewArenaFreeList(a, arenaList->thingSize); @@ -1818,7 +1803,7 @@ js_LockGCThingRT(JSRuntime *rt, void *thing) if (!thing) return true; - JS_LOCK_GC(rt); + AutoLockGC lock(rt); JSGCLockHashEntry *lhe = (JSGCLockHashEntry *) JS_DHashTableOperate(&rt->gcLocksHash, thing, JS_DHASH_ADD); @@ -1833,7 +1818,6 @@ js_LockGCThingRT(JSRuntime *rt, void *thing) } METER(rt->gcStats.lock++); } - JS_UNLOCK_GC(rt); return ok; } @@ -1843,7 +1827,7 @@ js_UnlockGCThingRT(JSRuntime *rt, void *thing) if (!thing) return; - JS_LOCK_GC(rt); + AutoLockGC lock(rt); JSGCLockHashEntry *lhe = (JSGCLockHashEntry *) JS_DHashTableOperate(&rt->gcLocksHash, thing, JS_DHASH_LOOKUP); @@ -1853,7 +1837,6 @@ js_UnlockGCThingRT(JSRuntime *rt, void *thing) JS_DHashTableOperate(&rt->gcLocksHash, thing, JS_DHASH_REMOVE); METER(rt->gcStats.unlock++); } - JS_UNLOCK_GC(rt); } JS_PUBLIC_API(void) @@ -3151,15 +3134,8 @@ FireGCBegin(JSContext *cx, JSGCInvocationKind gckind) * another thread. */ if (gckind != GC_SET_SLOT_REQUEST && callback) { - JSBool ok; - - if (gckind & GC_LOCK_HELD) - JS_UNLOCK_GC(rt); - ok = callback(cx, JSGC_BEGIN); - if (gckind & GC_LOCK_HELD) - JS_LOCK_GC(rt); - if (!ok && gckind != GC_LAST_CONTEXT) - return false; + Conditionally unlockIf(gckind & GC_LOCK_HELD, rt); + return callback(cx, JSGC_BEGIN) || gckind == GC_LAST_CONTEXT; } return true; } @@ -3196,14 +3172,10 @@ FireGCEnd(JSContext *cx, JSGCInvocationKind gckind) * collection and overwrites. */ AutoSaveWeakRoots save(cx); - - JS_KEEP_ATOMS(rt); - JS_UNLOCK_GC(rt); + AutoKeepAtoms keep(rt); + AutoUnlockGC unlock(rt); (void) callback(cx, JSGC_END); - - JS_LOCK_GC(rt); - JS_UNKEEP_ATOMS(rt); } } return true; @@ -3300,9 +3272,8 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) * notify the GC. Otherwise the GC may start immediately * after we unlock while this thread is still on trace. */ - JS_UNLOCK_GC(rt); + AutoUnlockGC unlock(rt); LeaveTrace(cx); - JS_LOCK_GC(rt); } #endif rt->requestCount -= requestDebit; @@ -3320,8 +3291,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) * Make sure that the GC from another thread respects * GC_KEEP_ATOMS. */ - if (gckind & GC_KEEP_ATOMS) - JS_KEEP_ATOMS(rt); + Conditionally keepIf(gckind & GC_KEEP_ATOMS, rt); /* * Check that we did not release the GC lock above and let the @@ -3333,8 +3303,6 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) } while (rt->gcLevel > 0); cx->thread->gcWaiting = false; - if (gckind & GC_KEEP_ATOMS) - JS_UNKEEP_ATOMS(rt); rt->requestCount += requestDebit; } } @@ -3407,10 +3375,9 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) while ((ssr = rt->setSlotRequests) != NULL) { rt->setSlotRequests = ssr->next; - JS_UNLOCK_GC(rt); + AutoUnlockGC unlock(rt); ssr->next = NULL; ProcessSetSlotRequest(cx, ssr); - JS_LOCK_GC(rt); } /* diff --git a/js/src/jslock.cpp b/js/src/jslock.cpp index 2982d7bcedb8..1533977c55ee 100644 --- a/js/src/jslock.cpp +++ b/js/src/jslock.cpp @@ -558,7 +558,7 @@ ClaimTitle(JSTitle *title, JSContext *cx) cx->thread == rt->gcThread && rt->gcRunning); JS_RUNTIME_METER(rt, claimAttempts); - JS_LOCK_GC(rt); + AutoLockGC lock(rt); /* Reload in case ownercx went away while we blocked on the lock. */ while (JSContext *ownercx = title->ownercx) { @@ -595,7 +595,6 @@ ClaimTitle(JSTitle *title, JSContext *cx) } if (canClaim) { title->ownercx = cx; - JS_UNLOCK_GC(rt); JS_RUNTIME_METER(rt, claimedTitles); return JS_TRUE; } @@ -646,8 +645,6 @@ ClaimTitle(JSTitle *title, JSContext *cx) JS_ASSERT(stat != PR_FAILURE); cx->thread->titleToShare = NULL; } - - JS_UNLOCK_GC(rt); return JS_FALSE; } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index e3d3c8733f5f..6a69d243b528 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -451,6 +451,7 @@ js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, map->table = table; JS_KEEP_ATOMS(cx->runtime); } + /* From this point the control must flow either through out: or bad:. */ ida = NULL; @@ -2884,10 +2885,9 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, */ if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) { AutoValueRooter tvr(cx, obj); - JS_KEEP_ATOMS(cx->runtime); + AutoKeepAtoms keep(cx->runtime); cx->debugHooks->objectHook(cx, obj, JS_TRUE, cx->debugHooks->objectHookData); - JS_UNKEEP_ATOMS(cx->runtime); cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj; } @@ -4601,10 +4601,11 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, : NULL; JS_UNLOCK_OBJ(cx, obj); - /* Protect id and all atoms from a GC nested in resolve. */ - JS_KEEP_ATOMS(cx->runtime); - ok = newresolve(cx, obj, ID_TO_VALUE(id), flags, &obj2); - JS_UNKEEP_ATOMS(cx->runtime); + { + /* Protect id and all atoms from a GC nested in resolve. */ + AutoKeepAtoms keep(cx->runtime); + ok = newresolve(cx, obj, ID_TO_VALUE(id), flags, &obj2); + } if (!ok) goto cleanup; diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 433e09780007..0656e96cc0d3 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -169,9 +169,6 @@ JSCompiler::init(const jschar *base, size_t length, JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark); return false; } - - /* Root atoms and objects allocated for the parsed tree. */ - JS_KEEP_ATOMS(cx->runtime); return true; } @@ -181,7 +178,6 @@ JSCompiler::~JSCompiler() if (principals) JSPRINCIPALS_DROP(cx, principals); - JS_UNKEEP_ATOMS(cx->runtime); tokenStream.close(); JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark); } diff --git a/js/src/jsparse.h b/js/src/jsparse.h index ad1d6e4c48bb..d69dff243be0 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -924,11 +924,15 @@ struct JSCompiler : private js::AutoGCRooter { JSObjectBox *traceListHead; /* list of parsed object for GC tracing */ JSTreeContext *tc; /* innermost tree context (stack-allocated) */ + /* Root atoms and objects allocated for the parsed tree. */ + js::AutoKeepAtoms keepAtoms; + JSCompiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL) : js::AutoGCRooter(cx, COMPILER), context(cx), aleFreeList(NULL), tokenStream(cx), principals(NULL), callerFrame(cfp), callerVarObj(cfp ? cfp->varobj(cx->containingCallStack(cfp)) : NULL), - nodeList(NULL), functionCount(0), traceListHead(NULL), tc(NULL) + nodeList(NULL), functionCount(0), traceListHead(NULL), tc(NULL), + keepAtoms(cx->runtime) { js::PodArrayZero(tempFreeList); setPrincipals(prin); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index db7a69a339c7..73edd15ca732 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1087,10 +1087,9 @@ js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun) hook = cx->debugHooks->newScriptHook; if (hook) { - JS_KEEP_ATOMS(cx->runtime); + AutoKeepAtoms keep(cx->runtime); hook(cx, script->filename, script->lineno, script, fun, cx->debugHooks->newScriptHookData); - JS_UNKEEP_ATOMS(cx->runtime); } } diff --git a/js/src/jstl.h b/js/src/jstl.h index c745aa614bdb..3faaacb6a47e 100644 --- a/js/src/jstl.h +++ b/js/src/jstl.h @@ -300,6 +300,18 @@ class LazilyConstructed } }; + +template +class Conditionally { + LazilyConstructed t; + + public: + Conditionally(bool b) { if (b) t.construct(); } + + template + Conditionally(bool b, const T1 &t1) { if (b) t.construct(t1); } +}; + template JS_ALWAYS_INLINE static void PodZero(T *t) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 8ac9698cab14..09945a5926a2 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -14945,12 +14945,11 @@ GetBuiltinFunction(JSContext *cx, uintN index) funobj->clearProto(); funobj->clearParent(); - JS_LOCK_GC(rt); + AutoLockGC lock(rt); if (!rt->builtinFunctions[index]) /* retest now that the lock is held */ rt->builtinFunctions[index] = funobj; else funobj = rt->builtinFunctions[index]; - JS_UNLOCK_GC(rt); } } return funobj;