Index: src/heap/mark-compact.cc |
diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc |
index b328393da00c13e916d4eed730ab472adf239b48..d410797bdf7b71fae2b8c54464c7d2048784963b 100644 |
--- a/src/heap/mark-compact.cc |
+++ b/src/heap/mark-compact.cc |
@@ -2799,42 +2799,138 @@ void MarkCompactCollector::RecordRelocSlot(Code* host, RelocInfo* rinfo, |
} |
} |
-static inline void UpdateTypedSlot(Isolate* isolate, ObjectVisitor* v, |
- SlotType slot_type, Address addr) { |
+static inline SlotCallbackResult UpdateSlot(Object** slot) { |
+ Object* obj = reinterpret_cast<Object*>( |
+ base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot))); |
+ |
+ if (obj->IsHeapObject()) { |
+ HeapObject* heap_obj = HeapObject::cast(obj); |
+ MapWord map_word = heap_obj->map_word(); |
+ if (map_word.IsForwardingAddress()) { |
+ DCHECK(heap_obj->GetHeap()->InFromSpace(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), |
+ reinterpret_cast<base::AtomicWord>(obj), |
+ reinterpret_cast<base::AtomicWord>(target)); |
+ DCHECK(!heap_obj->GetHeap()->InFromSpace(target) && |
+ !MarkCompactCollector::IsOnEvacuationCandidate(target)); |
+ } |
+ } |
+ return REMOVE_SLOT; |
+} |
+ |
+// Updates a cell slot using an untyped slot callback. |
+// The callback accepts (Heap*, Object**) and returns SlotCallbackResult. |
+template <typename Callback> |
+static SlotCallbackResult UpdateCell(RelocInfo* rinfo, Callback callback) { |
+ DCHECK(rinfo->rmode() == RelocInfo::CELL); |
+ Object* cell = rinfo->target_cell(); |
+ Object* old_cell = cell; |
+ SlotCallbackResult result = callback(&cell); |
+ if (cell != old_cell) { |
+ rinfo->set_target_cell(reinterpret_cast<Cell*>(cell)); |
+ } |
+ return result; |
+} |
+ |
+// Updates a code entry slot using an untyped slot callback. |
+// The callback accepts (Heap*, Object**) and returns SlotCallbackResult. |
+template <typename Callback> |
+static SlotCallbackResult UpdateCodeEntry(Address entry_address, |
+ Callback callback) { |
+ Object* code = Code::GetObjectFromEntryAddress(entry_address); |
+ Object* old_code = code; |
+ SlotCallbackResult result = callback(&code); |
+ if (code != old_code) { |
+ Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry(); |
+ } |
+ return result; |
+} |
+ |
+// Updates a code target slot using an untyped slot callback. |
+// The callback accepts (Heap*, Object**) and returns SlotCallbackResult. |
+template <typename Callback> |
+static SlotCallbackResult UpdateCodeTarget(RelocInfo* rinfo, |
+ Callback callback) { |
+ DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode())); |
+ Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); |
+ Object* old_target = target; |
+ SlotCallbackResult result = callback(&target); |
+ if (target != old_target) { |
+ rinfo->set_target_address(Code::cast(target)->instruction_start()); |
+ } |
+ return result; |
+} |
+ |
+// Updates an embedded pointer slot using an untyped slot callback. |
+// The callback accepts (Heap*, Object**) and returns SlotCallbackResult. |
+template <typename Callback> |
+static SlotCallbackResult UpdateEmbeddedPointer(RelocInfo* rinfo, |
+ Callback callback) { |
+ DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); |
+ Object* target = rinfo->target_object(); |
+ Object* old_target = target; |
+ SlotCallbackResult result = callback(&target); |
+ if (target != old_target) { |
+ rinfo->set_target_object(target); |
+ } |
+ return result; |
+} |
+ |
+// Updates a debug target slot using an untyped slot callback. |
+// The callback accepts (Heap*, Object**) and returns SlotCallbackResult. |
+template <typename Callback> |
+static SlotCallbackResult UpdateDebugTarget(RelocInfo* rinfo, |
+ Callback callback) { |
+ DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && |
+ rinfo->IsPatchedDebugBreakSlotSequence()); |
+ Object* target = Code::GetCodeFromTargetAddress(rinfo->debug_call_address()); |
+ SlotCallbackResult result = callback(&target); |
+ rinfo->set_debug_call_address(Code::cast(target)->instruction_start()); |
+ return result; |
+} |
+ |
+// Updates a typed slot using an untyped slot callback. |
+// The callback accepts (Heap*, Object**) and returns SlotCallbackResult. |
+template <typename Callback> |
+static SlotCallbackResult UpdateTypedSlot(Isolate* isolate, SlotType slot_type, |
+ Address addr, Callback callback) { |
switch (slot_type) { |
case CODE_TARGET_SLOT: { |
RelocInfo rinfo(isolate, addr, RelocInfo::CODE_TARGET, 0, NULL); |
- rinfo.Visit(isolate, v); |
- break; |
+ return UpdateCodeTarget(&rinfo, callback); |
} |
case CELL_TARGET_SLOT: { |
RelocInfo rinfo(isolate, addr, RelocInfo::CELL, 0, NULL); |
- rinfo.Visit(isolate, v); |
- break; |
+ return UpdateCell(&rinfo, callback); |
} |
case CODE_ENTRY_SLOT: { |
- v->VisitCodeEntry(addr); |
- break; |
+ return UpdateCodeEntry(addr, callback); |
} |
case DEBUG_TARGET_SLOT: { |
RelocInfo rinfo(isolate, addr, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION, 0, |
NULL); |
- if (rinfo.IsPatchedDebugBreakSlotSequence()) rinfo.Visit(isolate, v); |
- break; |
+ if (rinfo.IsPatchedDebugBreakSlotSequence()) { |
+ return UpdateDebugTarget(&rinfo, callback); |
+ } |
+ return REMOVE_SLOT; |
} |
case EMBEDDED_OBJECT_SLOT: { |
RelocInfo rinfo(isolate, addr, RelocInfo::EMBEDDED_OBJECT, 0, NULL); |
- rinfo.Visit(isolate, v); |
- break; |
+ return UpdateEmbeddedPointer(&rinfo, callback); |
} |
case OBJECT_SLOT: { |
- v->VisitPointer(reinterpret_cast<Object**>(addr)); |
- break; |
+ return callback(reinterpret_cast<Object**>(addr)); |
} |
- default: |
- UNREACHABLE(); |
+ case NUMBER_OF_SLOT_TYPES: |
break; |
} |
+ UNREACHABLE(); |
+ return REMOVE_SLOT; |
} |
@@ -2842,103 +2938,29 @@ static inline void UpdateTypedSlot(Isolate* isolate, ObjectVisitor* v, |
// It does not expect to encounter pointers to dead objects. |
class PointersUpdatingVisitor : public ObjectVisitor { |
public: |
- explicit PointersUpdatingVisitor(Heap* heap) : heap_(heap) {} |
- |
- void VisitPointer(Object** p) override { UpdatePointer(p); } |
+ void VisitPointer(Object** p) override { UpdateSlot(p); } |
void VisitPointers(Object** start, Object** end) override { |
- for (Object** p = start; p < end; p++) UpdatePointer(p); |
+ for (Object** p = start; p < end; p++) UpdateSlot(p); |
} |
- void VisitCell(RelocInfo* rinfo) override { |
- DCHECK(rinfo->rmode() == RelocInfo::CELL); |
- Object* cell = rinfo->target_cell(); |
- Object* old_cell = cell; |
- VisitPointer(&cell); |
- if (cell != old_cell) { |
- rinfo->set_target_cell(reinterpret_cast<Cell*>(cell)); |
- } |
- } |
+ void VisitCell(RelocInfo* rinfo) override { UpdateCell(rinfo, UpdateSlot); } |
void VisitEmbeddedPointer(RelocInfo* rinfo) override { |
- DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); |
- Object* target = rinfo->target_object(); |
- Object* old_target = target; |
- VisitPointer(&target); |
- // Avoid unnecessary changes that might unnecessary flush the instruction |
- // cache. |
- if (target != old_target) { |
- rinfo->set_target_object(target); |
- } |
+ UpdateEmbeddedPointer(rinfo, UpdateSlot); |
} |
void VisitCodeTarget(RelocInfo* rinfo) override { |
- DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode())); |
- Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); |
- Object* old_target = target; |
- VisitPointer(&target); |
- if (target != old_target) { |
- rinfo->set_target_address(Code::cast(target)->instruction_start()); |
- } |
- } |
- |
- void VisitCodeAgeSequence(RelocInfo* rinfo) override { |
- DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode())); |
- Object* stub = rinfo->code_age_stub(); |
- DCHECK(stub != NULL); |
- VisitPointer(&stub); |
- if (stub != rinfo->code_age_stub()) { |
- rinfo->set_code_age_stub(Code::cast(stub)); |
- } |
+ UpdateCodeTarget(rinfo, UpdateSlot); |
} |
void VisitCodeEntry(Address entry_address) override { |
- Object* code = Code::GetObjectFromEntryAddress(entry_address); |
- Object* old_code = code; |
- VisitPointer(&code); |
- if (code != old_code) { |
- Memory::Address_at(entry_address) = |
- reinterpret_cast<Code*>(code)->entry(); |
- } |
+ UpdateCodeEntry(entry_address, UpdateSlot); |
} |
void VisitDebugTarget(RelocInfo* rinfo) override { |
- DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && |
- rinfo->IsPatchedDebugBreakSlotSequence()); |
- Object* target = |
- Code::GetCodeFromTargetAddress(rinfo->debug_call_address()); |
- VisitPointer(&target); |
- rinfo->set_debug_call_address(Code::cast(target)->instruction_start()); |
- } |
- |
- static inline void UpdateSlot(Heap* heap, Object** slot) { |
- Object* obj = reinterpret_cast<Object*>( |
- base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot))); |
- |
- if (!obj->IsHeapObject()) return; |
- |
- HeapObject* heap_obj = HeapObject::cast(obj); |
- |
- MapWord map_word = heap_obj->map_word(); |
- if (map_word.IsForwardingAddress()) { |
- DCHECK(heap->InFromSpace(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), |
- reinterpret_cast<base::AtomicWord>(obj), |
- reinterpret_cast<base::AtomicWord>(target)); |
- DCHECK(!heap->InFromSpace(target) && |
- !MarkCompactCollector::IsOnEvacuationCandidate(target)); |
- } |
+ UpdateDebugTarget(rinfo, UpdateSlot); |
} |
- |
- private: |
- inline void UpdatePointer(Object** p) { UpdateSlot(heap_, p); } |
- |
- Heap* heap_; |
}; |
static String* UpdateReferenceInExternalStringTableEntry(Heap* heap, |
@@ -3629,12 +3651,12 @@ template <PointerDirection direction> |
class PointerUpdateJobTraits { |
public: |
typedef int PerPageData; // Per page data is not used in this job. |
- typedef PointersUpdatingVisitor* PerTaskData; |
+ typedef int PerTaskData; // Per task data is not used in this job. |
- static bool ProcessPageInParallel(Heap* heap, PerTaskData visitor, |
- MemoryChunk* chunk, PerPageData) { |
+ static bool ProcessPageInParallel(Heap* heap, PerTaskData, MemoryChunk* chunk, |
+ PerPageData) { |
UpdateUntypedPointers(heap, chunk); |
- UpdateTypedPointers(heap, chunk, visitor); |
+ UpdateTypedPointers(heap, chunk); |
return true; |
} |
static const bool NeedSequentialFinalization = false; |
@@ -3647,22 +3669,18 @@ class PointerUpdateJobTraits { |
RememberedSet<OLD_TO_NEW>::IterateWithWrapper(heap, chunk, |
UpdateOldToNewSlot); |
} else { |
- RememberedSet<OLD_TO_OLD>::Iterate(chunk, [heap](Address slot) { |
- PointersUpdatingVisitor::UpdateSlot(heap, |
- reinterpret_cast<Object**>(slot)); |
- return REMOVE_SLOT; |
+ RememberedSet<OLD_TO_OLD>::Iterate(chunk, [](Address slot) { |
+ return UpdateSlot(reinterpret_cast<Object**>(slot)); |
}); |
} |
} |
- static void UpdateTypedPointers(Heap* heap, MemoryChunk* chunk, |
- PointersUpdatingVisitor* visitor) { |
+ static void UpdateTypedPointers(Heap* heap, MemoryChunk* chunk) { |
if (direction == OLD_TO_OLD) { |
Isolate* isolate = heap->isolate(); |
RememberedSet<OLD_TO_OLD>::IterateTyped( |
- chunk, [isolate, visitor](SlotType type, Address slot) { |
- UpdateTypedSlot(isolate, visitor, type, slot); |
- return REMOVE_SLOT; |
+ chunk, [isolate](SlotType type, Address slot) { |
+ return UpdateTypedSlot(isolate, type, slot, UpdateSlot); |
}); |
} |
} |
@@ -3691,10 +3709,9 @@ void UpdatePointersInParallel(Heap* heap) { |
heap, heap->isolate()->cancelable_task_manager()); |
RememberedSet<direction>::IterateMemoryChunks( |
heap, [&job](MemoryChunk* chunk) { job.AddPage(chunk, 0); }); |
- PointersUpdatingVisitor visitor(heap); |
int num_pages = job.NumberOfPages(); |
int num_tasks = NumberOfPointerUpdateTasks(num_pages); |
- job.Run(num_tasks, [&visitor](int i) { return &visitor; }); |
+ job.Run(num_tasks, [](int i) { return 0; }); |
} |
class ToSpacePointerUpdateJobTraits { |
@@ -3731,7 +3748,7 @@ void UpdateToSpacePointersInParallel(Heap* heap) { |
Address end = page->Contains(space_end) ? space_end : page->area_end(); |
job.AddPage(page, std::make_pair(start, end)); |
} |
- PointersUpdatingVisitor visitor(heap); |
+ PointersUpdatingVisitor visitor; |
int num_tasks = FLAG_parallel_pointer_update ? job.NumberOfPages() : 1; |
job.Run(num_tasks, [&visitor](int i) { return &visitor; }); |
} |
@@ -3739,7 +3756,7 @@ void UpdateToSpacePointersInParallel(Heap* heap) { |
void MarkCompactCollector::UpdatePointersAfterEvacuation() { |
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS); |
- PointersUpdatingVisitor updating_visitor(heap()); |
+ PointersUpdatingVisitor updating_visitor; |
{ |
TRACE_GC(heap()->tracer(), |