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:
Jason Orendorff 2010-04-08 07:54:18 -05:00
Родитель cfd234f70a
Коммит 447564b524
12 изменённых файлов: 166 добавлений и 185 удалений

Просмотреть файл

@ -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);
{
AutoLockGC lock(rt);
bool wasInhibited = rt->debuggerInhibitsJIT();
#endif
rt->globalDebugHooks.interruptHandler = handler;
rt->globalDebugHooks.interruptHandlerData = closure;
#ifdef JS_TRACER
JITInhibitingHookChange(rt, wasInhibited);
JS_UNLOCK_GC(rt);
}
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);
{
AutoLockGC lock(rt);
bool wasInhibited = rt->debuggerInhibitsJIT();
#endif
rt->globalDebugHooks.callHook = hook;
rt->globalDebugHooks.callHookData = closure;
#ifdef JS_TRACER
JITInhibitingHookChange(rt, wasInhibited);
JS_UNLOCK_GC(rt);
}
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);
{
AutoLockGC lock(rt);
bool wasInhibited = rt->debuggerInhibitsJIT();
#endif
rt->globalDebugHooks.objectHook = hook;
rt->globalDebugHooks.objectHookData = closure;
#ifdef JS_TRACER
JITInhibitingHookChange(rt, wasInhibited);
JS_UNLOCK_GC(rt);
}
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;
}

Просмотреть файл

@ -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,50 +1434,49 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
{
JS_ASSERT(!GetGCFreeLists(cx)->finalizables[thingKind]);
JSRuntime *rt = cx->runtime;
JS_LOCK_GC(rt);
JSGCArenaList *arenaList;
JSGCArena *a;
{
AutoLockGC lock(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];
JSGCArena *a;
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 at https://bugzilla.mozilla.org/.
* 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.
* 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);
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;
JS_UNLOCK_GC(rt);
return freeList;
}
}
@ -1500,7 +1486,6 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
break;
if (!canGC) {
METER(cx->runtime->gcStats.arenaStats[thingKind].fail++);
JS_UNLOCK_GC(rt);
return NULL;
}
doGC = true;
@ -1517,7 +1502,7 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
a->info.freeList = NULL;
a->info.unmarkedChildren = 0;
arenaList->head = a;
JS_UNLOCK_GC(rt);
}
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;
}

Просмотреть файл

@ -452,6 +452,7 @@ js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap,
JS_KEEP_ATOMS(cx->runtime);
}
/* From this point the control must flow either through out: or bad:. */
ida = NULL;
if (map->depth == 0) {
@ -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);
AutoKeepAtoms keep(cx->runtime);
ok = newresolve(cx, obj, ID_TO_VALUE(id), flags, &obj2);
JS_UNKEEP_ATOMS(cx->runtime);
}
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;