Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(398)

Unified Diff: src/heap/mark-compact.cc

Issue 2855143003: [heap] Minor MC: Implement page moving (Closed)
Patch Set: Disable flag Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/heap/mark-compact.h ('k') | src/heap/spaces.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/heap/mark-compact.cc
diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc
index ab6907ecc674a40c653c93741676b004e7157ff6..a3aec5cabcd1eab36d06e11e0e266fb433cce0c2 100644
--- a/src/heap/mark-compact.cc
+++ b/src/heap/mark-compact.cc
@@ -447,6 +447,8 @@ void MarkCompactCollector::CollectGarbage() {
// update the state as they proceed.
DCHECK(state_ == PREPARE_GC);
+ heap()->minor_mark_compact_collector()->CleanupSweepToIteratePages();
+
MarkLiveObjects();
DCHECK(heap_->incremental_marking()->IsStopped());
@@ -1458,6 +1460,16 @@ void MarkCompactCollector::PrepareForCodeFlushing() {
ProcessMarkingDeque();
}
+void MinorMarkCompactCollector::CleanupSweepToIteratePages() {
+ for (Page* p : sweep_to_iterate_pages_) {
+ if (p->IsFlagSet(Page::SWEEP_TO_ITERATE)) {
+ p->ClearFlag(Page::SWEEP_TO_ITERATE);
+ marking_state(p).ClearLiveness();
+ }
+ }
+ sweep_to_iterate_pages_.clear();
+}
+
class MinorMarkCompactCollector::RootMarkingVisitor : public RootVisitor {
public:
explicit RootMarkingVisitor(MinorMarkCompactCollector* collector)
@@ -2588,6 +2600,8 @@ void MinorMarkCompactCollector::EmptyMarkingDeque() {
void MinorMarkCompactCollector::CollectGarbage() {
heap()->mark_compact_collector()->sweeper().EnsureNewSpaceCompleted();
+ CleanupSweepToIteratePages();
+
MarkLiveObjects();
ClearNonLiveReferences();
#ifdef VERIFY_HEAP
@@ -2611,6 +2625,7 @@ void MinorMarkCompactCollector::CollectGarbage() {
TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_CLEAR_LIVENESS);
for (Page* p : PageRange(heap()->new_space()->FromSpaceStart(),
heap()->new_space()->FromSpaceEnd())) {
+ DCHECK(!p->IsFlagSet(Page::SWEEP_TO_ITERATE));
marking_state(p).ClearLiveness();
}
}
@@ -2618,6 +2633,56 @@ void MinorMarkCompactCollector::CollectGarbage() {
heap()->account_external_memory_concurrently_freed();
}
+void MinorMarkCompactCollector::MakeIterable(
+ Page* p, MarkingTreatmentMode marking_mode,
+ FreeSpaceTreatmentMode free_space_mode) {
+ // We have to clear the full collectors markbits for the areas that we
+ // remove here.
+ MarkCompactCollector* full_collector = heap()->mark_compact_collector();
+ Address free_start = p->area_start();
+ DCHECK(reinterpret_cast<intptr_t>(free_start) % (32 * kPointerSize) == 0);
+ LiveObjectIterator<kBlackObjects> it(p, marking_state(p));
+ HeapObject* object = nullptr;
+
+ while ((object = it.Next()) != nullptr) {
+ DCHECK(ObjectMarking::IsBlack(object, marking_state(object)));
+ Address free_end = object->address();
+ if (free_end != free_start) {
+ CHECK_GT(free_end, free_start);
+ size_t size = static_cast<size_t>(free_end - free_start);
+ if (free_space_mode == ZAP_FREE_SPACE) {
+ memset(free_start, 0xcc, size);
+ full_collector->marking_state(p).bitmap()->ClearRange(
+ p->AddressToMarkbitIndex(free_start),
+ p->AddressToMarkbitIndex(free_end));
+ }
+ p->heap()->CreateFillerObjectAt(free_start, static_cast<int>(size),
+ ClearRecordedSlots::kNo);
+ }
+ Map* map = object->synchronized_map();
+ int size = object->SizeFromMap(map);
+ free_start = free_end + size;
+ }
+
+ if (free_start != p->area_end()) {
+ CHECK_GT(p->area_end(), free_start);
+ size_t size = static_cast<size_t>(p->area_end() - free_start);
+ if (free_space_mode == ZAP_FREE_SPACE) {
+ memset(free_start, 0xcc, size);
+ full_collector->marking_state(p).bitmap()->ClearRange(
+ p->AddressToMarkbitIndex(free_start),
+ p->AddressToMarkbitIndex(p->area_end()));
+ }
+ p->heap()->CreateFillerObjectAt(free_start, static_cast<int>(size),
+ ClearRecordedSlots::kNo);
+ }
+
+ if (marking_mode == MarkingTreatmentMode::CLEAR) {
+ marking_state(p).ClearLiveness();
+ p->ClearFlag(Page::SWEEP_TO_ITERATE);
+ }
+}
+
void MinorMarkCompactCollector::ClearNonLiveReferences() {
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR);
@@ -2680,7 +2745,15 @@ void MinorMarkCompactCollector::Evacuate() {
{
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_CLEAN_UP);
- // TODO(mlippautz): Implement page promotion.
+ for (Page* p : new_space_evacuation_pages_) {
+ if (p->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION) ||
+ p->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION)) {
+ p->ClearFlag(Page::PAGE_NEW_NEW_PROMOTION);
+ p->ClearFlag(Page::PAGE_NEW_OLD_PROMOTION);
+ p->SetFlag(Page::SWEEP_TO_ITERATE);
+ sweep_to_iterate_pages_.push_back(p);
+ }
+ }
new_space_evacuation_pages_.Rewind(0);
}
@@ -3571,12 +3644,30 @@ bool YoungGenerationEvacuator::RawEvacuatePage(Page* page,
page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
break;
case kPageNewToOld:
- // TODO(mlippautz): Implement page promotion.
- UNREACHABLE();
+ success = object_visitor.VisitBlackObjects(
+ page, state, &new_to_old_page_visitor_,
+ LiveObjectVisitor::kKeepMarking);
+ DCHECK(success);
+ new_to_old_page_visitor_.account_moved_bytes(state.live_bytes());
+ // TODO(mlippautz): If cleaning array buffers is too slow here we can
+ // delay it until the next GC.
+ ArrayBufferTracker::FreeDead(page, state);
+ if (heap()->ShouldZapGarbage())
+ collector_->MakeIterable(page, MarkingTreatmentMode::KEEP,
+ ZAP_FREE_SPACE);
break;
case kPageNewToNew:
- // TODO(mlippautz): Implement page promotion.
- UNREACHABLE();
+ success = object_visitor.VisitBlackObjects(
+ page, state, &new_to_new_page_visitor_,
+ LiveObjectVisitor::kKeepMarking);
+ DCHECK(success);
+ new_to_new_page_visitor_.account_moved_bytes(state.live_bytes());
+ // TODO(mlippautz): If cleaning array buffers is too slow here we can
+ // delay it until the next GC.
+ ArrayBufferTracker::FreeDead(page, state);
+ if (heap()->ShouldZapGarbage())
+ collector_->MakeIterable(page, MarkingTreatmentMode::KEEP,
+ ZAP_FREE_SPACE);
break;
case kObjectsOldToOld:
UNREACHABLE();
@@ -3689,6 +3780,14 @@ void MarkCompactCollectorBase::CreateAndExecuteEvacuationTasks(
}
}
+bool MarkCompactCollectorBase::ShouldMovePage(Page* p, intptr_t live_bytes) {
+ const bool reduce_memory = heap()->ShouldReduceMemory();
+ const Address age_mark = heap()->new_space()->age_mark();
+ return !reduce_memory && !p->NeverEvacuate() &&
+ (live_bytes > Evacuator::PageEvacuationThreshold()) &&
+ !p->Contains(age_mark) && heap()->CanExpandOldGeneration(live_bytes);
+}
+
void MarkCompactCollector::EvacuatePagesInParallel() {
PageParallelJob<EvacuationJobTraits> job(
heap_, heap_->isolate()->cancelable_task_manager(),
@@ -3701,22 +3800,16 @@ void MarkCompactCollector::EvacuatePagesInParallel() {
job.AddPage(page, {&abandoned_pages, marking_state(page)});
}
- const bool reduce_memory = heap()->ShouldReduceMemory();
- const Address age_mark = heap()->new_space()->age_mark();
for (Page* page : new_space_evacuation_pages_) {
intptr_t live_bytes_on_page = MarkingState::Internal(page).live_bytes();
live_bytes += live_bytes_on_page;
- if (!reduce_memory && !page->NeverEvacuate() &&
- (live_bytes_on_page > Evacuator::PageEvacuationThreshold()) &&
- !page->Contains(age_mark) &&
- heap()->CanExpandOldGeneration(live_bytes_on_page)) {
+ if (ShouldMovePage(page, live_bytes_on_page)) {
if (page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK)) {
EvacuateNewSpacePageVisitor<NEW_TO_OLD>::Move(page);
} else {
EvacuateNewSpacePageVisitor<NEW_TO_NEW>::Move(page);
}
}
-
job.AddPage(page, {&abandoned_pages, marking_state(page)});
}
DCHECK_GE(job.NumberOfPages(), 1);
@@ -3736,7 +3829,13 @@ void MinorMarkCompactCollector::EvacuatePagesInParallel() {
for (Page* page : new_space_evacuation_pages_) {
intptr_t live_bytes_on_page = marking_state(page).live_bytes();
live_bytes += live_bytes_on_page;
- // TODO(mlippautz): Implement page promotion.
+ if (ShouldMovePage(page, live_bytes_on_page)) {
+ if (page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK)) {
+ EvacuateNewSpacePageVisitor<NEW_TO_OLD>::Move(page);
+ } else {
+ EvacuateNewSpacePageVisitor<NEW_TO_NEW>::Move(page);
+ }
+ }
job.AddPage(page, {&abandoned_pages, marking_state(page)});
}
DCHECK_GE(job.NumberOfPages(), 1);
@@ -4060,12 +4159,12 @@ template <RememberedSetType type>
class PointerUpdateJobTraits {
public:
typedef int PerPageData; // Per page data is not used in this job.
- typedef int PerTaskData; // Per task data is not used in this job.
+ typedef const MarkCompactCollectorBase* PerTaskData;
- static bool ProcessPageInParallel(Heap* heap, PerTaskData, MemoryChunk* chunk,
- PerPageData) {
- UpdateUntypedPointers(heap, chunk);
- UpdateTypedPointers(heap, chunk);
+ static bool ProcessPageInParallel(Heap* heap, PerTaskData task_data,
+ MemoryChunk* chunk, PerPageData) {
+ UpdateUntypedPointers(heap, chunk, task_data);
+ UpdateTypedPointers(heap, chunk, task_data);
return true;
}
static const bool NeedSequentialFinalization = false;
@@ -4073,12 +4172,14 @@ class PointerUpdateJobTraits {
}
private:
- static void UpdateUntypedPointers(Heap* heap, MemoryChunk* chunk) {
+ static void UpdateUntypedPointers(Heap* heap, MemoryChunk* chunk,
+ const MarkCompactCollectorBase* collector) {
base::LockGuard<base::RecursiveMutex> guard(chunk->mutex());
if (type == OLD_TO_NEW) {
- RememberedSet<OLD_TO_NEW>::Iterate(chunk, [heap](Address slot) {
- return CheckAndUpdateOldToNewSlot(heap, slot);
- });
+ RememberedSet<OLD_TO_NEW>::Iterate(
+ chunk, [heap, collector](Address slot) {
+ return CheckAndUpdateOldToNewSlot(heap, slot, collector);
+ });
} else {
RememberedSet<OLD_TO_OLD>::Iterate(chunk, [](Address slot) {
return UpdateSlot(reinterpret_cast<Object**>(slot));
@@ -4086,7 +4187,8 @@ class PointerUpdateJobTraits {
}
}
- static void UpdateTypedPointers(Heap* heap, MemoryChunk* chunk) {
+ static void UpdateTypedPointers(Heap* heap, MemoryChunk* chunk,
+ const MarkCompactCollectorBase* collector) {
if (type == OLD_TO_OLD) {
Isolate* isolate = heap->isolate();
RememberedSet<OLD_TO_OLD>::IterateTyped(
@@ -4098,19 +4200,20 @@ class PointerUpdateJobTraits {
} else {
Isolate* isolate = heap->isolate();
RememberedSet<OLD_TO_NEW>::IterateTyped(
- chunk,
- [isolate, heap](SlotType slot_type, Address host_addr, Address slot) {
+ chunk, [isolate, heap, collector](SlotType slot_type,
+ Address host_addr, Address slot) {
return UpdateTypedSlotHelper::UpdateTypedSlot(
- isolate, slot_type, slot, [heap](Object** slot) {
+ isolate, slot_type, slot, [heap, collector](Object** slot) {
return CheckAndUpdateOldToNewSlot(
- heap, reinterpret_cast<Address>(slot));
+ heap, reinterpret_cast<Address>(slot), collector);
});
});
}
}
- static SlotCallbackResult CheckAndUpdateOldToNewSlot(Heap* heap,
- Address slot_address) {
+ static SlotCallbackResult CheckAndUpdateOldToNewSlot(
+ Heap* heap, Address slot_address,
+ const MarkCompactCollectorBase* collector) {
// There may be concurrent action on slots in dead objects. Concurrent
// sweeper threads may overwrite the slot content with a free space object.
// Moreover, the pointed-to object may also get concurrently overwritten
@@ -4150,7 +4253,7 @@ class PointerUpdateJobTraits {
// markbits to determine liveness.
HeapObject* heap_object = reinterpret_cast<HeapObject*>(slot_reference);
if (ObjectMarking::IsBlack(heap_object,
- MarkingState::Internal(heap_object)))
+ collector->marking_state(heap_object)))
return KEEP_SLOT;
} else {
DCHECK(!heap->InNewSpace(slot_reference));
@@ -4169,14 +4272,15 @@ int NumberOfPointerUpdateTasks(int pages) {
}
template <RememberedSetType type>
-void UpdatePointersInParallel(Heap* heap, base::Semaphore* semaphore) {
+void UpdatePointersInParallel(Heap* heap, base::Semaphore* semaphore,
+ const MarkCompactCollectorBase* collector) {
PageParallelJob<PointerUpdateJobTraits<type> > job(
heap, heap->isolate()->cancelable_task_manager(), semaphore);
RememberedSet<type>::IterateMemoryChunks(
heap, [&job](MemoryChunk* chunk) { job.AddPage(chunk, 0); });
int num_pages = job.NumberOfPages();
int num_tasks = NumberOfPointerUpdateTasks(num_pages);
- job.Run(num_tasks, [](int i) { return 0; });
+ job.Run(num_tasks, [collector](int i) { return collector; });
}
class ToSpacePointerUpdateJobTraits {
@@ -4263,14 +4367,16 @@ void MarkCompactCollector::UpdatePointersAfterEvacuation() {
// Update roots.
PointersUpdatingVisitor updating_visitor;
heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE);
- UpdatePointersInParallel<OLD_TO_NEW>(heap_, &page_parallel_job_semaphore_);
+ UpdatePointersInParallel<OLD_TO_NEW>(heap_, &page_parallel_job_semaphore_,
+ this);
}
{
Heap* heap = this->heap();
TRACE_GC(heap->tracer(),
GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_EVACUATED);
- UpdatePointersInParallel<OLD_TO_OLD>(heap_, &page_parallel_job_semaphore_);
+ UpdatePointersInParallel<OLD_TO_OLD>(heap_, &page_parallel_job_semaphore_,
+ this);
}
{
@@ -4299,7 +4405,8 @@ void MinorMarkCompactCollector::UpdatePointersAfterEvacuation() {
// global handles. Find a way to only process the ones related to new
// space.
heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE);
- UpdatePointersInParallel<OLD_TO_NEW>(heap_, &page_parallel_job_semaphore_);
+ UpdatePointersInParallel<OLD_TO_NEW>(heap_, &page_parallel_job_semaphore_,
+ this);
}
{
@@ -4357,7 +4464,7 @@ int MarkCompactCollector::Sweeper::ParallelSweepPage(Page* page,
DCHECK_EQ(Page::kSweepingPending,
page->concurrent_sweeping_state().Value());
page->concurrent_sweeping_state().SetValue(Page::kSweepingInProgress);
- const Sweeper::FreeSpaceTreatmentMode free_space_mode =
+ const FreeSpaceTreatmentMode free_space_mode =
Heap::ShouldZapGarbage() ? ZAP_FREE_SPACE : IGNORE_FREE_SPACE;
if (identity == NEW_SPACE) {
RawSweep(page, IGNORE_FREE_LIST, free_space_mode);
@@ -4442,8 +4549,9 @@ void MarkCompactCollector::StartSweepSpace(PagedSpace* space) {
// testing this is fine.
p->concurrent_sweeping_state().SetValue(Page::kSweepingInProgress);
Sweeper::RawSweep(p, Sweeper::IGNORE_FREE_LIST,
- Heap::ShouldZapGarbage() ? Sweeper::ZAP_FREE_SPACE
- : Sweeper::IGNORE_FREE_SPACE);
+ Heap::ShouldZapGarbage()
+ ? FreeSpaceTreatmentMode::ZAP_FREE_SPACE
+ : FreeSpaceTreatmentMode::IGNORE_FREE_SPACE);
continue;
}
« no previous file with comments | « src/heap/mark-compact.h ('k') | src/heap/spaces.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698