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