OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef V8_REMEMBERED_SET_H | |
6 #define V8_REMEMBERED_SET_H | |
7 | |
8 #include "src/heap/heap.h" | |
9 #include "src/heap/slot-set.h" | |
10 #include "src/heap/spaces.h" | |
11 | |
12 namespace v8 { | |
13 namespace internal { | |
14 | |
15 enum PointerDirection { OLD_TO_OLD, OLD_TO_NEW }; | |
16 | |
17 template <PointerDirection direction> | |
18 class RememberedSet { | |
19 public: | |
20 // Given a page and a slot in that page, this function adds the slot to the | |
21 // remembered set. | |
22 static void Insert(Page* page, Address slot_addr) { | |
23 DCHECK(page->Contains(slot_addr)); | |
Hannes Payer (out of office)
2016/02/15 16:53:39
You can drop the DCHECK if you move the page looku
| |
24 SlotSet* slot_set = GetSlotSet(page); | |
25 if (slot_set == nullptr) { | |
26 slot_set = AllocateSlotSet(page); | |
27 } | |
28 uintptr_t offset = slot_addr - page->address(); | |
29 slot_set[offset / Page::kPageSize].Insert(offset % Page::kPageSize); | |
30 } | |
31 | |
32 // Given a page and a slot in that page, this function removes the slot from | |
33 // the remembered set. | |
34 // If the slot was never added, then the function does nothing. | |
35 static void Remove(Page* page, Address slot_addr) { | |
36 DCHECK(page->Contains(slot_addr)); | |
Hannes Payer (out of office)
2016/02/15 16:53:38
You can drop the DCHECK if you move the page looku
| |
37 SlotSet* slot_set = GetSlotSet(page); | |
38 if (slot_set != nullptr) { | |
39 uintptr_t offset = slot_addr - page->address(); | |
40 slot_set[offset / Page::kPageSize].Remove(offset % Page::kPageSize); | |
41 } | |
42 } | |
43 | |
44 // Iterates and filters the remembered set with the given callback. | |
45 // The callback should take (Address slot) and return SlotSet::CallbackResult. | |
46 template <typename Callback> | |
47 static void Iterate(Heap* heap, Callback callback) { | |
48 PointerChunkIterator it(heap); | |
49 MemoryChunk* chunk; | |
50 while ((chunk = it.next()) != nullptr) { | |
51 SlotSet* slots = GetSlotSet(chunk); | |
52 if (slots != nullptr) { | |
53 size_t pages = (chunk->size() + Page::kPageSize - 1) / Page::kPageSize; | |
54 int new_count = 0; | |
55 for (size_t page = 0; page < pages; page++) { | |
56 new_count += slots[page].Iterate(callback); | |
57 } | |
58 if (new_count == 0) { | |
59 ReleaseSlotSet(chunk); | |
60 } | |
61 } | |
62 } | |
63 } | |
64 | |
65 // Iterates and filters the remembered set with the given callback. | |
66 // The callback should take (HeapObject** slot, HeapObject* target) and | |
67 // update the slot. | |
68 // A special wrapper takes care of filtering the slots based on their values. | |
69 // For OLD_TO_NEW case: slots that do not point to the ToSpace after | |
70 // callback invocation will be removed from the set. | |
71 template <typename Callback> | |
72 static void IterateWithWrapper(Heap* heap, Callback callback) { | |
73 Iterate(heap, [heap, callback](Address addr) { | |
74 return Wrapper(heap, addr, callback); | |
75 }); | |
76 } | |
77 | |
78 // Eliminates all stale slots from the remembered set, i.e. | |
79 // slots that are not part of live objects anymore. This method must be | |
80 // called after marking, when the whole transitive closure is known and | |
81 // must be called before sweeping when mark bits are still intact. | |
82 static void ClearInvalidSlots(Heap* heap); | |
83 | |
84 static void VerifyValidSlots(Heap* heap); | |
85 | |
86 private: | |
87 static SlotSet* GetSlotSet(MemoryChunk* chunk) { | |
88 if (direction == OLD_TO_OLD) { | |
89 return chunk->old_to_old_slots(); | |
90 } else { | |
91 return chunk->old_to_new_slots(); | |
92 } | |
93 } | |
94 | |
95 static void ReleaseSlotSet(MemoryChunk* chunk) { | |
96 if (direction == OLD_TO_OLD) { | |
97 chunk->ReleaseOldToOldSlots(); | |
98 } else { | |
99 chunk->ReleaseOldToNewSlots(); | |
100 } | |
101 } | |
102 | |
103 static SlotSet* AllocateSlotSet(MemoryChunk* chunk) { | |
104 if (direction == OLD_TO_OLD) { | |
105 chunk->AllocateOldToOldSlots(); | |
106 return chunk->old_to_old_slots(); | |
107 } else { | |
108 chunk->AllocateOldToNewSlots(); | |
109 return chunk->old_to_new_slots(); | |
110 } | |
111 } | |
112 | |
113 template <typename Callback> | |
114 static SlotSet::CallbackResult Wrapper(Heap* heap, Address slot_address, | |
115 Callback slot_callback) { | |
116 STATIC_ASSERT(direction == OLD_TO_NEW); | |
117 Object** slot = reinterpret_cast<Object**>(slot_address); | |
118 Object* object = *slot; | |
119 if (heap->InFromSpace(object)) { | |
120 HeapObject* heap_object = reinterpret_cast<HeapObject*>(object); | |
121 DCHECK(heap_object->IsHeapObject()); | |
122 slot_callback(reinterpret_cast<HeapObject**>(slot), heap_object); | |
123 object = *slot; | |
124 // If the object was in from space before and is after executing the | |
125 // callback in to space, the object is still live. | |
126 // Unfortunately, we do not know about the slot. It could be in a | |
127 // just freed free space object. | |
128 if (heap->InToSpace(object)) { | |
129 return SlotSet::KEEP_SLOT; | |
130 } | |
131 } else { | |
132 DCHECK(!heap->InNewSpace(object)); | |
133 } | |
134 return SlotSet::REMOVE_SLOT; | |
135 } | |
136 | |
137 static bool IsValidSlot(Heap* heap, Object** slot); | |
138 }; | |
139 | |
140 } // namespace internal | |
141 } // namespace v8 | |
142 | |
143 #endif // V8_REMEMBERED_SET_H | |
OLD | NEW |