Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions Source/JavaScriptCore/heap/MarkedBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ MarkedBlock::Handle* MarkedBlock::tryCreate(JSC::Heap& heap, AlignedMemoryAlloca
}

MarkedBlock::Handle::Handle(JSC::Heap& heap, AlignedMemoryAllocator* alignedMemoryAllocator, void* blockSpace)
: m_alignedMemoryAllocator(alignedMemoryAllocator)
: m_markingVersionAtLastSweep(heap.objectSpace().markingVersion())
, m_alignedMemoryAllocator(alignedMemoryAllocator)
, m_weakSet(heap.vm())
, m_block(new (NotNull, blockSpace) MarkedBlock(heap.vm(), *this))
{
Expand Down Expand Up @@ -491,7 +492,7 @@ Subspace* MarkedBlock::Handle::subspace() const
return directory()->subspace();
}

void MarkedBlock::Handle::decommitUnusedPages()
void MarkedBlock::Handle::decommitUnusedPages(bool isFirstSweepSinceFullCollection)
{
#if OS(WINDOWS)
// OSAllocator::decommit makes the pages inaccessible there; this scheme relies on decommitted pages reading as zero.
Expand All @@ -510,9 +511,12 @@ void MarkedBlock::Handle::decommitUnusedPages()
size_t pageSize = WTF::pageSize();
if (pageSize >= blockSize || blockSize / pageSize > 16)
return;
// Only after a full collection (the blocks an eden collection sweeps are the young ones, refilled straight away, so
// decommitting there mostly buys page faults) and only for blocks that are not mostly full anyway.
if (heap()->lastCollectionScope() != CollectionScope::Full && !Options::decommitUnusedMarkedBlockPagesAfterEdenCollections())
// Only for what a full collection left behind (the blocks an eden collection adds to the unswept set are the young
// ones, refilled straight away, so decommitting there mostly buys page faults) and only for blocks that are not
// mostly full anyway. The test is whether this sweep is the block's first since the last full collection began, not
// which collection finished last: an eden collection can run between the end of a full one and the incremental
// sweeper's timer slice that reaches the block, and the block is no younger for it.
if (!isFirstSweepSinceFullCollection && !Options::decommitUnusedMarkedBlockPagesAfterEdenCollections())
return;
m_directory->assertIsMutatorOrMutatorIsStopped();
if (m_directory->isMarkingRetired(this))
Expand Down Expand Up @@ -634,6 +638,12 @@ void MarkedBlock::Handle::sweep(FreeList* freeList)

SweepMode sweepMode = freeList ? SweepToFreeList : SweepOnly;
bool needsDestruction = m_attributes.destruction != DoesNotNeedDestruction && m_directory->isDestructible(this);
// A sweep while a full collection is marking still goes by the previous collection's marks (they are stale, the
// block is treated as fully live or newly allocated): it is not that collection's first sweep, and must not count as it.
bool isMarking = space()->isMarking();
bool isFirstSweepSinceFullCollection = !isMarking && m_markingVersionAtLastSweep != space()->markingVersion();
if (!isMarking)
m_markingVersionAtLastSweep = space()->markingVersion();
Comment thread
claude[bot] marked this conversation as resolved.
Outdated

m_weakSet.sweep();

Expand All @@ -642,7 +652,7 @@ void MarkedBlock::Handle::sweep(FreeList* freeList)

if (sweepMode == SweepOnly && !needsDestruction) {
if (!isEmpty())
decommitUnusedPages();
decommitUnusedPages(isFirstSweepSinceFullCollection);
Locker locker(m_directory->bitvectorLock());
m_directory->setIsUnswept(this, false);
return;
Expand Down Expand Up @@ -673,7 +683,7 @@ void MarkedBlock::Handle::sweep(FreeList* freeList)
if (needsDestruction) {
subspace()->finishSweep(*this, freeList);
if (sweepMode == SweepOnly && !isEmpty())
decommitUnusedPages();
decommitUnusedPages(isFirstSweepSinceFullCollection);
return;
}

Expand Down
3 changes: 2 additions & 1 deletion Source/JavaScriptCore/heap/MarkedBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ class MarkedBlock {
inline void shrink();
// Return interior OS pages that hold no live cell to the OS (after a sweep-only sweep); re-commit them
// before the block is handed to an allocator or freed. No-op when an OS page is not smaller than a block.
void decommitUnusedPages();
void decommitUnusedPages(bool isFirstSweepSinceFullCollection);
void recommitPages();
unsigned numberOfDecommittedPages() const { return std::popcount(m_decommittedPages); }

Expand Down Expand Up @@ -254,6 +254,7 @@ class MarkedBlock {
bool m_isFreeListed { false };
uint16_t m_decommittedPages { 0 }; // bit i set: OS page i of the block is decommitted
uint16_t m_zeroPagesDuringSweep { 0 }; // The pages that were decommitted, and so all zero, when the sweep in progress began.
HeapVersion m_markingVersionAtLastSweep; // A full collection is what moves MarkedSpace::markingVersion() on.
unsigned m_index { std::numeric_limits<unsigned>::max() };

AlignedMemoryAllocator* m_alignedMemoryAllocator { nullptr };
Expand Down
Loading