| Index: src/heap/remembered-set.h
|
| diff --git a/src/heap/remembered-set.h b/src/heap/remembered-set.h
|
| index 801bdbfe8dd5f4b25e60817333549424863e28e0..548e4d4554c330bc9d71614e677a4dd8f0e3706c 100644
|
| --- a/src/heap/remembered-set.h
|
| +++ b/src/heap/remembered-set.h
|
| @@ -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
|
|
|
|
|