зеркало из https://github.com/mozilla/pjs.git
bug 714066 - Missed FreeChunkList call in JSRuntime::onOutOfMemory. r=wmccloskey
This commit is contained in:
Родитель
859fe9155c
Коммит
222e9fbd53
|
@ -104,7 +104,6 @@ ThreadData::ThreadData(JSRuntime *rt)
|
|||
#ifdef JS_THREADSAFE
|
||||
requestDepth(0),
|
||||
#endif
|
||||
waiveGCQuota(false),
|
||||
tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
|
||||
execAlloc(NULL),
|
||||
bumpAlloc(NULL),
|
||||
|
@ -1598,7 +1597,7 @@ JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
|
|||
AutoLockGC lock(this);
|
||||
gcHelperThread.waitBackgroundSweepOrAllocEnd();
|
||||
#endif
|
||||
gcChunkPool.expire(this, true);
|
||||
gcChunkPool.expireAndFree(this, true);
|
||||
}
|
||||
if (!p)
|
||||
p = OffTheBooks::malloc_(nbytes);
|
||||
|
|
|
@ -140,12 +140,6 @@ struct ThreadData {
|
|||
/* Keeper of the contiguous stack used by all contexts in this thread. */
|
||||
StackSpace stackSpace;
|
||||
|
||||
/*
|
||||
* Flag indicating that we are waiving any soft limits on the GC heap
|
||||
* because we want allocations to be infallible (except when we hit OOM).
|
||||
*/
|
||||
bool waiveGCQuota;
|
||||
|
||||
/* Temporary arena pool used while compiling and decompiling. */
|
||||
static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 1 << 12;
|
||||
LifoAlloc tempLifoAlloc;
|
||||
|
|
|
@ -517,6 +517,22 @@ ChunkPool::expire(JSRuntime *rt, bool releaseAll)
|
|||
return freeList;
|
||||
}
|
||||
|
||||
static void
|
||||
FreeChunkList(Chunk *chunkListHead)
|
||||
{
|
||||
while (Chunk *chunk = chunkListHead) {
|
||||
JS_ASSERT(!chunk->info.numArenasFreeCommitted);
|
||||
chunkListHead = chunk->info.next;
|
||||
FreeChunk(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChunkPool::expireAndFree(JSRuntime *rt, bool releaseAll)
|
||||
{
|
||||
FreeChunkList(expire(rt, releaseAll));
|
||||
}
|
||||
|
||||
JS_FRIEND_API(int64_t)
|
||||
ChunkPool::countCleanDecommittedArenas(JSRuntime *rt)
|
||||
{
|
||||
|
@ -553,16 +569,6 @@ Chunk::release(JSRuntime *rt, Chunk *chunk)
|
|||
FreeChunk(chunk);
|
||||
}
|
||||
|
||||
static void
|
||||
FreeChunkList(Chunk *chunkListHead)
|
||||
{
|
||||
while (Chunk *chunk = chunkListHead) {
|
||||
JS_ASSERT(!chunk->info.numArenasFreeCommitted);
|
||||
chunkListHead = chunk->info.next;
|
||||
FreeChunk(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Chunk::prepareToBeFreed(JSRuntime *rt)
|
||||
{
|
||||
|
@ -1211,7 +1217,7 @@ js_FinishGC(JSRuntime *rt)
|
|||
* Finish the pool after the background thread stops in case it was doing
|
||||
* the background sweeping.
|
||||
*/
|
||||
FreeChunkList(rt->gcChunkPool.expire(rt, true));
|
||||
rt->gcChunkPool.expireAndFree(rt, true);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!rt->gcRootsHash.empty())
|
||||
|
@ -1670,12 +1676,6 @@ RunLastDitchGC(JSContext *cx)
|
|||
#endif
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsGCAllowed(JSContext *cx)
|
||||
{
|
||||
return !JS_THREAD_DATA(cx)->waiveGCQuota;
|
||||
}
|
||||
|
||||
/* static */ void *
|
||||
ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
|
||||
{
|
||||
|
@ -1687,7 +1687,7 @@ ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
|
|||
|
||||
bool runGC = !!rt->gcIsNeeded;
|
||||
for (;;) {
|
||||
if (JS_UNLIKELY(runGC) && IsGCAllowed(cx)) {
|
||||
if (JS_UNLIKELY(runGC)) {
|
||||
RunLastDitchGC(cx);
|
||||
|
||||
/* Report OOM of the GC failed to free enough memory. */
|
||||
|
@ -1708,14 +1708,11 @@ ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
|
|||
return thing;
|
||||
|
||||
/*
|
||||
* We failed to allocate. Run the GC if we can unless we have done it
|
||||
* already. Otherwise report OOM but first schedule a new GC soon.
|
||||
* We failed to allocate. Run the GC if we haven't done it already.
|
||||
* Otherwise report OOM.
|
||||
*/
|
||||
if (runGC || !IsGCAllowed(cx)) {
|
||||
AutoLockGC lock(rt);
|
||||
TriggerGC(rt, gcstats::REFILL);
|
||||
if (runGC)
|
||||
break;
|
||||
}
|
||||
runGC = true;
|
||||
}
|
||||
|
||||
|
@ -3022,12 +3019,10 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
|
|||
js_PurgeThreads_PostGlobalSweep(cx);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) {
|
||||
if (cx->gcBackgroundFree) {
|
||||
JS_ASSERT(cx->gcBackgroundFree == &rt->gcHelperThread);
|
||||
cx->gcBackgroundFree = NULL;
|
||||
rt->gcHelperThread.startBackgroundSweep(gckind == GC_SHRINK);
|
||||
} else {
|
||||
JS_ASSERT(!cx->gcBackgroundFree);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3308,19 +3303,17 @@ void
|
|||
RunDebugGC(JSContext *cx)
|
||||
{
|
||||
#ifdef JS_GC_ZEAL
|
||||
if (IsGCAllowed(cx)) {
|
||||
JSRuntime *rt = cx->runtime;
|
||||
JSRuntime *rt = cx->runtime;
|
||||
|
||||
/*
|
||||
* If rt->gcDebugCompartmentGC is true, only GC the current
|
||||
* compartment. But don't GC the atoms compartment.
|
||||
*/
|
||||
rt->gcTriggerCompartment = rt->gcDebugCompartmentGC ? cx->compartment : NULL;
|
||||
if (rt->gcTriggerCompartment == rt->atomsCompartment)
|
||||
rt->gcTriggerCompartment = NULL;
|
||||
|
||||
RunLastDitchGC(cx);
|
||||
}
|
||||
/*
|
||||
* If rt->gcDebugCompartmentGC is true, only GC the current
|
||||
* compartment. But don't GC the atoms compartment.
|
||||
*/
|
||||
rt->gcTriggerCompartment = rt->gcDebugCompartmentGC ? cx->compartment : NULL;
|
||||
if (rt->gcTriggerCompartment == rt->atomsCompartment)
|
||||
rt->gcTriggerCompartment = NULL;
|
||||
|
||||
RunLastDitchGC(cx);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -808,6 +808,9 @@ class ChunkPool {
|
|||
*/
|
||||
Chunk *expire(JSRuntime *rt, bool releaseAll);
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void expireAndFree(JSRuntime *rt, bool releaseAll);
|
||||
|
||||
/* Must be called either during the GC or with the GC lock taken. */
|
||||
JS_FRIEND_API(int64_t) countCleanDecommittedArenas(JSRuntime *rt);
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче