diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp index 890c957e913c..0942106c1686 100644 --- a/js/src/gc/GC.cpp +++ b/js/src/gc/GC.cpp @@ -908,10 +908,6 @@ void Chunk::recycleArena(Arena* arena, SortedArenaList& dest, } void Chunk::releaseArena(JSRuntime* rt, Arena* arena, const AutoLockGC& lock) { - MOZ_ASSERT(arena->allocated()); - MOZ_ASSERT(!arena->onDelayedMarkingList()); - - arena->release(lock); addArenaToFreeList(rt, arena); updateChunkListAfterFree(rt, lock); } @@ -973,10 +969,14 @@ void Chunk::updateChunkListAfterFree(JSRuntime* rt, const AutoLockGC& lock) { } void GCRuntime::releaseArena(Arena* arena, const AutoLockGC& lock) { + MOZ_ASSERT(arena->allocated()); + MOZ_ASSERT(!arena->onDelayedMarkingList()); + arena->zone->zoneSize.removeGCArena(); if (arena->zone->wasGCStarted()) { stats().recordFreedArena(); } + arena->release(lock); arena->chunk()->releaseArena(rt, arena, lock); } @@ -3079,36 +3079,15 @@ void GCRuntime::updateRuntimePointersToRelocatedCells(AutoGCSession& session) { callWeakPointerZonesCallbacks(); } -void GCRuntime::protectAndHoldArenas(Arena* arenaList) { - for (Arena* arena = arenaList; arena;) { - MOZ_ASSERT(arena->allocated()); - Arena* next = arena->next; - if (!next) { - // Prepend to hold list before we protect the memory. - arena->next = relocatedArenasToRelease; - relocatedArenasToRelease = arenaList; - } - ProtectPages(arena, ArenaSize); - arena = next; - } -} - -void GCRuntime::unprotectHeldRelocatedArenas() { - for (Arena* arena = relocatedArenasToRelease; arena; arena = arena->next) { - UnprotectPages(arena, ArenaSize); - MOZ_ASSERT(arena->allocated()); - } -} - -void GCRuntime::releaseRelocatedArenas(Arena* arenaList) { +void GCRuntime::clearRelocatedArenas(Arena* arenaList, JS::GCReason reason) { AutoLockGC lock(rt); - releaseRelocatedArenasWithoutUnlocking(arenaList, lock); + clearRelocatedArenasWithoutUnlocking(arenaList, reason, lock); } -void GCRuntime::releaseRelocatedArenasWithoutUnlocking(Arena* arenaList, - const AutoLockGC& lock) { - // Release the relocated arenas, now containing only forwarding pointers - unsigned count = 0; +void GCRuntime::clearRelocatedArenasWithoutUnlocking(Arena* arenaList, + JS::GCReason reason, + const AutoLockGC& lock) { + // Clear the relocated arenas, now containing only forwarding pointers while (arenaList) { Arena* arena = arenaList; arenaList = arenaList->next; @@ -3123,8 +3102,55 @@ void GCRuntime::releaseRelocatedArenasWithoutUnlocking(Arena* arenaList, JS_MOVED_TENURED_PATTERN, arena->getThingsSpan(), MemCheckKind::MakeNoAccess); - releaseArena(arena, lock); - ++count; + arena->zone->zoneSize.removeGCArena(); + + // Don't count arenas as freed if we purposely moved everything to new + // arenas. + if (!ShouldRelocateAllArenas(reason) && arena->zone->wasGCStarted()) { + stats().recordFreedArena(); + } + + // Release the arena but don't return it to the chunk yet. + arena->release(lock); + } +} + +void GCRuntime::protectAndHoldArenas(Arena* arenaList) { + for (Arena* arena = arenaList; arena;) { + MOZ_ASSERT(!arena->allocated()); + Arena* next = arena->next; + if (!next) { + // Prepend to hold list before we protect the memory. + arena->next = relocatedArenasToRelease; + relocatedArenasToRelease = arenaList; + } + ProtectPages(arena, ArenaSize); + arena = next; + } +} + +void GCRuntime::unprotectHeldRelocatedArenas() { + for (Arena* arena = relocatedArenasToRelease; arena; arena = arena->next) { + UnprotectPages(arena, ArenaSize); + MOZ_ASSERT(!arena->allocated()); + } +} + +void GCRuntime::releaseRelocatedArenas(Arena* arenaList) { + AutoLockGC lock(rt); + releaseRelocatedArenasWithoutUnlocking(arenaList, lock); +} + +void GCRuntime::releaseRelocatedArenasWithoutUnlocking(Arena* arenaList, + const AutoLockGC& lock) { + // Release relocated arenas previously cleared with clearRelocatedArenas(). + while (arenaList) { + Arena* arena = arenaList; + arenaList = arenaList->next; + + // We already updated the memory accounting so just call + // Chunk::releaseArena. + arena->chunk()->releaseArena(rt, arena, lock); } } @@ -6862,6 +6888,8 @@ IncrementalProgress GCRuntime::compactPhase(JS::GCReason reason, } while (!relocatedZones.isEmpty()); } + clearRelocatedArenas(relocatedArenas, reason); + if (ShouldProtectRelocatedArenas(reason)) { protectAndHoldArenas(relocatedArenas); } else { diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 2e40167c146d..6b7207af04be 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -690,6 +690,10 @@ class GCRuntime { void updateRuntimePointersToRelocatedCells(AutoGCSession& session); void protectAndHoldArenas(Arena* arenaList); void unprotectHeldRelocatedArenas(); + void clearRelocatedArenas(Arena* arenaList, JS::GCReason reason); + void clearRelocatedArenasWithoutUnlocking(Arena* arenaList, + JS::GCReason reason, + const AutoLockGC& lock); void releaseRelocatedArenas(Arena* arenaList); void releaseRelocatedArenasWithoutUnlocking(Arena* arenaList, const AutoLockGC& lock);