Commit ff69ca78 authored by ahaas's avatar ahaas Committed by Commit bot

[heap] Introduce a new remembered set for typed pointers from old to new.

R=ulan@chromium.org, titzer@chromium.org

Review-Url: https://codereview.chromium.org/2003553002
Cr-Commit-Position: refs/heads/master@{#36431}
parent a7a14fde
......@@ -1672,6 +1672,15 @@ void Heap::Scavenge() {
RememberedSet<OLD_TO_NEW>::Iterate(this, [this](Address addr) {
return Scavenger::CheckAndScavengeObject(this, addr);
});
RememberedSet<OLD_TO_NEW>::IterateTyped(
this, [this](SlotType type, Address addr) {
return UpdateTypedSlotHelper::UpdateTypedSlot(
isolate(), type, addr, [this](Object** addr) {
return Scavenger::CheckAndScavengeObject(
this, reinterpret_cast<Address>(addr));
});
});
}
{
......
......@@ -2825,117 +2825,6 @@ static inline SlotCallbackResult UpdateSlot(Object** slot) {
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);
return UpdateCodeTarget(&rinfo, callback);
}
case CELL_TARGET_SLOT: {
RelocInfo rinfo(isolate, addr, RelocInfo::CELL, 0, NULL);
return UpdateCell(&rinfo, callback);
}
case CODE_ENTRY_SLOT: {
return UpdateCodeEntry(addr, callback);
}
case DEBUG_TARGET_SLOT: {
RelocInfo rinfo(isolate, addr, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION, 0,
NULL);
if (rinfo.IsPatchedDebugBreakSlotSequence()) {
return UpdateDebugTarget(&rinfo, callback);
}
return REMOVE_SLOT;
}
case EMBEDDED_OBJECT_SLOT: {
RelocInfo rinfo(isolate, addr, RelocInfo::EMBEDDED_OBJECT, 0, NULL);
return UpdateEmbeddedPointer(&rinfo, callback);
}
case OBJECT_SLOT: {
return callback(reinterpret_cast<Object**>(addr));
}
case NUMBER_OF_SLOT_TYPES:
break;
}
UNREACHABLE();
return REMOVE_SLOT;
}
// Visitor for updating pointers from live objects in old spaces to new space.
// It does not expect to encounter pointers to dead objects.
class PointersUpdatingVisitor : public ObjectVisitor {
......@@ -2946,22 +2835,24 @@ class PointersUpdatingVisitor : public ObjectVisitor {
for (Object** p = start; p < end; p++) UpdateSlot(p);
}
void VisitCell(RelocInfo* rinfo) override { UpdateCell(rinfo, UpdateSlot); }
void VisitCell(RelocInfo* rinfo) override {
UpdateTypedSlotHelper::UpdateCell(rinfo, UpdateSlot);
}
void VisitEmbeddedPointer(RelocInfo* rinfo) override {
UpdateEmbeddedPointer(rinfo, UpdateSlot);
UpdateTypedSlotHelper::UpdateEmbeddedPointer(rinfo, UpdateSlot);
}
void VisitCodeTarget(RelocInfo* rinfo) override {
UpdateCodeTarget(rinfo, UpdateSlot);
UpdateTypedSlotHelper::UpdateCodeTarget(rinfo, UpdateSlot);
}
void VisitCodeEntry(Address entry_address) override {
UpdateCodeEntry(entry_address, UpdateSlot);
UpdateTypedSlotHelper::UpdateCodeEntry(entry_address, UpdateSlot);
}
void VisitDebugTarget(RelocInfo* rinfo) override {
UpdateDebugTarget(rinfo, UpdateSlot);
UpdateTypedSlotHelper::UpdateDebugTarget(rinfo, UpdateSlot);
}
};
......@@ -3512,6 +3403,7 @@ void MarkCompactCollector::InvalidateCode(Code* code) {
Address start = code->instruction_start();
Address end = code->address() + code->Size();
RememberedSet<OLD_TO_OLD>::RemoveRangeTyped(page, start, end);
RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(page, start, end);
}
}
......@@ -3684,7 +3576,18 @@ class PointerUpdateJobTraits {
Isolate* isolate = heap->isolate();
RememberedSet<OLD_TO_OLD>::IterateTyped(
chunk, [isolate](SlotType type, Address slot) {
return UpdateTypedSlot(isolate, type, slot, UpdateSlot);
return UpdateTypedSlotHelper::UpdateTypedSlot(isolate, type, slot,
UpdateSlot);
});
} else {
Isolate* isolate = heap->isolate();
RememberedSet<OLD_TO_NEW>::IterateTyped(
chunk, [isolate, heap](SlotType type, Address slot) {
return UpdateTypedSlotHelper::UpdateTypedSlot(
isolate, type, slot, [heap](Object** slot) {
return CheckAndUpdateOldToNewSlot(
heap, reinterpret_cast<Address>(slot));
});
});
}
}
......
......@@ -5,6 +5,7 @@
#ifndef V8_REMEMBERED_SET_H
#define V8_REMEMBERED_SET_H
#include "src/assembler.h"
#include "src/heap/heap.h"
#include "src/heap/slot-set.h"
#include "src/heap/spaces.h"
......@@ -14,6 +15,7 @@ namespace internal {
enum PointerDirection { OLD_TO_OLD, OLD_TO_NEW };
// TODO(ulan): Investigate performance of de-templatizing this class.
template <PointerDirection direction>
class RememberedSet {
public:
......@@ -67,9 +69,7 @@ class RememberedSet {
// The callback should take (MemoryChunk* chunk) and return void.
template <typename Callback>
static void IterateMemoryChunks(Heap* heap, Callback callback) {
MemoryChunkIterator it(heap, direction == OLD_TO_OLD
? MemoryChunkIterator::ALL
: MemoryChunkIterator::ALL_BUT_CODE_SPACE);
MemoryChunkIterator it(heap);
MemoryChunk* chunk;
while ((chunk = it.next()) != nullptr) {
SlotSet* slots = GetSlotSet(chunk);
......@@ -101,11 +101,10 @@ class RememberedSet {
// Given a page and a typed slot in that page, this function adds the slot
// to the remembered set.
static void InsertTyped(Page* page, SlotType slot_type, Address slot_addr) {
STATIC_ASSERT(direction == OLD_TO_OLD);
TypedSlotSet* slot_set = page->typed_old_to_old_slots();
TypedSlotSet* slot_set = GetTypedSlotSet(page);
if (slot_set == nullptr) {
page->AllocateTypedOldToOldSlots();
slot_set = page->typed_old_to_old_slots();
AllocateTypedSlotSet(page);
slot_set = GetTypedSlotSet(page);
}
uintptr_t offset = slot_addr - page->address();
DCHECK_LT(offset, static_cast<uintptr_t>(TypedSlotSet::kMaxOffset));
......@@ -115,7 +114,7 @@ class RememberedSet {
// Given a page and a range of typed slots in that page, this function removes
// the slots from the remembered set.
static void RemoveRangeTyped(Page* page, Address start, Address end) {
TypedSlotSet* slots = page->typed_old_to_old_slots();
TypedSlotSet* slots = GetTypedSlotSet(page);
if (slots != nullptr) {
slots->Iterate([start, end](SlotType slot_type, Address slot_addr) {
return start <= slot_addr && slot_addr < end ? REMOVE_SLOT : KEEP_SLOT;
......@@ -123,15 +122,26 @@ class RememberedSet {
}
}
// Iterates and filters the remembered set with the given callback.
// The callback should take (SlotType slot_type, SlotAddress slot) and return
// SlotCallbackResult.
template <typename Callback>
static void IterateTyped(Heap* heap, Callback callback) {
IterateMemoryChunks(heap, [callback](MemoryChunk* chunk) {
IterateTyped(chunk, callback);
});
}
// Iterates and filters typed old to old pointers in the given memory chunk
// with the given callback. The callback should take (SlotType slot_type,
// Address slot_addr) and return SlotCallbackResult.
template <typename Callback>
static void IterateTyped(MemoryChunk* chunk, Callback callback) {
TypedSlotSet* slots = chunk->typed_old_to_old_slots();
TypedSlotSet* slots = GetTypedSlotSet(chunk);
if (slots != nullptr) {
int new_count = slots->Iterate(callback);
if (new_count == 0) {
ReleaseTypedSlotSet(chunk);
chunk->ReleaseTypedOldToOldSlots();
}
}
......@@ -140,7 +150,7 @@ class RememberedSet {
// Clear all old to old slots from the remembered set.
static void ClearAll(Heap* heap) {
STATIC_ASSERT(direction == OLD_TO_OLD);
MemoryChunkIterator it(heap, MemoryChunkIterator::ALL);
MemoryChunkIterator it(heap);
MemoryChunk* chunk;
while ((chunk = it.next()) != nullptr) {
chunk->ReleaseOldToOldSlots();
......@@ -169,7 +179,7 @@ class RememberedSet {
if (direction == OLD_TO_OLD) {
return chunk->typed_old_to_old_slots();
} else {
return nullptr;
return chunk->typed_old_to_new_slots();
}
}
......@@ -181,6 +191,14 @@ class RememberedSet {
}
}
static void ReleaseTypedSlotSet(MemoryChunk* chunk) {
if (direction == OLD_TO_OLD) {
chunk->ReleaseTypedOldToOldSlots();
} else {
chunk->ReleaseTypedOldToNewSlots();
}
}
static SlotSet* AllocateSlotSet(MemoryChunk* chunk) {
if (direction == OLD_TO_OLD) {
chunk->AllocateOldToOldSlots();
......@@ -191,9 +209,135 @@ class RememberedSet {
}
}
static TypedSlotSet* AllocateTypedSlotSet(MemoryChunk* chunk) {
if (direction == OLD_TO_OLD) {
chunk->AllocateTypedOldToOldSlots();
return chunk->typed_old_to_old_slots();
} else {
chunk->AllocateTypedOldToNewSlots();
return chunk->typed_old_to_new_slots();
}
}
static bool IsValidSlot(Heap* heap, MemoryChunk* chunk, Object** slot);
};
class UpdateTypedSlotHelper {
public:
// 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);
return UpdateCodeTarget(&rinfo, callback);
}
case CELL_TARGET_SLOT: {
RelocInfo rinfo(isolate, addr, RelocInfo::CELL, 0, NULL);
return UpdateCell(&rinfo, callback);
}
case CODE_ENTRY_SLOT: {
return UpdateCodeEntry(addr, callback);
}
case DEBUG_TARGET_SLOT: {
RelocInfo rinfo(isolate, addr, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION,
0, NULL);
if (rinfo.IsPatchedDebugBreakSlotSequence()) {
return UpdateDebugTarget(&rinfo, callback);
}
return REMOVE_SLOT;
}
case EMBEDDED_OBJECT_SLOT: {
RelocInfo rinfo(isolate, addr, RelocInfo::EMBEDDED_OBJECT, 0, NULL);
return UpdateEmbeddedPointer(&rinfo, callback);
}
case OBJECT_SLOT: {
return callback(reinterpret_cast<Object**>(addr));
}
case NUMBER_OF_SLOT_TYPES:
break;
}
UNREACHABLE();
return REMOVE_SLOT;
}
};
} // namespace internal
} // namespace v8
......
......@@ -405,9 +405,8 @@ void Page::ClearEvacuationCandidate() {
InitializeFreeListCategories();
}
MemoryChunkIterator::MemoryChunkIterator(Heap* heap, Mode mode)
MemoryChunkIterator::MemoryChunkIterator(Heap* heap)
: state_(kOldSpaceState),
mode_(mode),
old_iterator_(heap->old_space()),
code_iterator_(heap->code_space()),
map_iterator_(heap->map_space()),
......@@ -423,14 +422,14 @@ MemoryChunk* MemoryChunkIterator::next() {
// Fall through.
}
case kMapState: {
if (mode_ != ALL_BUT_MAP_SPACE && map_iterator_.has_next()) {
if (map_iterator_.has_next()) {
return map_iterator_.next();
}
state_ = kCodeState;
// Fall through.
}
case kCodeState: {
if (mode_ != ALL_BUT_CODE_SPACE && code_iterator_.has_next()) {
if (code_iterator_.has_next()) {
return code_iterator_.next();
}
state_ = kLargeObjectState;
......
......@@ -504,6 +504,7 @@ MemoryChunk* MemoryChunk::Initialize(Heap* heap, Address base, size_t size,
chunk->InitializeReservedMemory();
chunk->old_to_new_slots_ = nullptr;
chunk->old_to_old_slots_ = nullptr;
chunk->typed_old_to_new_slots_ = nullptr;
chunk->typed_old_to_old_slots_ = nullptr;
chunk->skip_list_ = nullptr;
chunk->write_barrier_counter_ = kWriteBarrierCounterGranularity;
......@@ -1036,6 +1037,8 @@ void MemoryChunk::ReleaseAllocatedMemory() {
}
if (old_to_new_slots_ != nullptr) ReleaseOldToNewSlots();
if (old_to_old_slots_ != nullptr) ReleaseOldToOldSlots();
if (typed_old_to_new_slots_ != nullptr) ReleaseTypedOldToNewSlots();
if (typed_old_to_old_slots_ != nullptr) ReleaseTypedOldToOldSlots();
}
static SlotSet* AllocateSlotSet(size_t size, Address page_start) {
......@@ -1068,6 +1071,16 @@ void MemoryChunk::ReleaseOldToOldSlots() {
old_to_old_slots_ = nullptr;
}
void MemoryChunk::AllocateTypedOldToNewSlots() {
DCHECK(nullptr == typed_old_to_new_slots_);
typed_old_to_new_slots_ = new TypedSlotSet(address());
}
void MemoryChunk::ReleaseTypedOldToNewSlots() {
delete typed_old_to_new_slots_;
typed_old_to_new_slots_ = nullptr;
}
void MemoryChunk::AllocateTypedOldToOldSlots() {
DCHECK(nullptr == typed_old_to_old_slots_);
typed_old_to_old_slots_ = new TypedSlotSet(address());
......
......@@ -509,6 +509,7 @@ class MemoryChunk {
static const size_t kWriteBarrierCounterOffset =
kOldToNewSlotsOffset + kPointerSize // SlotSet* old_to_new_slots_;
+ kPointerSize // SlotSet* old_to_old_slots_;
+ kPointerSize // TypedSlotSet* typed_old_to_new_slots_;
+ kPointerSize // TypedSlotSet* typed_old_to_old_slots_;
+ kPointerSize; // SkipList* skip_list_;
......@@ -625,6 +626,9 @@ class MemoryChunk {
inline SlotSet* old_to_new_slots() { return old_to_new_slots_; }
inline SlotSet* old_to_old_slots() { return old_to_old_slots_; }
inline TypedSlotSet* typed_old_to_new_slots() {
return typed_old_to_new_slots_;
}
inline TypedSlotSet* typed_old_to_old_slots() {
return typed_old_to_old_slots_;
}
......@@ -633,6 +637,8 @@ class MemoryChunk {
void ReleaseOldToNewSlots();
void AllocateOldToOldSlots();
void ReleaseOldToOldSlots();
void AllocateTypedOldToNewSlots();
void ReleaseTypedOldToNewSlots();
void AllocateTypedOldToOldSlots();
void ReleaseTypedOldToOldSlots();
......@@ -792,6 +798,7 @@ class MemoryChunk {
// is ceil(size() / kPageSize).
SlotSet* old_to_new_slots_;
SlotSet* old_to_old_slots_;
TypedSlotSet* typed_old_to_new_slots_;
TypedSlotSet* typed_old_to_old_slots_;
SkipList* skip_list_;
......@@ -3111,8 +3118,7 @@ class LargePageIterator BASE_EMBEDDED {
// pointers to new space or to evacuation candidates.
class MemoryChunkIterator BASE_EMBEDDED {
public:
enum Mode { ALL, ALL_BUT_MAP_SPACE, ALL_BUT_CODE_SPACE };
inline explicit MemoryChunkIterator(Heap* heap, Mode mode);
inline explicit MemoryChunkIterator(Heap* heap);
// Return NULL when the iterator is done.
inline MemoryChunk* next();
......@@ -3126,7 +3132,6 @@ class MemoryChunkIterator BASE_EMBEDDED {
kFinishedState
};
State state_;
const Mode mode_;
PageIterator old_iterator_;
PageIterator code_iterator_;
PageIterator map_iterator_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment