OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_REMEMBERED_SET_H | 5 #ifndef V8_REMEMBERED_SET_H |
6 #define V8_REMEMBERED_SET_H | 6 #define V8_REMEMBERED_SET_H |
7 | 7 |
8 #include "src/assembler.h" | |
8 #include "src/heap/heap.h" | 9 #include "src/heap/heap.h" |
9 #include "src/heap/slot-set.h" | 10 #include "src/heap/slot-set.h" |
10 #include "src/heap/spaces.h" | 11 #include "src/heap/spaces.h" |
11 | 12 |
12 namespace v8 { | 13 namespace v8 { |
13 namespace internal { | 14 namespace internal { |
14 | 15 |
15 enum PointerDirection { OLD_TO_OLD, OLD_TO_NEW }; | 16 enum PointerDirection { OLD_TO_OLD, OLD_TO_NEW }; |
16 | 17 |
17 template <PointerDirection direction> | 18 template <PointerDirection direction> |
titzer
2016/05/20 11:47:36
(meta question)
Does this class really need to be
ulan
2016/05/20 12:48:12
Insertion is performance critical. Run-time check
ahaas
2016/05/20 13:20:16
Done.
| |
18 class RememberedSet { | 19 class RememberedSet { |
19 public: | 20 public: |
20 // Given a page and a slot in that page, this function adds the slot to the | 21 // Given a page and a slot in that page, this function adds the slot to the |
21 // remembered set. | 22 // remembered set. |
22 static void Insert(Page* page, Address slot_addr) { | 23 static void Insert(Page* page, Address slot_addr) { |
23 DCHECK(page->Contains(slot_addr)); | 24 DCHECK(page->Contains(slot_addr)); |
24 SlotSet* slot_set = GetSlotSet(page); | 25 SlotSet* slot_set = GetSlotSet(page); |
25 if (slot_set == nullptr) { | 26 if (slot_set == nullptr) { |
26 slot_set = AllocateSlotSet(page); | 27 slot_set = AllocateSlotSet(page); |
27 } | 28 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
60 template <typename Callback> | 61 template <typename Callback> |
61 static void Iterate(Heap* heap, Callback callback) { | 62 static void Iterate(Heap* heap, Callback callback) { |
62 IterateMemoryChunks( | 63 IterateMemoryChunks( |
63 heap, [callback](MemoryChunk* chunk) { Iterate(chunk, callback); }); | 64 heap, [callback](MemoryChunk* chunk) { Iterate(chunk, callback); }); |
64 } | 65 } |
65 | 66 |
66 // Iterates over all memory chunks that contains non-empty slot sets. | 67 // Iterates over all memory chunks that contains non-empty slot sets. |
67 // The callback should take (MemoryChunk* chunk) and return void. | 68 // The callback should take (MemoryChunk* chunk) and return void. |
68 template <typename Callback> | 69 template <typename Callback> |
69 static void IterateMemoryChunks(Heap* heap, Callback callback) { | 70 static void IterateMemoryChunks(Heap* heap, Callback callback) { |
70 MemoryChunkIterator it(heap, direction == OLD_TO_OLD | 71 MemoryChunkIterator it(heap); |
71 ? MemoryChunkIterator::ALL | |
72 : MemoryChunkIterator::ALL_BUT_CODE_SPACE); | |
73 MemoryChunk* chunk; | 72 MemoryChunk* chunk; |
74 while ((chunk = it.next()) != nullptr) { | 73 while ((chunk = it.next()) != nullptr) { |
75 SlotSet* slots = GetSlotSet(chunk); | 74 SlotSet* slots = GetSlotSet(chunk); |
76 TypedSlotSet* typed_slots = GetTypedSlotSet(chunk); | 75 TypedSlotSet* typed_slots = GetTypedSlotSet(chunk); |
77 if (slots != nullptr || typed_slots != nullptr) { | 76 if (slots != nullptr || typed_slots != nullptr) { |
78 callback(chunk); | 77 callback(chunk); |
79 } | 78 } |
80 } | 79 } |
81 } | 80 } |
82 | 81 |
(...skipping 11 matching lines...) Expand all Loading... | |
94 } | 93 } |
95 if (new_count == 0) { | 94 if (new_count == 0) { |
96 ReleaseSlotSet(chunk); | 95 ReleaseSlotSet(chunk); |
97 } | 96 } |
98 } | 97 } |
99 } | 98 } |
100 | 99 |
101 // Given a page and a typed slot in that page, this function adds the slot | 100 // Given a page and a typed slot in that page, this function adds the slot |
102 // to the remembered set. | 101 // to the remembered set. |
103 static void InsertTyped(Page* page, SlotType slot_type, Address slot_addr) { | 102 static void InsertTyped(Page* page, SlotType slot_type, Address slot_addr) { |
104 STATIC_ASSERT(direction == OLD_TO_OLD); | 103 TypedSlotSet* slot_set = GetTypedSlotSet(page); |
105 TypedSlotSet* slot_set = page->typed_old_to_old_slots(); | |
106 if (slot_set == nullptr) { | 104 if (slot_set == nullptr) { |
107 page->AllocateTypedOldToOldSlots(); | 105 AllocateTypedSlotSet(page); |
108 slot_set = page->typed_old_to_old_slots(); | 106 slot_set = GetTypedSlotSet(page); |
109 } | 107 } |
110 uintptr_t offset = slot_addr - page->address(); | 108 uintptr_t offset = slot_addr - page->address(); |
111 DCHECK_LT(offset, static_cast<uintptr_t>(TypedSlotSet::kMaxOffset)); | 109 DCHECK_LT(offset, static_cast<uintptr_t>(TypedSlotSet::kMaxOffset)); |
112 slot_set->Insert(slot_type, static_cast<uint32_t>(offset)); | 110 slot_set->Insert(slot_type, static_cast<uint32_t>(offset)); |
113 } | 111 } |
114 | 112 |
115 // Given a page and a range of typed slots in that page, this function removes | 113 // Given a page and a range of typed slots in that page, this function removes |
116 // the slots from the remembered set. | 114 // the slots from the remembered set. |
117 static void RemoveRangeTyped(Page* page, Address start, Address end) { | 115 static void RemoveRangeTyped(Page* page, Address start, Address end) { |
118 TypedSlotSet* slots = page->typed_old_to_old_slots(); | 116 TypedSlotSet* slots = GetTypedSlotSet(page); |
119 if (slots != nullptr) { | 117 if (slots != nullptr) { |
120 slots->Iterate([start, end](SlotType slot_type, Address slot_addr) { | 118 slots->Iterate([start, end](SlotType slot_type, Address slot_addr) { |
121 return start <= slot_addr && slot_addr < end ? REMOVE_SLOT : KEEP_SLOT; | 119 return start <= slot_addr && slot_addr < end ? REMOVE_SLOT : KEEP_SLOT; |
122 }); | 120 }); |
123 } | 121 } |
124 } | 122 } |
125 | 123 |
124 // Iterates and filters the remembered set with the given callback. | |
125 // The callback should take (SlotType slot_type, SlotAddress slot) and return | |
126 // SlotCallbackResult. | |
127 template <typename Callback> | |
128 static void IterateTyped(Heap* heap, Callback callback) { | |
129 IterateMemoryChunks(heap, [callback](MemoryChunk* chunk) { | |
130 IterateTyped(chunk, callback); | |
131 }); | |
132 } | |
133 | |
126 // Iterates and filters typed old to old pointers in the given memory chunk | 134 // Iterates and filters typed old to old pointers in the given memory chunk |
127 // with the given callback. The callback should take (SlotType slot_type, | 135 // with the given callback. The callback should take (SlotType slot_type, |
128 // Address slot_addr) and return SlotCallbackResult. | 136 // Address slot_addr) and return SlotCallbackResult. |
129 template <typename Callback> | 137 template <typename Callback> |
130 static void IterateTyped(MemoryChunk* chunk, Callback callback) { | 138 static void IterateTyped(MemoryChunk* chunk, Callback callback) { |
131 TypedSlotSet* slots = chunk->typed_old_to_old_slots(); | 139 TypedSlotSet* slots = GetTypedSlotSet(chunk); |
132 if (slots != nullptr) { | 140 if (slots != nullptr) { |
133 int new_count = slots->Iterate(callback); | 141 int new_count = slots->Iterate(callback); |
134 if (new_count == 0) { | 142 if (new_count == 0) { |
143 ReleaseTypedSlotSet(chunk); | |
135 chunk->ReleaseTypedOldToOldSlots(); | 144 chunk->ReleaseTypedOldToOldSlots(); |
136 } | 145 } |
137 } | 146 } |
138 } | 147 } |
139 | 148 |
140 // Clear all old to old slots from the remembered set. | 149 // Clear all old to old slots from the remembered set. |
141 static void ClearAll(Heap* heap) { | 150 static void ClearAll(Heap* heap) { |
142 STATIC_ASSERT(direction == OLD_TO_OLD); | 151 STATIC_ASSERT(direction == OLD_TO_OLD); |
143 MemoryChunkIterator it(heap, MemoryChunkIterator::ALL); | 152 MemoryChunkIterator it(heap); |
144 MemoryChunk* chunk; | 153 MemoryChunk* chunk; |
145 while ((chunk = it.next()) != nullptr) { | 154 while ((chunk = it.next()) != nullptr) { |
146 chunk->ReleaseOldToOldSlots(); | 155 chunk->ReleaseOldToOldSlots(); |
147 chunk->ReleaseTypedOldToOldSlots(); | 156 chunk->ReleaseTypedOldToOldSlots(); |
148 } | 157 } |
149 } | 158 } |
150 | 159 |
151 // Eliminates all stale slots from the remembered set, i.e. | 160 // Eliminates all stale slots from the remembered set, i.e. |
152 // slots that are not part of live objects anymore. This method must be | 161 // slots that are not part of live objects anymore. This method must be |
153 // called after marking, when the whole transitive closure is known and | 162 // called after marking, when the whole transitive closure is known and |
154 // must be called before sweeping when mark bits are still intact. | 163 // must be called before sweeping when mark bits are still intact. |
155 static void ClearInvalidSlots(Heap* heap); | 164 static void ClearInvalidSlots(Heap* heap); |
156 | 165 |
157 static void VerifyValidSlots(Heap* heap); | 166 static void VerifyValidSlots(Heap* heap); |
158 | 167 |
159 private: | 168 private: |
160 static SlotSet* GetSlotSet(MemoryChunk* chunk) { | 169 static SlotSet* GetSlotSet(MemoryChunk* chunk) { |
161 if (direction == OLD_TO_OLD) { | 170 if (direction == OLD_TO_OLD) { |
162 return chunk->old_to_old_slots(); | 171 return chunk->old_to_old_slots(); |
163 } else { | 172 } else { |
164 return chunk->old_to_new_slots(); | 173 return chunk->old_to_new_slots(); |
165 } | 174 } |
166 } | 175 } |
167 | 176 |
168 static TypedSlotSet* GetTypedSlotSet(MemoryChunk* chunk) { | 177 static TypedSlotSet* GetTypedSlotSet(MemoryChunk* chunk) { |
169 if (direction == OLD_TO_OLD) { | 178 if (direction == OLD_TO_OLD) { |
170 return chunk->typed_old_to_old_slots(); | 179 return chunk->typed_old_to_old_slots(); |
171 } else { | 180 } else { |
172 return nullptr; | 181 return chunk->typed_old_to_new_slots(); |
173 } | 182 } |
174 } | 183 } |
175 | 184 |
176 static void ReleaseSlotSet(MemoryChunk* chunk) { | 185 static void ReleaseSlotSet(MemoryChunk* chunk) { |
177 if (direction == OLD_TO_OLD) { | 186 if (direction == OLD_TO_OLD) { |
178 chunk->ReleaseOldToOldSlots(); | 187 chunk->ReleaseOldToOldSlots(); |
179 } else { | 188 } else { |
180 chunk->ReleaseOldToNewSlots(); | 189 chunk->ReleaseOldToNewSlots(); |
181 } | 190 } |
182 } | 191 } |
183 | 192 |
193 static void ReleaseTypedSlotSet(MemoryChunk* chunk) { | |
194 if (direction == OLD_TO_OLD) { | |
195 chunk->ReleaseTypedOldToOldSlots(); | |
196 } else { | |
197 chunk->ReleaseTypedOldToNewSlots(); | |
198 } | |
199 } | |
200 | |
184 static SlotSet* AllocateSlotSet(MemoryChunk* chunk) { | 201 static SlotSet* AllocateSlotSet(MemoryChunk* chunk) { |
185 if (direction == OLD_TO_OLD) { | 202 if (direction == OLD_TO_OLD) { |
186 chunk->AllocateOldToOldSlots(); | 203 chunk->AllocateOldToOldSlots(); |
187 return chunk->old_to_old_slots(); | 204 return chunk->old_to_old_slots(); |
188 } else { | 205 } else { |
189 chunk->AllocateOldToNewSlots(); | 206 chunk->AllocateOldToNewSlots(); |
190 return chunk->old_to_new_slots(); | 207 return chunk->old_to_new_slots(); |
191 } | 208 } |
192 } | 209 } |
193 | 210 |
211 static TypedSlotSet* AllocateTypedSlotSet(MemoryChunk* chunk) { | |
212 if (direction == OLD_TO_OLD) { | |
213 chunk->AllocateTypedOldToOldSlots(); | |
214 return chunk->typed_old_to_old_slots(); | |
215 } else { | |
216 chunk->AllocateTypedOldToNewSlots(); | |
217 return chunk->typed_old_to_new_slots(); | |
218 } | |
219 } | |
220 | |
194 static bool IsValidSlot(Heap* heap, MemoryChunk* chunk, Object** slot); | 221 static bool IsValidSlot(Heap* heap, MemoryChunk* chunk, Object** slot); |
195 }; | 222 }; |
196 | 223 |
224 class UpdateTypedSlotHelper { | |
225 public: | |
226 // Updates a cell slot using an untyped slot callback. | |
227 // The callback accepts (Heap*, Object**) and returns SlotCallbackResult. | |
228 template <typename Callback> | |
229 static SlotCallbackResult UpdateCell(RelocInfo* rinfo, Callback callback) { | |
230 DCHECK(rinfo->rmode() == RelocInfo::CELL); | |
231 Object* cell = rinfo->target_cell(); | |
232 Object* old_cell = cell; | |
233 SlotCallbackResult result = callback(&cell); | |
234 if (cell != old_cell) { | |
235 rinfo->set_target_cell(reinterpret_cast<Cell*>(cell)); | |
236 } | |
237 return result; | |
238 } | |
239 | |
240 // Updates a code entry slot using an untyped slot callback. | |
241 // The callback accepts (Heap*, Object**) and returns SlotCallbackResult. | |
242 template <typename Callback> | |
243 static SlotCallbackResult UpdateCodeEntry(Address entry_address, | |
244 Callback callback) { | |
245 Object* code = Code::GetObjectFromEntryAddress(entry_address); | |
246 Object* old_code = code; | |
247 SlotCallbackResult result = callback(&code); | |
248 if (code != old_code) { | |
249 Memory::Address_at(entry_address) = | |
250 reinterpret_cast<Code*>(code)->entry(); | |
251 } | |
252 return result; | |
253 } | |
254 | |
255 // Updates a code target slot using an untyped slot callback. | |
256 // The callback accepts (Heap*, Object**) and returns SlotCallbackResult. | |
257 template <typename Callback> | |
258 static SlotCallbackResult UpdateCodeTarget(RelocInfo* rinfo, | |
259 Callback callback) { | |
260 DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode())); | |
261 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); | |
262 Object* old_target = target; | |
263 SlotCallbackResult result = callback(&target); | |
264 if (target != old_target) { | |
265 rinfo->set_target_address(Code::cast(target)->instruction_start()); | |
266 } | |
267 return result; | |
268 } | |
269 | |
270 // Updates an embedded pointer slot using an untyped slot callback. | |
271 // The callback accepts (Heap*, Object**) and returns SlotCallbackResult. | |
272 template <typename Callback> | |
273 static SlotCallbackResult UpdateEmbeddedPointer(RelocInfo* rinfo, | |
274 Callback callback) { | |
275 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); | |
276 Object* target = rinfo->target_object(); | |
277 Object* old_target = target; | |
278 SlotCallbackResult result = callback(&target); | |
279 if (target != old_target) { | |
280 rinfo->set_target_object(target); | |
281 } | |
282 return result; | |
283 } | |
284 | |
285 // Updates a debug target slot using an untyped slot callback. | |
286 // The callback accepts (Heap*, Object**) and returns SlotCallbackResult. | |
287 template <typename Callback> | |
288 static SlotCallbackResult UpdateDebugTarget(RelocInfo* rinfo, | |
289 Callback callback) { | |
290 DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && | |
291 rinfo->IsPatchedDebugBreakSlotSequence()); | |
292 Object* target = | |
293 Code::GetCodeFromTargetAddress(rinfo->debug_call_address()); | |
294 SlotCallbackResult result = callback(&target); | |
295 rinfo->set_debug_call_address(Code::cast(target)->instruction_start()); | |
296 return result; | |
297 } | |
298 | |
299 // Updates a typed slot using an untyped slot callback. | |
300 // The callback accepts (Heap*, Object**) and returns SlotCallbackResult. | |
301 template <typename Callback> | |
302 static SlotCallbackResult UpdateTypedSlot(Isolate* isolate, | |
303 SlotType slot_type, Address addr, | |
304 Callback callback) { | |
305 switch (slot_type) { | |
306 case CODE_TARGET_SLOT: { | |
307 RelocInfo rinfo(isolate, addr, RelocInfo::CODE_TARGET, 0, NULL); | |
308 return UpdateCodeTarget(&rinfo, callback); | |
309 } | |
310 case CELL_TARGET_SLOT: { | |
311 RelocInfo rinfo(isolate, addr, RelocInfo::CELL, 0, NULL); | |
312 return UpdateCell(&rinfo, callback); | |
313 } | |
314 case CODE_ENTRY_SLOT: { | |
315 return UpdateCodeEntry(addr, callback); | |
316 } | |
317 case DEBUG_TARGET_SLOT: { | |
318 RelocInfo rinfo(isolate, addr, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION, | |
319 0, NULL); | |
320 if (rinfo.IsPatchedDebugBreakSlotSequence()) { | |
321 return UpdateDebugTarget(&rinfo, callback); | |
322 } | |
323 return REMOVE_SLOT; | |
324 } | |
325 case EMBEDDED_OBJECT_SLOT: { | |
326 RelocInfo rinfo(isolate, addr, RelocInfo::EMBEDDED_OBJECT, 0, NULL); | |
327 return UpdateEmbeddedPointer(&rinfo, callback); | |
328 } | |
329 case OBJECT_SLOT: { | |
330 return callback(reinterpret_cast<Object**>(addr)); | |
331 } | |
332 case NUMBER_OF_SLOT_TYPES: | |
333 break; | |
334 } | |
335 UNREACHABLE(); | |
336 return REMOVE_SLOT; | |
337 } | |
338 }; | |
339 | |
197 } // namespace internal | 340 } // namespace internal |
198 } // namespace v8 | 341 } // namespace v8 |
199 | 342 |
200 #endif // V8_REMEMBERED_SET_H | 343 #endif // V8_REMEMBERED_SET_H |
OLD | NEW |