Index: src/heap/mark-compact.cc |
diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc |
index e77e90e166bfaeb6e8347dd56698e94ec7ec8906..5ed7b4a1bf9e0f69117d336c42e9837a2357c9a1 100644 |
--- a/src/heap/mark-compact.cc |
+++ b/src/heap/mark-compact.cc |
@@ -2935,7 +2935,9 @@ class PointersUpdatingVisitor : public ObjectVisitor { |
MapWord map_word = heap_obj->map_word(); |
if (map_word.IsForwardingAddress()) { |
DCHECK(heap->InFromSpace(heap_obj) || |
- MarkCompactCollector::IsOnEvacuationCandidate(heap_obj)); |
+ MarkCompactCollector::IsOnEvacuationCandidate(heap_obj) || |
+ Page::FromAddress(heap_obj->address()) |
+ ->IsFlagSet(Page::COMPACTION_WAS_ABORTED)); |
HeapObject* target = map_word.ToForwardingAddress(); |
base::NoBarrier_CompareAndSwap( |
reinterpret_cast<base::AtomicWord*>(slot), |
@@ -3463,7 +3465,7 @@ void MarkCompactCollector::EvacuatePagesInParallel() { |
// - Leave the page in the list of pages of a space since we could not |
// fully evacuate it. |
DCHECK(p->IsEvacuationCandidate()); |
- p->SetFlag(Page::RESCAN_ON_EVACUATION); |
+ p->SetFlag(Page::COMPACTION_WAS_ABORTED); |
abandoned_pages++; |
break; |
case MemoryChunk::kCompactingFinalize: |
@@ -3701,6 +3703,57 @@ void MarkCompactCollector::RemoveObjectSlots(Address start_slot, |
} |
+void MarkCompactCollector::VisitLiveObjects(Page* page, |
+ ObjectVisitor* visitor) { |
+ // First pass on aborted pages. |
+ int offsets[16]; |
+ for (MarkBitCellIterator it(page); !it.Done(); it.Advance()) { |
+ Address cell_base = it.CurrentCellBase(); |
+ MarkBit::CellType* cell = it.CurrentCell(); |
+ if (*cell == 0) continue; |
+ int live_objects = MarkWordToObjectStarts(*cell, offsets); |
+ for (int i = 0; i < live_objects; i++) { |
+ Address object_addr = cell_base + offsets[i] * kPointerSize; |
+ HeapObject* live_object = HeapObject::FromAddress(object_addr); |
+ DCHECK(Marking::IsBlack(Marking::MarkBitFrom(live_object))); |
+ Map* map = live_object->synchronized_map(); |
+ int size = live_object->SizeFromMap(map); |
+ live_object->IterateBody(map->instance_type(), size, visitor); |
+ } |
+ } |
+} |
+ |
+ |
+void MarkCompactCollector::SweepAbortedPages() { |
+ // Second pass on aborted pages. |
+ for (int i = 0; i < evacuation_candidates_.length(); i++) { |
+ Page* p = evacuation_candidates_[i]; |
+ if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) { |
+ p->ClearFlag(MemoryChunk::COMPACTION_WAS_ABORTED); |
+ PagedSpace* space = static_cast<PagedSpace*>(p->owner()); |
+ switch (space->identity()) { |
+ case OLD_SPACE: |
+ Sweep<SWEEP_ONLY, SWEEP_ON_MAIN_THREAD, IGNORE_SKIP_LIST, |
+ IGNORE_FREE_SPACE>(space, nullptr, p, nullptr); |
+ break; |
+ case CODE_SPACE: |
+ if (FLAG_zap_code_space) { |
+ Sweep<SWEEP_ONLY, SWEEP_ON_MAIN_THREAD, REBUILD_SKIP_LIST, |
+ ZAP_FREE_SPACE>(space, NULL, p, nullptr); |
+ } else { |
+ Sweep<SWEEP_ONLY, SWEEP_ON_MAIN_THREAD, REBUILD_SKIP_LIST, |
+ IGNORE_FREE_SPACE>(space, NULL, p, nullptr); |
+ } |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ } |
+ } |
+} |
+ |
+ |
void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { |
Heap::RelocationLock relocation_lock(heap()); |
@@ -3794,13 +3847,15 @@ void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { |
// code objects from non-updated pc pointing into evacuation candidate. |
SkipList* list = p->skip_list(); |
if (list != NULL) list->Clear(); |
- } |
- if (p->IsEvacuationCandidate() && |
- p->IsFlagSet(Page::RESCAN_ON_EVACUATION)) { |
- // Case where we've aborted compacting a page. Clear the flag here to |
- // avoid release the page later on. |
- p->ClearEvacuationCandidate(); |
+ // First pass on aborted pages, fixing up all live objects. |
+ if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) { |
+ // Clearing the evacuation candidate flag here has the effect of |
+ // stopping recording of slots for it in the following pointer |
+ // update phases. |
+ p->ClearEvacuationCandidate(); |
+ VisitLiveObjects(p, &updating_visitor); |
+ } |
} |
if (p->IsFlagSet(Page::RESCAN_ON_EVACUATION)) { |
@@ -3836,17 +3891,26 @@ void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { |
} |
} |
- GCTracer::Scope gc_scope(heap()->tracer(), |
- GCTracer::Scope::MC_UPDATE_MISC_POINTERS); |
+ { |
+ GCTracer::Scope gc_scope(heap()->tracer(), |
+ GCTracer::Scope::MC_UPDATE_MISC_POINTERS); |
+ heap_->string_table()->Iterate(&updating_visitor); |
- heap_->string_table()->Iterate(&updating_visitor); |
+ // Update pointers from external string table. |
+ heap_->UpdateReferencesInExternalStringTable( |
+ &UpdateReferenceInExternalStringTableEntry); |
- // Update pointers from external string table. |
- heap_->UpdateReferencesInExternalStringTable( |
- &UpdateReferenceInExternalStringTableEntry); |
+ EvacuationWeakObjectRetainer evacuation_object_retainer; |
+ heap()->ProcessAllWeakReferences(&evacuation_object_retainer); |
+ } |
- EvacuationWeakObjectRetainer evacuation_object_retainer; |
- heap()->ProcessAllWeakReferences(&evacuation_object_retainer); |
+ { |
+ GCTracer::Scope gc_scope(heap()->tracer(), |
+ GCTracer::Scope::MC_SWEEP_ABORTED); |
+ // After updating all pointers, we can finally sweep the aborted pages, |
+ // effectively overriding any forward pointers. |
+ SweepAbortedPages(); |
+ } |
heap_->isolate()->inner_pointer_to_code_cache()->Flush(); |