[heap] Optimize migration of objects
* Better inlining * Avoid vtable lookup for visitor BUG=chromium:524425 LOG=N Review URL: https://codereview.chromium.org/1818013002 Cr-Commit-Position: refs/heads/master@{#34965}
This commit is contained in:
parent
249bf75e0c
commit
34fe5ee929
@ -1508,6 +1508,39 @@ void MarkCompactCollector::DiscoverGreyObjectsOnPage(MemoryChunk* p) {
|
||||
}
|
||||
}
|
||||
|
||||
class RecordMigratedSlotVisitor final : public ObjectVisitor {
|
||||
public:
|
||||
inline void VisitPointer(Object** p) final {
|
||||
RecordMigratedSlot(*p, reinterpret_cast<Address>(p));
|
||||
}
|
||||
|
||||
inline void VisitPointers(Object** start, Object** end) final {
|
||||
while (start < end) {
|
||||
RecordMigratedSlot(*start, reinterpret_cast<Address>(start));
|
||||
++start;
|
||||
}
|
||||
}
|
||||
|
||||
inline void VisitCodeEntry(Address code_entry_slot) final {
|
||||
Address code_entry = Memory::Address_at(code_entry_slot);
|
||||
if (Page::FromAddress(code_entry)->IsEvacuationCandidate()) {
|
||||
RememberedSet<OLD_TO_OLD>::InsertTyped(Page::FromAddress(code_entry_slot),
|
||||
CODE_ENTRY_SLOT, code_entry_slot);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
inline void RecordMigratedSlot(Object* value, Address slot) {
|
||||
if (value->IsHeapObject()) {
|
||||
Page* p = Page::FromAddress(reinterpret_cast<Address>(value));
|
||||
if (p->InNewSpace()) {
|
||||
RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot);
|
||||
} else if (p->IsEvacuationCandidate()) {
|
||||
RememberedSet<OLD_TO_OLD>::Insert(Page::FromAddress(slot), slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MarkCompactCollector::HeapObjectVisitor {
|
||||
public:
|
||||
@ -1515,32 +1548,62 @@ class MarkCompactCollector::HeapObjectVisitor {
|
||||
virtual bool Visit(HeapObject* object) = 0;
|
||||
};
|
||||
|
||||
|
||||
class MarkCompactCollector::EvacuateVisitorBase
|
||||
: public MarkCompactCollector::HeapObjectVisitor {
|
||||
public:
|
||||
EvacuateVisitorBase(Heap* heap, CompactionSpaceCollection* compaction_spaces)
|
||||
: heap_(heap), compaction_spaces_(compaction_spaces) {}
|
||||
|
||||
bool TryEvacuateObject(PagedSpace* target_space, HeapObject* object,
|
||||
HeapObject** target_object) {
|
||||
inline bool TryEvacuateObject(PagedSpace* target_space, HeapObject* object,
|
||||
HeapObject** target_object) {
|
||||
int size = object->Size();
|
||||
AllocationAlignment alignment = object->RequiredAlignment();
|
||||
AllocationResult allocation = target_space->AllocateRaw(size, alignment);
|
||||
if (allocation.To(target_object)) {
|
||||
heap_->mark_compact_collector()->MigrateObject(
|
||||
*target_object, object, size, target_space->identity());
|
||||
MigrateObject(*target_object, object, size, target_space->identity());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void MigrateObject(HeapObject* dst, HeapObject* src, int size,
|
||||
AllocationSpace dest) {
|
||||
Address dst_addr = dst->address();
|
||||
Address src_addr = src->address();
|
||||
DCHECK(heap_->AllowedToBeMigrated(src, dest));
|
||||
DCHECK(dest != LO_SPACE);
|
||||
if (dest == OLD_SPACE) {
|
||||
DCHECK_OBJECT_SIZE(size);
|
||||
DCHECK(IsAligned(size, kPointerSize));
|
||||
heap_->MoveBlock(dst_addr, src_addr, size);
|
||||
if (FLAG_ignition && dst->IsBytecodeArray()) {
|
||||
PROFILE(heap_->isolate(),
|
||||
CodeMoveEvent(AbstractCode::cast(src), dst_addr));
|
||||
}
|
||||
RecordMigratedSlotVisitor visitor;
|
||||
dst->IterateBodyFast(dst->map()->instance_type(), size, &visitor);
|
||||
} else if (dest == CODE_SPACE) {
|
||||
DCHECK_CODEOBJECT_SIZE(size, heap_->code_space());
|
||||
PROFILE(heap_->isolate(),
|
||||
CodeMoveEvent(AbstractCode::cast(src), dst_addr));
|
||||
heap_->MoveBlock(dst_addr, src_addr, size);
|
||||
RememberedSet<OLD_TO_OLD>::InsertTyped(Page::FromAddress(dst_addr),
|
||||
RELOCATED_CODE_OBJECT, dst_addr);
|
||||
Code::cast(dst)->Relocate(dst_addr - src_addr);
|
||||
} else {
|
||||
DCHECK_OBJECT_SIZE(size);
|
||||
DCHECK(dest == NEW_SPACE);
|
||||
heap_->MoveBlock(dst_addr, src_addr, size);
|
||||
}
|
||||
heap_->OnMoveEvent(dst, src, size);
|
||||
Memory::Address_at(src_addr) = dst_addr;
|
||||
}
|
||||
|
||||
protected:
|
||||
Heap* heap_;
|
||||
CompactionSpaceCollection* compaction_spaces_;
|
||||
};
|
||||
|
||||
|
||||
class MarkCompactCollector::EvacuateNewSpaceVisitor final
|
||||
: public MarkCompactCollector::EvacuateVisitorBase {
|
||||
public:
|
||||
@ -1575,8 +1638,7 @@ class MarkCompactCollector::EvacuateNewSpaceVisitor final
|
||||
}
|
||||
HeapObject* target = nullptr;
|
||||
AllocationSpace space = AllocateTargetObject(object, &target);
|
||||
heap_->mark_compact_collector()->MigrateObject(HeapObject::cast(target),
|
||||
object, size, space);
|
||||
MigrateObject(HeapObject::cast(target), object, size, space);
|
||||
if (V8_UNLIKELY(target->IsJSArrayBuffer())) {
|
||||
heap_->array_buffer_tracker()->MarkLive(JSArrayBuffer::cast(target));
|
||||
}
|
||||
@ -2556,95 +2618,6 @@ void MarkCompactCollector::RecordRelocSlot(Code* host, RelocInfo* rinfo,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class RecordMigratedSlotVisitor final : public ObjectVisitor {
|
||||
public:
|
||||
explicit RecordMigratedSlotVisitor(MarkCompactCollector* collector)
|
||||
: collector_(collector) {}
|
||||
|
||||
V8_INLINE void VisitPointer(Object** p) override {
|
||||
RecordMigratedSlot(*p, reinterpret_cast<Address>(p));
|
||||
}
|
||||
|
||||
V8_INLINE void VisitPointers(Object** start, Object** end) override {
|
||||
while (start < end) {
|
||||
RecordMigratedSlot(*start, reinterpret_cast<Address>(start));
|
||||
++start;
|
||||
}
|
||||
}
|
||||
|
||||
V8_INLINE void VisitCodeEntry(Address code_entry_slot) override {
|
||||
if (collector_->compacting_) {
|
||||
Address code_entry = Memory::Address_at(code_entry_slot);
|
||||
if (Page::FromAddress(code_entry)->IsEvacuationCandidate()) {
|
||||
RememberedSet<OLD_TO_OLD>::InsertTyped(
|
||||
Page::FromAddress(code_entry_slot), CODE_ENTRY_SLOT,
|
||||
code_entry_slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
inline void RecordMigratedSlot(Object* value, Address slot) {
|
||||
if (collector_->heap()->InNewSpace(value)) {
|
||||
RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot);
|
||||
} else if (value->IsHeapObject() &&
|
||||
Page::FromAddress(reinterpret_cast<Address>(value))
|
||||
->IsEvacuationCandidate()) {
|
||||
RememberedSet<OLD_TO_OLD>::Insert(Page::FromAddress(slot), slot);
|
||||
}
|
||||
}
|
||||
|
||||
MarkCompactCollector* collector_;
|
||||
};
|
||||
|
||||
|
||||
// We scavenge new space simultaneously with sweeping. This is done in two
|
||||
// passes.
|
||||
//
|
||||
// The first pass migrates all alive objects from one semispace to another or
|
||||
// promotes them to old space. Forwarding address is written directly into
|
||||
// first word of object without any encoding. If object is dead we write
|
||||
// NULL as a forwarding address.
|
||||
//
|
||||
// The second pass updates pointers to new space in all spaces. It is possible
|
||||
// to encounter pointers to dead new space objects during traversal of pointers
|
||||
// to new space. We should clear them to avoid encountering them during next
|
||||
// pointer iteration. This is an issue if the store buffer overflows and we
|
||||
// have to scan the entire old space, including dead objects, looking for
|
||||
// pointers to new space.
|
||||
void MarkCompactCollector::MigrateObject(HeapObject* dst, HeapObject* src,
|
||||
int size, AllocationSpace dest) {
|
||||
Address dst_addr = dst->address();
|
||||
Address src_addr = src->address();
|
||||
DCHECK(heap()->AllowedToBeMigrated(src, dest));
|
||||
DCHECK(dest != LO_SPACE);
|
||||
if (dest == OLD_SPACE) {
|
||||
DCHECK_OBJECT_SIZE(size);
|
||||
DCHECK(IsAligned(size, kPointerSize));
|
||||
|
||||
heap()->MoveBlock(dst->address(), src->address(), size);
|
||||
if (FLAG_ignition && dst->IsBytecodeArray()) {
|
||||
PROFILE(isolate(), CodeMoveEvent(AbstractCode::cast(src), dst_addr));
|
||||
}
|
||||
RecordMigratedSlotVisitor visitor(this);
|
||||
dst->IterateBody(&visitor);
|
||||
} else if (dest == CODE_SPACE) {
|
||||
DCHECK_CODEOBJECT_SIZE(size, heap()->code_space());
|
||||
PROFILE(isolate(), CodeMoveEvent(AbstractCode::cast(src), dst_addr));
|
||||
heap()->MoveBlock(dst_addr, src_addr, size);
|
||||
RememberedSet<OLD_TO_OLD>::InsertTyped(Page::FromAddress(dst_addr),
|
||||
RELOCATED_CODE_OBJECT, dst_addr);
|
||||
Code::cast(dst)->Relocate(dst_addr - src_addr);
|
||||
} else {
|
||||
DCHECK_OBJECT_SIZE(size);
|
||||
DCHECK(dest == NEW_SPACE);
|
||||
heap()->MoveBlock(dst_addr, src_addr, size);
|
||||
}
|
||||
heap()->OnMoveEvent(dst, src, size);
|
||||
Memory::Address_at(src_addr) = dst_addr;
|
||||
}
|
||||
|
||||
static inline void UpdateTypedSlot(Isolate* isolate, ObjectVisitor* v,
|
||||
SlotType slot_type, Address addr) {
|
||||
switch (slot_type) {
|
||||
|
@ -485,9 +485,6 @@ class MarkCompactCollector {
|
||||
void UpdateSlots(SlotsBuffer* buffer);
|
||||
void UpdateSlotsRecordedIn(SlotsBuffer* buffer);
|
||||
|
||||
void MigrateObject(HeapObject* dst, HeapObject* src, int size,
|
||||
AllocationSpace to_old_space);
|
||||
|
||||
void InvalidateCode(Code* code);
|
||||
|
||||
void ClearMarkbits();
|
||||
|
Loading…
Reference in New Issue
Block a user