Chromium Code Reviews| Index: src/heap/mark-compact.cc |
| diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc |
| index 88e6983035cd618394b2d47bc44414b2a37ad7c0..20e99a671d99077b91af3239bc4bdb544f8a234f 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,6 +353,40 @@ void MarkCompactCollector::VerifyMarkbitsAreClean() { |
| } |
| } |
| +void MarkCompactCollector::MarkYoungGenerationForVerification() { |
| + MarkLiveObjectsInYoungGeneration(); |
| +} |
| + |
| +std::vector<HeapObject*> MarkCompactCollector::GetObjectsInToSpace() { |
| + std::vector<HeapObject*> objects; |
| + const Address top = heap()->new_space()->top(); |
| + const Address space_start = heap()->new_space()->bottom(); |
| + const Address space_end = heap()->new_space()->top(); |
| + for (Page* page : NewSpacePageRange(space_start, space_end)) { |
| + HeapObject* object = HeapObject::FromAddress(page->area_start()); |
| + while (object->address() < page->area_end() && |
| + (!page->ContainsLimit(top) || (object->address() < top))) { |
| + if (!object->IsFiller()) { |
| + objects.push_back(object); |
| + } |
| + object = HeapObject::FromAddress(object->address() + object->Size()); |
| + } |
| + } |
| + return objects; |
| +} |
| + |
| +void MarkCompactCollector::VerifyYoungGenerationMarkbitsUsingForwardingPointers( |
| + const std::vector<HeapObject*>& objects) { |
| + for (HeapObject* object : objects) { |
| + const MapWord map_word = object->map_word(); |
| + const bool is_black = Marking::IsBlack(ObjectMarking::MarkBitFrom(object)); |
| + if (map_word.IsForwardingAddress()) { |
| + CHECK(is_black); |
| + } else { |
| + CHECK(!is_black); |
| + } |
| + } |
| +} |
| void MarkCompactCollector::VerifyWeakEmbeddedObjectsInCode() { |
| HeapObjectIterator code_iterator(heap()->code_space()); |
| @@ -1083,6 +1116,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 +1402,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 +1429,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 +1440,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 +2024,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 +2035,7 @@ void MarkCompactCollector::MarkStringTable(RootMarkingVisitor* visitor) { |
| } |
| // Explicitly mark the prefix. |
| string_table->IteratePrefix(visitor); |
| - ProcessMarkingDeque(); |
| + ProcessMarkingDeque<MarkCompactMode::FULL>(); |
| } |
| @@ -1966,8 +2044,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 +2055,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 +2096,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 +2107,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 +2127,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 +2135,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 +2155,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 +2187,7 @@ void MarkCompactCollector::ProcessEphemeralMarking( |
| } |
| ProcessWeakCollections(); |
| work_to_do = !marking_deque()->IsEmpty(); |
| - ProcessMarkingDeque(); |
| + ProcessMarkingDeque<MarkCompactMode::FULL>(); |
| } |
| } |
| @@ -2114,7 +2202,7 @@ void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor) { |
| if (!code->CanDeoptAt(it.frame()->pc())) { |
| Code::BodyDescriptor::IterateBody(code, visitor); |
| } |
| - ProcessMarkingDeque(); |
| + ProcessMarkingDeque<MarkCompactMode::FULL>(); |
| return; |
| } |
| } |
| @@ -2152,13 +2240,15 @@ void MarkingDeque::StartUsing() { |
| overflowed_ = false; |
| } |
| -void MarkingDeque::StopUsing() { |
| +void MarkingDeque::StopUsing(bool free_immediately) { |
| base::LockGuard<base::Mutex> guard(&mutex_); |
| + if (!in_use_) return; |
| + |
| DCHECK(IsEmpty()); |
| DCHECK(!overflowed_); |
| top_ = bottom_ = mask_ = 0; |
| in_use_ = false; |
| - if (FLAG_concurrent_sweeping) { |
| + if (FLAG_concurrent_sweeping && !free_immediately) { |
| StartUncommitTask(); |
| } else { |
| Uncommit(); |
| @@ -2173,6 +2263,7 @@ void MarkingDeque::Clear() { |
| void MarkingDeque::Uncommit() { |
| DCHECK(!in_use_); |
| + if (backing_store_committed_size_ == 0) return; |
|
ulan
2016/11/15 19:57:21
How can this happen?
Michael Lippautz
2016/11/16 08:59:37
I added a comment: Basically, two calls for StopUs
|
| bool success = backing_store_->Uncommit(backing_store_->address(), |
| backing_store_committed_size_); |
| backing_store_committed_size_ = 0; |
| @@ -2267,6 +2358,93 @@ void MarkCompactCollector::RecordObjectStats() { |
| } |
| } |
| +SlotCallbackResult MarkCompactCollector::CheckAndMarkObject( |
| + Heap* heap, Address slot_address) { |
| + Object* object = *reinterpret_cast<Object**>(slot_address); |
| + // Marking happens before flipping the young generation, hence check for |
| + // ToSpace. |
|
ulan
2016/11/15 19:57:21
DCHECK(object_in_new_space implies object_in_to_sp
Michael Lippautz
2016/11/16 08:59:37
Used InNewSpace with a DCHECK for ToSpace.
|
| + if (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) { |
| + return heap->InNewSpace(*p) && |
|
ulan
2016/11/15 19:57:21
For consistency let's use either InNewSpace or InT
Michael Lippautz
2016/11/16 08:59:37
Done (added dcheck).
|
| + !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::DONT_HANDLE_PHANTOM_NODES>(&root_visitor); |
| + ProcessMarkingDeque<MarkCompactMode::YOUNG_GENERATION>(); |
| + } |
| + |
| + marking_deque()->StopUsing(true); |
| +} |
| + |
| void MarkCompactCollector::MarkLiveObjects() { |
| TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK); |
| // The recursive GC marker detects when it is nearing stack overflow, |
| @@ -2296,7 +2474,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 +2506,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 +2514,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 |