Index: src/heap/mark-compact.cc |
diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc |
index 88e6983035cd618394b2d47bc44414b2a37ad7c0..a038fa6056f75036f7b1853553c8f2b3963959bd 100644 |
--- a/src/heap/mark-compact.cc |
+++ b/src/heap/mark-compact.cc |
@@ -322,7 +322,6 @@ void MarkCompactCollector::CollectGarbage() { |
Finish(); |
} |
- |
#ifdef VERIFY_HEAP |
void MarkCompactCollector::VerifyMarkbitsAreClean(PagedSpace* space) { |
for (Page* p : *space) { |
@@ -354,7 +353,6 @@ void MarkCompactCollector::VerifyMarkbitsAreClean() { |
} |
} |
- |
void MarkCompactCollector::VerifyWeakEmbeddedObjectsInCode() { |
HeapObjectIterator code_iterator(heap()->code_space()); |
for (HeapObject* obj = code_iterator.Next(); obj != NULL; |
@@ -1083,6 +1081,39 @@ void CodeFlusher::IteratePointersToFromSpace(ObjectVisitor* v) { |
} |
} |
+class StaticYoungGenerationMarkingVisitor |
+ : public StaticNewSpaceVisitor<StaticYoungGenerationMarkingVisitor> { |
+ public: |
+ static void Initialize(Heap* heap) { |
+ StaticNewSpaceVisitor<StaticYoungGenerationMarkingVisitor>::Initialize(); |
+ } |
+ |
+ inline static void VisitPointer(Heap* heap, HeapObject* object, Object** p) { |
+ Object* target = *p; |
+ if (heap->InNewSpace(target)) { |
+ if (MarkRecursively(heap, HeapObject::cast(target))) return; |
+ PushOnMarkingDeque(heap, target); |
+ } |
+ } |
+ |
+ protected: |
+ inline static void PushOnMarkingDeque(Heap* heap, Object* obj) { |
+ HeapObject* object = HeapObject::cast(obj); |
+ MarkBit mark_bit = ObjectMarking::MarkBitFrom(object); |
+ heap->mark_compact_collector()->MarkObject(object, mark_bit); |
+ } |
+ |
+ inline static bool MarkRecursively(Heap* heap, HeapObject* object) { |
+ StackLimitCheck check(heap->isolate()); |
+ if (check.HasOverflowed()) return false; |
+ |
+ MarkBit mark = ObjectMarking::MarkBitFrom(object); |
+ if (Marking::IsBlackOrGrey(mark)) return true; |
+ heap->mark_compact_collector()->SetMark(object, mark); |
+ IterateBody(object->map(), object); |
+ return true; |
+ } |
+}; |
class MarkCompactMarkingVisitor |
: public StaticMarkingVisitor<MarkCompactMarkingVisitor> { |
@@ -1336,11 +1367,12 @@ void MarkCompactCollector::PrepareForCodeFlushing() { |
heap()->isolate()->compilation_cache()->IterateFunctions(&visitor); |
heap()->isolate()->handle_scope_implementer()->Iterate(&visitor); |
- ProcessMarkingDeque(); |
+ ProcessMarkingDeque<MarkCompactMode::FULL>(); |
} |
// Visitor class for marking heap roots. |
+template <MarkCompactMode mode> |
class RootMarkingVisitor : public ObjectVisitor { |
public: |
explicit RootMarkingVisitor(Heap* heap) |
@@ -1362,6 +1394,10 @@ class RootMarkingVisitor : public ObjectVisitor { |
HeapObject* object = HeapObject::cast(*p); |
+ if (mode == MarkCompactMode::YOUNG_GENERATION && |
+ !collector_->heap()->InNewSpace(object)) |
+ return; |
+ |
MarkBit mark_bit = ObjectMarking::MarkBitFrom(object); |
if (Marking::IsBlackOrGrey(mark_bit)) return; |
@@ -1369,14 +1405,21 @@ class RootMarkingVisitor : public ObjectVisitor { |
// Mark the object. |
collector_->SetMark(object, mark_bit); |
- // Mark the map pointer and body, and push them on the marking stack. |
- MarkBit map_mark = ObjectMarking::MarkBitFrom(map); |
- collector_->MarkObject(map, map_mark); |
- MarkCompactMarkingVisitor::IterateBody(map, object); |
+ switch (mode) { |
+ case MarkCompactMode::FULL: { |
+ // Mark the map pointer and body, and push them on the marking stack. |
+ MarkBit map_mark = ObjectMarking::MarkBitFrom(map); |
+ collector_->MarkObject(map, map_mark); |
+ MarkCompactMarkingVisitor::IterateBody(map, object); |
+ } break; |
+ case MarkCompactMode::YOUNG_GENERATION: |
+ StaticYoungGenerationMarkingVisitor::IterateBody(map, object); |
+ break; |
+ } |
// Mark all the objects reachable from the map and body. May leave |
// overflowed objects in the heap. |
- collector_->EmptyMarkingDeque(); |
+ collector_->EmptyMarkingDeque<mode>(); |
} |
MarkCompactCollector* collector_; |
@@ -1946,8 +1989,8 @@ bool MarkCompactCollector::IsUnmarkedHeapObjectWithHeap(Heap* heap, |
return Marking::IsWhite(mark); |
} |
- |
-void MarkCompactCollector::MarkStringTable(RootMarkingVisitor* visitor) { |
+void MarkCompactCollector::MarkStringTable( |
+ RootMarkingVisitor<MarkCompactMode::FULL>* visitor) { |
StringTable* string_table = heap()->string_table(); |
// Mark the string table itself. |
MarkBit string_table_mark = ObjectMarking::MarkBitFrom(string_table); |
@@ -1957,7 +2000,7 @@ void MarkCompactCollector::MarkStringTable(RootMarkingVisitor* visitor) { |
} |
// Explicitly mark the prefix. |
string_table->IteratePrefix(visitor); |
- ProcessMarkingDeque(); |
+ ProcessMarkingDeque<MarkCompactMode::FULL>(); |
} |
@@ -1966,8 +2009,8 @@ void MarkCompactCollector::MarkAllocationSite(AllocationSite* site) { |
SetMark(site, mark_bit); |
} |
- |
-void MarkCompactCollector::MarkRoots(RootMarkingVisitor* visitor) { |
+void MarkCompactCollector::MarkRoots( |
+ RootMarkingVisitor<MarkCompactMode::FULL>* visitor) { |
// Mark the heap roots including global variables, stack variables, |
// etc., and all objects reachable from them. |
heap()->IterateStrongRoots(visitor, VISIT_ONLY_STRONG); |
@@ -1977,8 +2020,8 @@ void MarkCompactCollector::MarkRoots(RootMarkingVisitor* visitor) { |
// There may be overflowed objects in the heap. Visit them now. |
while (marking_deque()->overflowed()) { |
- RefillMarkingDeque(); |
- EmptyMarkingDeque(); |
+ RefillMarkingDeque<MarkCompactMode::FULL>(); |
+ EmptyMarkingDeque<MarkCompactMode::FULL>(); |
} |
} |
@@ -2018,6 +2061,7 @@ void MarkCompactCollector::MarkImplicitRefGroups( |
// Before: the marking stack contains zero or more heap object pointers. |
// After: the marking stack is empty, and all objects reachable from the |
// marking stack have been marked, or are overflowed in the heap. |
+template <MarkCompactMode mode> |
void MarkCompactCollector::EmptyMarkingDeque() { |
while (!marking_deque()->IsEmpty()) { |
HeapObject* object = marking_deque()->Pop(); |
@@ -2028,10 +2072,17 @@ void MarkCompactCollector::EmptyMarkingDeque() { |
DCHECK(!Marking::IsWhite(ObjectMarking::MarkBitFrom(object))); |
Map* map = object->map(); |
- MarkBit map_mark = ObjectMarking::MarkBitFrom(map); |
- MarkObject(map, map_mark); |
- |
- MarkCompactMarkingVisitor::IterateBody(map, object); |
+ switch (mode) { |
+ case MarkCompactMode::FULL: { |
+ MarkBit map_mark = ObjectMarking::MarkBitFrom(map); |
+ MarkObject(map, map_mark); |
+ MarkCompactMarkingVisitor::IterateBody(map, object); |
+ } break; |
+ case MarkCompactMode::YOUNG_GENERATION: { |
+ DCHECK(Marking::IsBlack(ObjectMarking::MarkBitFrom(object))); |
+ StaticYoungGenerationMarkingVisitor::IterateBody(map, object); |
+ } break; |
+ } |
} |
} |
@@ -2041,6 +2092,7 @@ void MarkCompactCollector::EmptyMarkingDeque() { |
// before sweeping completes. If sweeping completes, there are no remaining |
// overflowed objects in the heap so the overflow flag on the markings stack |
// is cleared. |
+template <MarkCompactMode mode> |
void MarkCompactCollector::RefillMarkingDeque() { |
isolate()->CountUsage(v8::Isolate::UseCounterFeature::kMarkDequeOverflow); |
DCHECK(marking_deque()->overflowed()); |
@@ -2048,18 +2100,17 @@ void MarkCompactCollector::RefillMarkingDeque() { |
DiscoverGreyObjectsInNewSpace(); |
if (marking_deque()->IsFull()) return; |
- DiscoverGreyObjectsInSpace(heap()->old_space()); |
- if (marking_deque()->IsFull()) return; |
- |
- DiscoverGreyObjectsInSpace(heap()->code_space()); |
- if (marking_deque()->IsFull()) return; |
- |
- DiscoverGreyObjectsInSpace(heap()->map_space()); |
- if (marking_deque()->IsFull()) return; |
- |
- LargeObjectIterator lo_it(heap()->lo_space()); |
- DiscoverGreyObjectsWithIterator(&lo_it); |
- if (marking_deque()->IsFull()) return; |
+ if (mode == MarkCompactMode::FULL) { |
+ DiscoverGreyObjectsInSpace(heap()->old_space()); |
+ if (marking_deque()->IsFull()) return; |
+ DiscoverGreyObjectsInSpace(heap()->code_space()); |
+ if (marking_deque()->IsFull()) return; |
+ DiscoverGreyObjectsInSpace(heap()->map_space()); |
+ if (marking_deque()->IsFull()) return; |
+ LargeObjectIterator lo_it(heap()->lo_space()); |
+ DiscoverGreyObjectsWithIterator(&lo_it); |
+ if (marking_deque()->IsFull()) return; |
+ } |
marking_deque()->ClearOverflowed(); |
} |
@@ -2069,12 +2120,14 @@ void MarkCompactCollector::RefillMarkingDeque() { |
// stack. Before: the marking stack contains zero or more heap object |
// pointers. After: the marking stack is empty and there are no overflowed |
// objects in the heap. |
+template <MarkCompactMode mode> |
void MarkCompactCollector::ProcessMarkingDeque() { |
- EmptyMarkingDeque(); |
+ EmptyMarkingDeque<mode>(); |
while (marking_deque()->overflowed()) { |
- RefillMarkingDeque(); |
- EmptyMarkingDeque(); |
+ RefillMarkingDeque<mode>(); |
+ EmptyMarkingDeque<mode>(); |
} |
+ DCHECK(marking_deque()->IsEmpty()); |
} |
// Mark all objects reachable (transitively) from objects on the marking |
@@ -2099,7 +2152,7 @@ void MarkCompactCollector::ProcessEphemeralMarking( |
} |
ProcessWeakCollections(); |
work_to_do = !marking_deque()->IsEmpty(); |
- ProcessMarkingDeque(); |
+ ProcessMarkingDeque<MarkCompactMode::FULL>(); |
} |
} |
@@ -2114,7 +2167,7 @@ void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor) { |
if (!code->CanDeoptAt(it.frame()->pc())) { |
Code::BodyDescriptor::IterateBody(code, visitor); |
} |
- ProcessMarkingDeque(); |
+ ProcessMarkingDeque<MarkCompactMode::FULL>(); |
return; |
} |
} |
@@ -2154,6 +2207,7 @@ void MarkingDeque::StartUsing() { |
void MarkingDeque::StopUsing() { |
base::LockGuard<base::Mutex> guard(&mutex_); |
+ if (!in_use_) return; |
DCHECK(IsEmpty()); |
DCHECK(!overflowed_); |
top_ = bottom_ = mask_ = 0; |
@@ -2267,6 +2321,95 @@ void MarkCompactCollector::RecordObjectStats() { |
} |
} |
+SlotCallbackResult MarkCompactCollector::CheckAndMarkObject( |
+ Heap* heap, Address slot_address) { |
+ Object* object = *reinterpret_cast<Object**>(slot_address); |
+ if (heap->InNewSpace(object)) { |
+ // Marking happens before flipping the young generation, so the object |
+ // has to be in ToSpace. |
+ DCHECK(heap->InToSpace(object)); |
+ HeapObject* heap_object = reinterpret_cast<HeapObject*>(object); |
+ MarkBit mark_bit = ObjectMarking::MarkBitFrom(heap_object); |
+ if (Marking::IsBlackOrGrey(mark_bit)) { |
+ return KEEP_SLOT; |
+ } |
+ heap->mark_compact_collector()->SetMark(heap_object, mark_bit); |
+ StaticYoungGenerationMarkingVisitor::IterateBody(heap_object->map(), |
+ heap_object); |
+ return KEEP_SLOT; |
+ } |
+ return REMOVE_SLOT; |
+} |
+ |
+static bool IsUnmarkedObject(Heap* heap, Object** p) { |
+ DCHECK_IMPLIES(heap->InNewSpace(*p), heap->InToSpace(*p)); |
+ return heap->InNewSpace(*p) && |
+ !Marking::IsBlack(ObjectMarking::MarkBitFrom(HeapObject::cast(*p))); |
+} |
+ |
+void MarkCompactCollector::MarkLiveObjectsInYoungGeneration() { |
+ TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK); |
+ |
+ PostponeInterruptsScope postpone(isolate()); |
+ |
+ StaticYoungGenerationMarkingVisitor::Initialize(heap()); |
+ RootMarkingVisitor<MarkCompactMode::YOUNG_GENERATION> root_visitor(heap()); |
+ |
+ marking_deque()->StartUsing(); |
+ |
+ isolate()->global_handles()->IdentifyWeakUnmodifiedObjects( |
+ &Heap::IsUnmodifiedHeapObject); |
+ |
+ { |
+ TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK_ROOTS); |
+ heap()->IterateRoots(&root_visitor, VISIT_ALL_IN_SCAVENGE); |
+ ProcessMarkingDeque<MarkCompactMode::YOUNG_GENERATION>(); |
+ } |
+ |
+ { |
+ TRACE_GC(heap()->tracer(), |
+ GCTracer::Scope::MINOR_MC_MARK_OLD_TO_NEW_POINTERS); |
+ RememberedSet<OLD_TO_NEW>::Iterate(heap(), [this](Address addr) { |
+ return CheckAndMarkObject(heap(), addr); |
+ }); |
+ RememberedSet<OLD_TO_NEW>::IterateTyped( |
+ heap(), [this](SlotType type, Address host_addr, Address addr) { |
+ return UpdateTypedSlotHelper::UpdateTypedSlot( |
+ isolate(), type, addr, [this](Object** addr) { |
+ return CheckAndMarkObject(heap(), |
+ reinterpret_cast<Address>(addr)); |
+ }); |
+ }); |
+ ProcessMarkingDeque<MarkCompactMode::YOUNG_GENERATION>(); |
+ } |
+ |
+ { |
+ TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK_WEAK); |
+ heap()->VisitEncounteredWeakCollections(&root_visitor); |
+ ProcessMarkingDeque<MarkCompactMode::YOUNG_GENERATION>(); |
+ } |
+ |
+ if (is_code_flushing_enabled()) { |
+ TRACE_GC(heap()->tracer(), |
+ GCTracer::Scope::MINOR_MC_MARK_CODE_FLUSH_CANDIDATES); |
+ code_flusher()->IteratePointersToFromSpace(&root_visitor); |
+ ProcessMarkingDeque<MarkCompactMode::YOUNG_GENERATION>(); |
+ } |
+ |
+ { |
+ TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK_GLOBAL_HANDLES); |
+ isolate()->global_handles()->MarkNewSpaceWeakUnmodifiedObjectsPending( |
+ &IsUnmarkedObject); |
+ isolate() |
+ ->global_handles() |
+ ->IterateNewSpaceWeakUnmodifiedRoots<GlobalHandles::VISIT_OTHERS>( |
+ &root_visitor); |
+ ProcessMarkingDeque<MarkCompactMode::YOUNG_GENERATION>(); |
+ } |
+ |
+ marking_deque()->StopUsing(); |
+} |
+ |
void MarkCompactCollector::MarkLiveObjects() { |
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK); |
// The recursive GC marker detects when it is nearing stack overflow, |
@@ -2296,7 +2439,7 @@ void MarkCompactCollector::MarkLiveObjects() { |
PrepareForCodeFlushing(); |
} |
- RootMarkingVisitor root_visitor(heap()); |
+ RootMarkingVisitor<MarkCompactMode::FULL> root_visitor(heap()); |
{ |
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK_ROOTS); |
@@ -2328,7 +2471,7 @@ void MarkCompactCollector::MarkLiveObjects() { |
GCTracer::Scope::MC_MARK_WEAK_CLOSURE_WEAK_HANDLES); |
heap()->isolate()->global_handles()->IdentifyWeakHandles( |
&IsUnmarkedHeapObject); |
- ProcessMarkingDeque(); |
+ ProcessMarkingDeque<MarkCompactMode::FULL>(); |
} |
// Then we mark the objects. |
@@ -2336,7 +2479,7 @@ void MarkCompactCollector::MarkLiveObjects() { |
TRACE_GC(heap()->tracer(), |
GCTracer::Scope::MC_MARK_WEAK_CLOSURE_WEAK_ROOTS); |
heap()->isolate()->global_handles()->IterateWeakRoots(&root_visitor); |
- ProcessMarkingDeque(); |
+ ProcessMarkingDeque<MarkCompactMode::FULL>(); |
} |
// Repeat Harmony weak maps marking to mark unmarked objects reachable from |