diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index cbd001dc723b..c05f79fee585 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -55,9 +55,6 @@ class ChunkPool /* Must be called either during the GC or with the GC lock taken. */ inline void put(Chunk *chunk); - /* Must be called with the GC lock taken. */ - void expireAndFree(JSRuntime *rt, bool releaseAll); - class Enum { public: Enum(ChunkPool &pool) : pool(pool), chunkp(&pool.emptyChunkListHead) {} @@ -358,7 +355,7 @@ class GCRuntime * Return the list of chunks that can be released outside the GC lock. * Must be called either during the GC or with the GC lock taken. */ - Chunk *expireChunkPool(bool releaseAll); + Chunk *expireChunkPool(bool shrinkBuffers, bool releaseAll); void expireAndFreeChunkPool(bool releaseAll); void freeChunkList(Chunk *chunkListHead); void prepareToFreeChunk(ChunkInfo &info); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 804b8a168ee8..ff1310e34095 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -239,10 +239,16 @@ static const uint64_t GC_IDLE_FULL_SPAN = 20 * 1000 * 1000; /* Increase the IGC marking slice time if we are in highFrequencyGC mode. */ static const int IGC_MARK_SLICE_MULTIPLIER = 2; -#if defined(ANDROID) || defined(MOZ_B2G) -static const int MAX_EMPTY_CHUNK_COUNT = 2; +#ifdef JSGC_GENERATIONAL +static const unsigned MIN_EMPTY_CHUNK_COUNT = 1; #else -static const int MAX_EMPTY_CHUNK_COUNT = 30; +static const unsigned MIN_EMPTY_CHUNK_COUNT = 0; +#endif + +#if defined(ANDROID) || defined(MOZ_B2G) +static const unsigned MAX_EMPTY_CHUNK_COUNT = 2; +#else +static const unsigned MAX_EMPTY_CHUNK_COUNT = 30; #endif const AllocKind gc::slotsToThingKind[] = { @@ -712,7 +718,7 @@ ChunkPool::Enum::removeAndPopFront() /* Must be called either during the GC or with the GC lock taken. */ Chunk * -GCRuntime::expireChunkPool(bool releaseAll) +GCRuntime::expireChunkPool(bool shrinkBuffers, bool releaseAll) { /* * Return old empty chunks to the system while preserving the order of @@ -721,14 +727,14 @@ GCRuntime::expireChunkPool(bool releaseAll) * and are more likely to reach the max age. */ Chunk *freeList = nullptr; - int freeChunkCount = 0; + unsigned freeChunkCount = 0; for (ChunkPool::Enum e(chunkPool); !e.empty(); ) { Chunk *chunk = e.front(); JS_ASSERT(chunk->unused()); JS_ASSERT(!chunkSet.has(chunk)); - JS_ASSERT(chunk->info.age <= MAX_EMPTY_CHUNK_AGE); - if (releaseAll || chunk->info.age == MAX_EMPTY_CHUNK_AGE || - freeChunkCount++ > MAX_EMPTY_CHUNK_COUNT) + if (releaseAll || freeChunkCount >= MAX_EMPTY_CHUNK_COUNT || + (freeChunkCount >= MIN_EMPTY_CHUNK_COUNT && + (shrinkBuffers || chunk->info.age == MAX_EMPTY_CHUNK_AGE))) { e.removeAndPopFront(); prepareToFreeChunk(chunk->info); @@ -736,10 +742,12 @@ GCRuntime::expireChunkPool(bool releaseAll) freeList = chunk; } else { /* Keep the chunk but increase its age. */ + ++freeChunkCount; ++chunk->info.age; e.popFront(); } } + JS_ASSERT_IF(shrinkBuffers, chunkPool.getEmptyCount() <= MIN_EMPTY_CHUNK_COUNT); JS_ASSERT_IF(releaseAll, chunkPool.getEmptyCount() == 0); return freeList; } @@ -757,7 +765,7 @@ GCRuntime::freeChunkList(Chunk *chunkListHead) void GCRuntime::expireAndFreeChunkPool(bool releaseAll) { - freeChunkList(expireChunkPool(releaseAll)); + freeChunkList(expireChunkPool(true, releaseAll)); } /* static */ Chunk * @@ -1056,7 +1064,7 @@ GCRuntime::wantBackgroundAllocation() const * of them. */ return helperState.canBackgroundAllocate() && - chunkPool.getEmptyCount() == 0 && + chunkPool.getEmptyCount() < MIN_EMPTY_CHUNK_COUNT && chunkSet.count() >= 4; } @@ -2609,7 +2617,7 @@ GCRuntime::expireChunksAndArenas(bool shouldShrink) rt->threadPool.pruneChunkCache(); #endif - if (Chunk *toFree = expireChunkPool(shouldShrink)) { + if (Chunk *toFree = expireChunkPool(shouldShrink, false)) { AutoUnlockGC unlock(rt); freeChunkList(toFree); }