[heap] Abstract away remaining SemiSpaceNewSpace methods

The abstractions in this CL include:
1) Using EvacuatePrologue to handle age mark updating in
SemiSpaceNewSpace.
2) Using IsPromotionCandidate to check if a page contains
the current age mark.
3) EnsureCurrentCapacity instead of Rebalance.
4) Delegate page promotions in mark-compact.cc to the
NewSpace implementation.

Bug: v8:12612
Change-Id: Ied83261d661a8e61a11bf33b1d7a2103ac99a853
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3644966
Commit-Queue: Omer Katz <omerkatz@chromium.org>
Reviewed-by: Dominik Inführ <dinfuehr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80846}
This commit is contained in:
Omer Katz 2022-05-31 11:56:47 +02:00 committed by V8 LUCI CQ
parent eadd2c5a05
commit 5411e8508b
7 changed files with 76 additions and 53 deletions

View File

@ -5817,9 +5817,9 @@ void Heap::SetUpSpaces(LinearAllocationArea* new_allocation_info,
DCHECK_NOT_NULL(read_only_space_);
const bool has_young_gen = !FLAG_single_generation && !IsShared();
if (has_young_gen) {
space_[NEW_SPACE] = new_space_ = new SemiSpaceNewSpace(
this, memory_allocator_->data_page_allocator(), initial_semispace_size_,
max_semi_space_size_, new_allocation_info);
space_[NEW_SPACE] = new_space_ =
new SemiSpaceNewSpace(this, initial_semispace_size_,
max_semi_space_size_, new_allocation_info);
space_[NEW_LO_SPACE] = new_lo_space_ =
new NewLargeObjectSpace(this, NewSpaceCapacity());
}

View File

@ -1957,17 +1957,10 @@ class EvacuateNewSpacePageVisitor final : public HeapObjectVisitor {
static void Move(Page* page) {
switch (mode) {
case NEW_TO_NEW:
SemiSpaceNewSpace::From(page->heap()->new_space())
->MovePageFromSpaceToSpace(page);
page->SetFlag(Page::PAGE_NEW_NEW_PROMOTION);
page->heap()->new_space()->PromotePageInNewSpace(page);
break;
case NEW_TO_OLD: {
SemiSpaceNewSpace::From(page->heap()->new_space())
->from_space()
.RemovePage(page);
Page* new_page = Page::ConvertNewToOld(page);
DCHECK(!new_page->InYoungGeneration());
new_page->SetFlag(Page::PAGE_NEW_OLD_PROMOTION);
page->heap()->new_space()->PromotePageToOldSpace(page);
break;
}
}
@ -3694,8 +3687,7 @@ void MarkCompactCollector::EvacuateEpilogue() {
// New space.
if (heap()->new_space()) {
SemiSpaceNewSpace::From(heap()->new_space())
->set_age_mark(heap()->new_space()->top());
heap()->new_space()->EvacuateEpilogue();
DCHECK_EQ(0, heap()->new_space()->Size());
}
@ -3862,15 +3854,14 @@ void Evacuator::EvacuatePage(MemoryChunk* chunk) {
if (FLAG_trace_evacuation) {
PrintIsolate(heap()->isolate(),
"evacuation[%p]: page=%p new_space=%d "
"page_evacuation=%d executable=%d contains_age_mark=%d "
"page_evacuation=%d executable=%d can_promote=%d "
"live_bytes=%" V8PRIdPTR " time=%f success=%d\n",
static_cast<void*>(this), static_cast<void*>(chunk),
chunk->InNewSpace(),
chunk->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION) ||
chunk->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION),
chunk->IsFlagSet(MemoryChunk::IS_EXECUTABLE),
chunk->Contains(
SemiSpaceNewSpace::From(heap()->new_space())->age_mark()),
heap()->new_space()->IsPromotionCandidate(chunk),
saved_live_bytes, evacuation_time,
chunk->IsFlagSet(Page::COMPACTION_WAS_ABORTED));
}
@ -4086,12 +4077,10 @@ bool ShouldMovePage(Page* p, intptr_t live_bytes,
AlwaysPromoteYoung always_promote_young) {
Heap* heap = p->heap();
const bool reduce_memory = heap->ShouldReduceMemory();
const Address age_mark =
SemiSpaceNewSpace::From(heap->new_space())->age_mark();
return !reduce_memory && !p->NeverEvacuate() &&
(live_bytes > Evacuator::NewSpacePageEvacuationThreshold()) &&
(always_promote_young == AlwaysPromoteYoung::kYes ||
!p->Contains(age_mark)) &&
heap->new_space()->IsPromotionCandidate(p)) &&
heap->CanExpandOldGeneration(live_bytes);
}
@ -4327,7 +4316,7 @@ void MarkCompactCollector::Evacuate() {
if (heap()->new_space()) {
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_REBALANCE);
if (!SemiSpaceNewSpace::From(heap()->new_space())->Rebalance()) {
if (!heap()->new_space()->EnsureCurrentCapacity()) {
heap()->FatalProcessOutOfMemory("NewSpace::Rebalance");
}
}
@ -5743,8 +5732,7 @@ void MinorMarkCompactCollector::EvacuatePrologue() {
}
void MinorMarkCompactCollector::EvacuateEpilogue() {
SemiSpaceNewSpace::From(heap()->new_space())
->set_age_mark(heap()->new_space()->top());
heap()->new_space()->EvacuateEpilogue();
}
int MinorMarkCompactCollector::CollectToSpaceUpdatingItems(
@ -6128,7 +6116,7 @@ void MinorMarkCompactCollector::Evacuate() {
{
TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_EVACUATE_REBALANCE);
if (!SemiSpaceNewSpace::From(heap()->new_space())->Rebalance()) {
if (!heap()->new_space()->EnsureCurrentCapacity()) {
heap()->FatalProcessOutOfMemory("NewSpace::Rebalance");
}
}

View File

@ -568,11 +568,18 @@ void NewSpace::VerifyImpl(Isolate* isolate, const Page* current_page,
}
#endif
void NewSpace::PromotePageToOldSpace(Page* page) {
DCHECK(page->InYoungGeneration());
RemovePage(page);
Page* new_page = Page::ConvertNewToOld(page);
DCHECK(!new_page->InYoungGeneration());
new_page->SetFlag(Page::PAGE_NEW_OLD_PROMOTION);
}
// -----------------------------------------------------------------------------
// SemiSpaceNewSpace implementation
SemiSpaceNewSpace::SemiSpaceNewSpace(Heap* heap,
v8::PageAllocator* page_allocator,
size_t initial_semispace_capacity,
size_t max_semispace_capacity,
LinearAllocationArea* allocation_info)
@ -641,7 +648,7 @@ size_t SemiSpaceNewSpace::CommittedPhysicalMemory() const {
return size;
}
bool SemiSpaceNewSpace::Rebalance() {
bool SemiSpaceNewSpace::EnsureCurrentCapacity() {
// Order here is important to make use of the page pool.
return to_space_.EnsureCurrentCapacity() &&
from_space_.EnsureCurrentCapacity();
@ -831,8 +838,11 @@ void SemiSpaceNewSpace::EvacuatePrologue() {
// live objects.
SemiSpace::Swap(&from_space_, &to_space_);
ResetLinearAllocationArea();
DCHECK_EQ(0u, Size());
}
void SemiSpaceNewSpace::EvacuateEpilogue() { set_age_mark(top()); }
void SemiSpaceNewSpace::ZapUnusedMemory() {
if (!IsFromSpaceCommitted()) return;
for (Page* page : PageRange(from_space().first_page(), nullptr)) {
@ -842,5 +852,22 @@ void SemiSpaceNewSpace::ZapUnusedMemory() {
}
}
void SemiSpaceNewSpace::RemovePage(Page* page) {
DCHECK(!page->IsToPage());
DCHECK(page->IsFromPage());
from_space().RemovePage(page);
}
void SemiSpaceNewSpace::PromotePageInNewSpace(Page* page) {
DCHECK(page->IsFromPage());
from_space_.RemovePage(page);
to_space_.PrependPage(page);
page->SetFlag(Page::PAGE_NEW_NEW_PROMOTION);
}
bool SemiSpaceNewSpace::IsPromotionCandidate(const MemoryChunk* page) const {
return !page->Contains(age_mark());
}
} // namespace internal
} // namespace v8

View File

@ -276,6 +276,9 @@ class NewSpace : NON_EXPORTED_BASE(public SpaceWithLinearArea) {
return result;
}
void PromotePageToOldSpace(Page* page);
virtual void PromotePageInNewSpace(Page* page) = 0;
virtual size_t Capacity() const = 0;
virtual size_t TotalCapacity() const = 0;
virtual size_t MaximumCapacity() const = 0;
@ -311,9 +314,14 @@ class NewSpace : NON_EXPORTED_BASE(public SpaceWithLinearArea) {
virtual void Prologue() {}
virtual void EvacuatePrologue() = 0;
virtual void EvacuateEpilogue() = 0;
virtual void ZapUnusedMemory() {}
virtual bool IsPromotionCandidate(const MemoryChunk* page) const = 0;
virtual bool EnsureCurrentCapacity() = 0;
protected:
static const int kAllocationBufferParkingThreshold = 4 * KB;
@ -323,6 +331,8 @@ class NewSpace : NON_EXPORTED_BASE(public SpaceWithLinearArea) {
ParkedAllocationBuffersVector parked_allocation_buffers_;
virtual void RemovePage(Page* page) = 0;
bool SupportsAllocationObserver() const final { return true; }
};
@ -338,8 +348,7 @@ class V8_EXPORT_PRIVATE SemiSpaceNewSpace final : public NewSpace {
return static_cast<SemiSpaceNewSpace*>(space);
}
SemiSpaceNewSpace(Heap* heap, v8::PageAllocator* page_allocator,
size_t initial_semispace_capacity,
SemiSpaceNewSpace(Heap* heap, size_t initial_semispace_capacity,
size_t max_semispace_capacity,
LinearAllocationArea* allocation_info);
@ -407,13 +416,9 @@ class V8_EXPORT_PRIVATE SemiSpaceNewSpace final : public NewSpace {
size_t AllocatedSinceLastGC() const final;
void MovePageFromSpaceToSpace(Page* page) {
DCHECK(page->IsFromPage());
from_space_.RemovePage(page);
to_space_.PrependPage(page);
}
void PromotePageInNewSpace(Page* page) final;
bool Rebalance();
bool EnsureCurrentCapacity() final;
// Return the maximum capacity of a semispace.
size_t MaximumCapacity() const final {
@ -468,10 +473,6 @@ class V8_EXPORT_PRIVATE SemiSpaceNewSpace final : public NewSpace {
void Print() override { to_space_.Print(); }
#endif
bool IsFromSpaceCommitted() const { return from_space_.IsCommitted(); }
SemiSpace* active_space() { return &to_space_; }
Page* first_page() final { return to_space_.first_page(); }
Page* last_page() final { return to_space_.last_page(); }
@ -496,16 +497,27 @@ class V8_EXPORT_PRIVATE SemiSpaceNewSpace final : public NewSpace {
void Prologue() final;
void EvacuatePrologue() final;
void EvacuateEpilogue() final;
void ZapUnusedMemory() final;
bool IsPromotionCandidate(const MemoryChunk* page) const final;
private:
bool IsFromSpaceCommitted() const { return from_space_.IsCommitted(); }
SemiSpace* active_space() { return &to_space_; }
// Reset the allocation pointer to the beginning of the active semispace.
void ResetLinearAllocationArea();
// Update linear allocation area to match the current to-space page.
void UpdateLinearAllocationArea(Address known_top = 0);
// Removes a page from the space. Assumes the page is in the `from_space` semi
// space.
void RemovePage(Page* page) final;
// The semispaces.
SemiSpace to_space_;
SemiSpace from_space_;

View File

@ -33,26 +33,24 @@ void PromoteYoungGenerationGC::EvacuateYoungGeneration() {
DCHECK(heap_->CanPromoteYoungAndExpandOldGeneration(0));
}
SemiSpaceNewSpace* semi_space_new_space =
SemiSpaceNewSpace::From(heap_->new_space());
NewSpace* new_space = heap_->new_space();
// Move pages from new->old generation.
PageRange range(semi_space_new_space->first_allocatable_address(),
semi_space_new_space->top());
PageRange range(new_space->first_allocatable_address(), new_space->top());
for (auto it = range.begin(); it != range.end();) {
Page* p = (*++it)->prev_page();
semi_space_new_space->from_space().RemovePage(p);
Page::ConvertNewToOld(p);
new_space->PromotePageToOldSpace(p);
if (heap_->incremental_marking()->IsMarking())
heap_->mark_compact_collector()->RecordLiveSlotsOnPage(p);
p->ClearFlag(Page::PAGE_NEW_OLD_PROMOTION);
}
// Reset new space.
semi_space_new_space->EvacuatePrologue();
if (!semi_space_new_space->Rebalance()) {
V8::FatalProcessOutOfMemory(heap_->isolate(), "NewSpace::Rebalance",
V8::kHeapOOM);
new_space->EvacuatePrologue();
if (!new_space->EnsureCurrentCapacity()) {
V8::FatalProcessOutOfMemory(
heap_->isolate(), "NewSpace::EnsureCurrentCapacity", V8::kHeapOOM);
}
semi_space_new_space->set_age_mark(semi_space_new_space->top());
new_space->EvacuateEpilogue();
for (auto it = heap_->new_lo_space()->begin();
it != heap_->new_lo_space()->end();) {

View File

@ -78,8 +78,7 @@ UNINITIALIZED_TEST(PagePromotion_NewToOld) {
CHECK_GT(handles.size(), 0u);
Page* const to_be_promoted_page = FindLastPageInNewSpace(handles);
CHECK_NOT_NULL(to_be_promoted_page);
CHECK(!to_be_promoted_page->Contains(
SemiSpaceNewSpace::From(heap->new_space())->age_mark()));
CHECK(heap->new_space()->IsPromotionCandidate(to_be_promoted_page));
// To perform a sanity check on live bytes we need to mark the heap.
heap::SimulateIncrementalMarking(heap, true);
// Sanity check that the page meets the requirements for promotion.

View File

@ -299,8 +299,7 @@ TEST(SemiSpaceNewSpace) {
std::unique_ptr<SemiSpaceNewSpace> new_space =
std::make_unique<SemiSpaceNewSpace>(
heap, memory_allocator->data_page_allocator(),
CcTest::heap()->InitialSemiSpaceSize(),
heap, CcTest::heap()->InitialSemiSpaceSize(),
CcTest::heap()->InitialSemiSpaceSize(), &allocation_info);
CHECK(new_space->MaximumCapacity());