Index: src/heap/remembered-set.h |
diff --git a/src/heap/remembered-set.h b/src/heap/remembered-set.h |
index 351d76edb84c18706da7fede9003948d75562a59..1b866d120679e2477afb3abf8019d0e1e1980950 100644 |
--- a/src/heap/remembered-set.h |
+++ b/src/heap/remembered-set.h |
@@ -56,10 +56,12 @@ class RememberedSet { |
} |
// Iterates and filters the remembered set with the given callback. |
- // The callback should take (Address slot) and return SlotSet::CallbackResult. |
+ // The callback should take (Address slot) and return SlotCallbackResult. |
template <typename Callback> |
static void Iterate(Heap* heap, Callback callback) { |
- PointerChunkIterator it(heap); |
+ MemoryChunkIterator it(heap, direction == OLD_TO_OLD |
+ ? MemoryChunkIterator::ALL |
+ : MemoryChunkIterator::ALL_BUT_CODE_SPACE); |
MemoryChunk* chunk; |
while ((chunk = it.next()) != nullptr) { |
SlotSet* slots = GetSlotSet(chunk); |
@@ -89,6 +91,60 @@ 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(); |
+ if (slot_set == nullptr) { |
+ page->AllocateTypedOldToOldSlots(); |
+ slot_set = page->typed_old_to_old_slots(); |
+ } |
+ uintptr_t offset = slot_addr - page->address(); |
+ DCHECK_LT(offset, static_cast<uintptr_t>(TypedSlotSet::kMaxOffset)); |
+ slot_set->Insert(slot_type, static_cast<uint32_t>(offset)); |
+ } |
+ |
+ // 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(); |
+ if (slots != nullptr) { |
+ slots->Iterate([start, end](SlotType slot_type, Address slot_addr) { |
+ return start <= slot_addr && slot_addr < end ? REMOVE_SLOT : KEEP_SLOT; |
+ }); |
+ } |
+ } |
+ |
+ // Iterates and filters typed old to old pointers with the given callback. |
+ // The callback should take (SlotType slot_type, Address slot_addr) and |
+ // return SlotCallbackResult. |
+ template <typename Callback> |
+ static void IterateTyped(Heap* heap, Callback callback) { |
+ MemoryChunkIterator it(heap, MemoryChunkIterator::ALL_BUT_MAP_SPACE); |
+ MemoryChunk* chunk; |
+ while ((chunk = it.next()) != nullptr) { |
+ TypedSlotSet* slots = chunk->typed_old_to_old_slots(); |
+ if (slots != nullptr) { |
+ int new_count = slots->Iterate(callback); |
+ if (new_count == 0) { |
+ chunk->ReleaseTypedOldToOldSlots(); |
+ } |
+ } |
+ } |
+ } |
+ |
+ // 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); |
+ MemoryChunk* chunk; |
+ while ((chunk = it.next()) != nullptr) { |
+ chunk->ReleaseOldToOldSlots(); |
+ chunk->ReleaseTypedOldToOldSlots(); |
+ } |
+ } |
+ |
// Eliminates all stale slots from the remembered set, i.e. |
// slots that are not part of live objects anymore. This method must be |
// called after marking, when the whole transitive closure is known and |
@@ -125,8 +181,8 @@ class RememberedSet { |
} |
template <typename Callback> |
- static SlotSet::CallbackResult Wrapper(Heap* heap, Address slot_address, |
- Callback slot_callback) { |
+ static SlotCallbackResult Wrapper(Heap* heap, Address slot_address, |
+ Callback slot_callback) { |
STATIC_ASSERT(direction == OLD_TO_NEW); |
Object** slot = reinterpret_cast<Object**>(slot_address); |
Object* object = *slot; |
@@ -140,17 +196,97 @@ class RememberedSet { |
// Unfortunately, we do not know about the slot. It could be in a |
// just freed free space object. |
if (heap->InToSpace(object)) { |
- return SlotSet::KEEP_SLOT; |
+ return KEEP_SLOT; |
} |
} else { |
DCHECK(!heap->InNewSpace(object)); |
} |
- return SlotSet::REMOVE_SLOT; |
+ return REMOVE_SLOT; |
} |
static bool IsValidSlot(Heap* heap, Object** slot); |
}; |
+// Buffer for keeping thead local migration slots during compaction. |
+// TODO(ulan): Remove this once every thread gets local pages in compaction |
+// space. |
+class LocalSlotsBuffer BASE_EMBEDDED { |
+ public: |
+ LocalSlotsBuffer() : top_(new Node(nullptr)) {} |
+ |
+ ~LocalSlotsBuffer() { |
+ Node* current = top_; |
+ while (current != nullptr) { |
+ Node* tmp = current->next; |
+ delete current; |
+ current = tmp; |
+ } |
+ } |
+ |
+ void Record(Address addr) { |
+ EnsureSpaceFor(1); |
+ uintptr_t entry = reinterpret_cast<uintptr_t>(addr); |
+ DCHECK_GE(entry, static_cast<uintptr_t>(NUMBER_OF_SLOT_TYPES)); |
+ Insert(entry); |
+ } |
+ |
+ void Record(SlotType type, Address addr) { |
+ EnsureSpaceFor(2); |
+ Insert(static_cast<uintptr_t>(type)); |
+ uintptr_t entry = reinterpret_cast<uintptr_t>(addr); |
+ DCHECK_GE(entry, static_cast<uintptr_t>(NUMBER_OF_SLOT_TYPES)); |
+ Insert(entry); |
+ } |
+ |
+ template <typename UntypedCallback, typename TypedCallback> |
+ void Iterate(UntypedCallback untyped_callback, TypedCallback typed_callback) { |
+ Node* current = top_; |
+ bool typed = false; |
+ SlotType type; |
+ Address addr; |
+ while (current != nullptr) { |
+ for (int i = 0; i < current->count; i++) { |
+ uintptr_t entry = current->buffer[i]; |
+ if (entry < NUMBER_OF_SLOT_TYPES) { |
+ DCHECK(!typed); |
+ typed = true; |
+ type = static_cast<SlotType>(entry); |
+ } else { |
+ addr = reinterpret_cast<Address>(entry); |
+ if (typed) { |
+ typed_callback(type, addr); |
+ typed = false; |
+ } else { |
+ untyped_callback(addr); |
+ } |
+ } |
+ } |
+ current = current->next; |
+ } |
+ } |
+ |
+ private: |
+ void EnsureSpaceFor(int count) { |
+ if (top_->remaining_free_slots() < count) top_ = new Node(top_); |
+ } |
+ |
+ void Insert(uintptr_t entry) { top_->buffer[top_->count++] = entry; } |
+ |
+ static const int kBufferSize = 16 * KB; |
+ |
+ struct Node : Malloced { |
+ explicit Node(Node* next_node) : next(next_node), count(0) {} |
+ |
+ inline int remaining_free_slots() { return kBufferSize - count; } |
+ |
+ Node* next; |
+ uintptr_t buffer[kBufferSize]; |
+ int count; |
+ }; |
+ |
+ Node* top_; |
+}; |
+ |
} // namespace internal |
} // namespace v8 |