| 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
|
|
|