Index: src/heap/mark-compact.cc |
diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc |
index fe886ac8136ebe99d1924a9b9250aa357038eadf..2e862977812c14d67ddad01a8a76283c7a23bca7 100644 |
--- a/src/heap/mark-compact.cc |
+++ b/src/heap/mark-compact.cc |
@@ -283,12 +283,39 @@ class FullEvacuationVerifier : public EvacuationVerifier { |
#endif // VERIFY_HEAP |
// ============================================================================= |
-// MarkCompactCollector |
+// MarkCompactCollectorBase, MinorMarkCompactCollector, MarkCompactCollector |
// ============================================================================= |
+int MarkCompactCollectorBase::NumberOfParallelCompactionTasks( |
+ int pages, intptr_t live_bytes) { |
+ if (!FLAG_parallel_compaction) return 1; |
+ // Compute the number of needed tasks based on a target compaction time, the |
+ // profiled compaction speed and marked live memory. |
+ // |
+ // The number of parallel compaction tasks is limited by: |
+ // - #evacuation pages |
+ // - #cores |
+ const double kTargetCompactionTimeInMs = .5; |
+ |
+ double compaction_speed = |
+ heap()->tracer()->CompactionSpeedInBytesPerMillisecond(); |
+ |
+ const int available_cores = Max( |
+ 1, static_cast<int>( |
+ V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads())); |
+ int tasks; |
+ if (compaction_speed > 0) { |
+ tasks = 1 + static_cast<int>(live_bytes / compaction_speed / |
+ kTargetCompactionTimeInMs); |
+ } else { |
+ tasks = pages; |
+ } |
+ const int tasks_capped_pages = Min(pages, tasks); |
+ return Min(available_cores, tasks_capped_pages); |
+} |
+ |
MarkCompactCollector::MarkCompactCollector(Heap* heap) |
- : // NOLINT |
- heap_(heap), |
+ : MarkCompactCollectorBase(heap), |
page_parallel_job_semaphore_(0), |
#ifdef DEBUG |
state_(IDLE), |
@@ -616,25 +643,6 @@ bool MarkCompactCollector::Sweeper::AreSweeperTasksRunning() { |
return num_sweeping_tasks_.Value() != 0; |
} |
-const char* AllocationSpaceName(AllocationSpace space) { |
- switch (space) { |
- case NEW_SPACE: |
- return "NEW_SPACE"; |
- case OLD_SPACE: |
- return "OLD_SPACE"; |
- case CODE_SPACE: |
- return "CODE_SPACE"; |
- case MAP_SPACE: |
- return "MAP_SPACE"; |
- case LO_SPACE: |
- return "LO_SPACE"; |
- default: |
- UNREACHABLE(); |
- } |
- |
- return NULL; |
-} |
- |
void MarkCompactCollector::ComputeEvacuationHeuristics( |
size_t area_size, int* target_fragmentation_percent, |
size_t* max_evacuated_bytes) { |
@@ -3140,7 +3148,7 @@ class Evacuator : public Malloced { |
virtual ~Evacuator() {} |
- virtual bool EvacuatePage(Page* page, const MarkingState& state) = 0; |
+ bool EvacuatePage(Page* page, const MarkingState& state); |
// Merge back locally cached info sequentially. Note that this method needs |
// to be called from the main thread. |
@@ -3152,6 +3160,8 @@ class Evacuator : public Malloced { |
protected: |
static const int kInitialLocalPretenuringFeedbackCapacity = 256; |
+ virtual bool RawEvacuatePage(Page* page, const MarkingState& state) = 0; |
+ |
inline Heap* heap() { return heap_; } |
void ReportCompactionProgress(double duration, intptr_t bytes_compacted) { |
@@ -3178,6 +3188,34 @@ class Evacuator : public Malloced { |
intptr_t bytes_compacted_; |
}; |
+bool Evacuator::EvacuatePage(Page* page, const MarkingState& state) { |
+ bool success = false; |
+ DCHECK(page->SweepingDone()); |
+ intptr_t saved_live_bytes = state.live_bytes(); |
+ double evacuation_time = 0.0; |
+ { |
+ AlwaysAllocateScope always_allocate(heap()->isolate()); |
+ TimedScope timed_scope(&evacuation_time); |
+ success = RawEvacuatePage(page, state); |
+ } |
+ ReportCompactionProgress(evacuation_time, saved_live_bytes); |
+ if (FLAG_trace_evacuation) { |
+ PrintIsolate( |
+ heap()->isolate(), |
+ "evacuation[%p]: page=%p new_space=%d " |
+ "page_evacuation=%d executable=%d contains_age_mark=%d " |
+ "live_bytes=%" V8PRIdPTR " time=%f page_promotion_qualifies=%d\n", |
+ static_cast<void*>(this), static_cast<void*>(page), page->InNewSpace(), |
+ page->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION) || |
+ page->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION), |
+ page->IsFlagSet(MemoryChunk::IS_EXECUTABLE), |
+ page->Contains(heap()->new_space()->age_mark()), saved_live_bytes, |
+ evacuation_time, |
+ saved_live_bytes > Evacuator::PageEvacuationThreshold()); |
+ } |
+ return success; |
+} |
+ |
void Evacuator::Finalize() { |
heap()->old_space()->MergeCompactionSpace(compaction_spaces_.Get(OLD_SPACE)); |
heap()->code_space()->MergeCompactionSpace( |
@@ -3201,116 +3239,66 @@ class FullEvacuator : public Evacuator { |
FullEvacuator(Heap* heap, RecordMigratedSlotVisitor* record_visitor) |
: Evacuator(heap, record_visitor) {} |
- bool EvacuatePage(Page* page, const MarkingState& state) override; |
+ protected: |
+ bool RawEvacuatePage(Page* page, const MarkingState& state) override; |
}; |
-bool FullEvacuator::EvacuatePage(Page* page, const MarkingState& state) { |
+bool FullEvacuator::RawEvacuatePage(Page* page, const MarkingState& state) { |
bool success = false; |
- DCHECK(page->SweepingDone()); |
- intptr_t saved_live_bytes = state.live_bytes(); |
- double evacuation_time = 0.0; |
- { |
- AlwaysAllocateScope always_allocate(heap()->isolate()); |
- TimedScope timed_scope(&evacuation_time); |
- LiveObjectVisitor object_visitor; |
- switch (ComputeEvacuationMode(page)) { |
- case kObjectsNewToOld: |
- success = |
- object_visitor.VisitBlackObjects(page, state, &new_space_visitor_, |
- LiveObjectVisitor::kClearMarkbits); |
+ LiveObjectVisitor object_visitor; |
+ switch (ComputeEvacuationMode(page)) { |
+ case kObjectsNewToOld: |
+ success = object_visitor.VisitBlackObjects( |
+ page, state, &new_space_visitor_, LiveObjectVisitor::kClearMarkbits); |
+ DCHECK(success); |
+ ArrayBufferTracker::ProcessBuffers( |
+ page, ArrayBufferTracker::kUpdateForwardedRemoveOthers); |
+ break; |
+ case kPageNewToOld: |
+ success = object_visitor.VisitBlackObjects( |
+ page, state, &new_to_old_page_visitor_, |
+ LiveObjectVisitor::kKeepMarking); |
+ DCHECK(success); |
+ new_to_old_page_visitor_.account_moved_bytes( |
+ MarkingState::Internal(page).live_bytes()); |
+ // ArrayBufferTracker will be updated during sweeping. |
+ break; |
+ case kPageNewToNew: |
+ success = object_visitor.VisitBlackObjects( |
+ page, state, &new_to_new_page_visitor_, |
+ LiveObjectVisitor::kKeepMarking); |
+ DCHECK(success); |
+ new_to_new_page_visitor_.account_moved_bytes( |
+ MarkingState::Internal(page).live_bytes()); |
+ // ArrayBufferTracker will be updated during sweeping. |
+ break; |
+ case kObjectsOldToOld: |
+ success = object_visitor.VisitBlackObjects( |
+ page, state, &old_space_visitor_, LiveObjectVisitor::kClearMarkbits); |
+ if (!success) { |
+ // Aborted compaction page. We have to record slots here, since we |
+ // might not have recorded them in first place. |
+ // Note: We mark the page as aborted here to be able to record slots |
+ // for code objects in |RecordMigratedSlotVisitor|. |
+ page->SetFlag(Page::COMPACTION_WAS_ABORTED); |
+ EvacuateRecordOnlyVisitor record_visitor(heap()); |
+ success = object_visitor.VisitBlackObjects( |
+ page, state, &record_visitor, LiveObjectVisitor::kKeepMarking); |
+ ArrayBufferTracker::ProcessBuffers( |
+ page, ArrayBufferTracker::kUpdateForwardedKeepOthers); |
DCHECK(success); |
+ // We need to return failure here to indicate that we want this page |
+ // added to the sweeper. |
+ success = false; |
+ } else { |
ArrayBufferTracker::ProcessBuffers( |
page, ArrayBufferTracker::kUpdateForwardedRemoveOthers); |
- break; |
- case kPageNewToOld: |
- success = object_visitor.VisitBlackObjects( |
- page, state, &new_to_old_page_visitor_, |
- LiveObjectVisitor::kKeepMarking); |
- DCHECK(success); |
- new_to_old_page_visitor_.account_moved_bytes( |
- MarkingState::Internal(page).live_bytes()); |
- // ArrayBufferTracker will be updated during sweeping. |
- break; |
- case kPageNewToNew: |
- success = object_visitor.VisitBlackObjects( |
- page, state, &new_to_new_page_visitor_, |
- LiveObjectVisitor::kKeepMarking); |
- DCHECK(success); |
- new_to_new_page_visitor_.account_moved_bytes( |
- MarkingState::Internal(page).live_bytes()); |
- // ArrayBufferTracker will be updated during sweeping. |
- break; |
- case kObjectsOldToOld: |
- success = |
- object_visitor.VisitBlackObjects(page, state, &old_space_visitor_, |
- LiveObjectVisitor::kClearMarkbits); |
- if (!success) { |
- // Aborted compaction page. We have to record slots here, since we |
- // might not have recorded them in first place. |
- // Note: We mark the page as aborted here to be able to record slots |
- // for code objects in |RecordMigratedSlotVisitor|. |
- page->SetFlag(Page::COMPACTION_WAS_ABORTED); |
- EvacuateRecordOnlyVisitor record_visitor(heap()); |
- success = object_visitor.VisitBlackObjects( |
- page, state, &record_visitor, LiveObjectVisitor::kKeepMarking); |
- ArrayBufferTracker::ProcessBuffers( |
- page, ArrayBufferTracker::kUpdateForwardedKeepOthers); |
- DCHECK(success); |
- // We need to return failure here to indicate that we want this page |
- // added to the sweeper. |
- success = false; |
- } else { |
- ArrayBufferTracker::ProcessBuffers( |
- page, ArrayBufferTracker::kUpdateForwardedRemoveOthers); |
- } |
- break; |
- } |
- } |
- ReportCompactionProgress(evacuation_time, saved_live_bytes); |
- if (FLAG_trace_evacuation) { |
- PrintIsolate(heap()->isolate(), |
- "evacuation[%p]: page=%p new_space=%d " |
- "page_evacuation=%d executable=%d contains_age_mark=%d " |
- "live_bytes=%" V8PRIdPTR " time=%f\n", |
- static_cast<void*>(this), static_cast<void*>(page), |
- page->InNewSpace(), |
- page->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION) || |
- page->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION), |
- page->IsFlagSet(MemoryChunk::IS_EXECUTABLE), |
- page->Contains(heap()->new_space()->age_mark()), |
- saved_live_bytes, evacuation_time); |
+ } |
+ break; |
} |
return success; |
} |
-int MarkCompactCollector::NumberOfParallelCompactionTasks(int pages, |
- intptr_t live_bytes) { |
- if (!FLAG_parallel_compaction) return 1; |
- // Compute the number of needed tasks based on a target compaction time, the |
- // profiled compaction speed and marked live memory. |
- // |
- // The number of parallel compaction tasks is limited by: |
- // - #evacuation pages |
- // - #cores |
- const double kTargetCompactionTimeInMs = .5; |
- |
- double compaction_speed = |
- heap()->tracer()->CompactionSpeedInBytesPerMillisecond(); |
- |
- const int available_cores = Max( |
- 1, static_cast<int>( |
- V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads())); |
- int tasks; |
- if (compaction_speed > 0) { |
- tasks = 1 + static_cast<int>(live_bytes / compaction_speed / |
- kTargetCompactionTimeInMs); |
- } else { |
- tasks = pages; |
- } |
- const int tasks_capped_pages = Min(pages, tasks); |
- return Min(available_cores, tasks_capped_pages); |
-} |
- |
class EvacuationJobTraits { |
public: |
typedef int* PerPageData; // Pointer to number of aborted pages. |