зеркало из https://github.com/mozilla/gecko-dev.git
Bug 553671 part 4 - RAII for JS_{LOCK,UNLOCK}_GC and JS_{KEEP,UNKEEP}_ATOMS. r=luke.
--HG-- extra : rebase_source : dfdfcdd3a602e12de1836068e2c9f16fce46d7b2
This commit is contained in:
Родитель
cfd234f70a
Коммит
447564b524
|
@ -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;
|
||||
|
|
|
@ -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<AutoLockGC> 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<AutoLockGC> 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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<JSDebugHooks *>(cx->debugHooks);
|
||||
cx->debugHooks = hooks;
|
||||
#ifdef JS_TRACER
|
||||
cx->updateJITEnabled();
|
||||
JS_UNLOCK_GC(cx->runtime);
|
||||
#endif
|
||||
return old;
|
||||
}
|
||||
|
|
195
js/src/jsgc.cpp
195
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<AutoUnlockGC> 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<AutoKeepAtoms> 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -300,6 +300,18 @@ class LazilyConstructed
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class Conditionally {
|
||||
LazilyConstructed<T> t;
|
||||
|
||||
public:
|
||||
Conditionally(bool b) { if (b) t.construct(); }
|
||||
|
||||
template <class T1>
|
||||
Conditionally(bool b, const T1 &t1) { if (b) t.construct(t1); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
JS_ALWAYS_INLINE static void
|
||||
PodZero(T *t)
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче