[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:
parent
eadd2c5a05
commit
5411e8508b
@ -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());
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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_;
|
||||
|
@ -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();) {
|
||||
|
@ -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.
|
||||
|
@ -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());
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user