Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: src/heap/remembered-set.h

Issue 2783873002: [heap] Reland: Make SlotSet allocation thread-safe and refactor code. (Closed)
Patch Set: comment Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/heap/mark-compact.cc ('k') | src/heap/spaces.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/assembler.h"
9 #include "src/heap/heap.h" 9 #include "src/heap/heap.h"
10 #include "src/heap/slot-set.h" 10 #include "src/heap/slot-set.h"
11 #include "src/heap/spaces.h" 11 #include "src/heap/spaces.h"
12 12
13 namespace v8 { 13 namespace v8 {
14 namespace internal { 14 namespace internal {
15 15
16 enum PointerDirection { OLD_TO_OLD, OLD_TO_NEW };
17
18 // TODO(ulan): Investigate performance of de-templatizing this class. 16 // TODO(ulan): Investigate performance of de-templatizing this class.
19 template <PointerDirection direction> 17 template <RememberedSetType type>
20 class RememberedSet : public AllStatic { 18 class RememberedSet : public AllStatic {
21 public: 19 public:
22 // Given a page and a slot in that page, this function adds the slot to the 20 // Given a page and a slot in that page, this function adds the slot to the
23 // remembered set. 21 // remembered set.
24 static void Insert(MemoryChunk* chunk, Address slot_addr) { 22 static void Insert(MemoryChunk* chunk, Address slot_addr) {
25 DCHECK(chunk->Contains(slot_addr)); 23 DCHECK(chunk->Contains(slot_addr));
26 SlotSet* slot_set = GetSlotSet(chunk); 24 SlotSet* slot_set = chunk->slot_set<type>();
27 if (slot_set == nullptr) { 25 if (slot_set == nullptr) {
28 slot_set = AllocateSlotSet(chunk); 26 slot_set = chunk->AllocateSlotSet<type>();
29 } 27 }
30 uintptr_t offset = slot_addr - chunk->address(); 28 uintptr_t offset = slot_addr - chunk->address();
31 slot_set[offset / Page::kPageSize].Insert(offset % Page::kPageSize); 29 slot_set[offset / Page::kPageSize].Insert(offset % Page::kPageSize);
32 } 30 }
33 31
34 // Given a page and a slot in that page, this function returns true if 32 // Given a page and a slot in that page, this function returns true if
35 // the remembered set contains the slot. 33 // the remembered set contains the slot.
36 static bool Contains(MemoryChunk* chunk, Address slot_addr) { 34 static bool Contains(MemoryChunk* chunk, Address slot_addr) {
37 DCHECK(chunk->Contains(slot_addr)); 35 DCHECK(chunk->Contains(slot_addr));
38 SlotSet* slot_set = GetSlotSet(chunk); 36 SlotSet* slot_set = chunk->slot_set<type>();
39 if (slot_set == nullptr) { 37 if (slot_set == nullptr) {
40 return false; 38 return false;
41 } 39 }
42 uintptr_t offset = slot_addr - chunk->address(); 40 uintptr_t offset = slot_addr - chunk->address();
43 return slot_set[offset / Page::kPageSize].Contains(offset % 41 return slot_set[offset / Page::kPageSize].Contains(offset %
44 Page::kPageSize); 42 Page::kPageSize);
45 } 43 }
46 44
47 // Given a page and a slot in that page, this function removes the slot from 45 // Given a page and a slot in that page, this function removes the slot from
48 // the remembered set. 46 // the remembered set.
49 // If the slot was never added, then the function does nothing. 47 // If the slot was never added, then the function does nothing.
50 static void Remove(MemoryChunk* chunk, Address slot_addr) { 48 static void Remove(MemoryChunk* chunk, Address slot_addr) {
51 DCHECK(chunk->Contains(slot_addr)); 49 DCHECK(chunk->Contains(slot_addr));
52 SlotSet* slot_set = GetSlotSet(chunk); 50 SlotSet* slot_set = chunk->slot_set<type>();
53 if (slot_set != nullptr) { 51 if (slot_set != nullptr) {
54 uintptr_t offset = slot_addr - chunk->address(); 52 uintptr_t offset = slot_addr - chunk->address();
55 slot_set[offset / Page::kPageSize].Remove(offset % Page::kPageSize); 53 slot_set[offset / Page::kPageSize].Remove(offset % Page::kPageSize);
56 } 54 }
57 } 55 }
58 56
59 // Given a page and a range of slots in that page, this function removes the 57 // Given a page and a range of slots in that page, this function removes the
60 // slots from the remembered set. 58 // slots from the remembered set.
61 static void RemoveRange(MemoryChunk* chunk, Address start, Address end, 59 static void RemoveRange(MemoryChunk* chunk, Address start, Address end,
62 SlotSet::EmptyBucketMode mode) { 60 SlotSet::EmptyBucketMode mode) {
63 SlotSet* slot_set = GetSlotSet(chunk); 61 SlotSet* slot_set = chunk->slot_set<type>();
64 if (slot_set != nullptr) { 62 if (slot_set != nullptr) {
65 uintptr_t start_offset = start - chunk->address(); 63 uintptr_t start_offset = start - chunk->address();
66 uintptr_t end_offset = end - chunk->address(); 64 uintptr_t end_offset = end - chunk->address();
67 DCHECK_LT(start_offset, end_offset); 65 DCHECK_LT(start_offset, end_offset);
68 if (end_offset < static_cast<uintptr_t>(Page::kPageSize)) { 66 if (end_offset < static_cast<uintptr_t>(Page::kPageSize)) {
69 slot_set->RemoveRange(static_cast<int>(start_offset), 67 slot_set->RemoveRange(static_cast<int>(start_offset),
70 static_cast<int>(end_offset), mode); 68 static_cast<int>(end_offset), mode);
71 } else { 69 } else {
72 // The large page has multiple slot sets. 70 // The large page has multiple slot sets.
73 // Compute slot set indicies for the range [start_offset, end_offset). 71 // Compute slot set indicies for the range [start_offset, end_offset).
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 heap, [callback](MemoryChunk* chunk) { Iterate(chunk, callback); }); 103 heap, [callback](MemoryChunk* chunk) { Iterate(chunk, callback); });
106 } 104 }
107 105
108 // Iterates over all memory chunks that contains non-empty slot sets. 106 // Iterates over all memory chunks that contains non-empty slot sets.
109 // The callback should take (MemoryChunk* chunk) and return void. 107 // The callback should take (MemoryChunk* chunk) and return void.
110 template <typename Callback> 108 template <typename Callback>
111 static void IterateMemoryChunks(Heap* heap, Callback callback) { 109 static void IterateMemoryChunks(Heap* heap, Callback callback) {
112 MemoryChunkIterator it(heap); 110 MemoryChunkIterator it(heap);
113 MemoryChunk* chunk; 111 MemoryChunk* chunk;
114 while ((chunk = it.next()) != nullptr) { 112 while ((chunk = it.next()) != nullptr) {
115 SlotSet* slots = GetSlotSet(chunk); 113 SlotSet* slots = chunk->slot_set<type>();
116 TypedSlotSet* typed_slots = GetTypedSlotSet(chunk); 114 TypedSlotSet* typed_slots = chunk->typed_slot_set<type>();
117 if (slots != nullptr || typed_slots != nullptr) { 115 if (slots != nullptr || typed_slots != nullptr) {
118 callback(chunk); 116 callback(chunk);
119 } 117 }
120 } 118 }
121 } 119 }
122 120
123 // Iterates and filters the remembered set in the given memory chunk with 121 // Iterates and filters the remembered set in the given memory chunk with
124 // the given callback. The callback should take (Address slot) and return 122 // the given callback. The callback should take (Address slot) and return
125 // SlotCallbackResult. 123 // SlotCallbackResult.
126 template <typename Callback> 124 template <typename Callback>
127 static void Iterate(MemoryChunk* chunk, Callback callback) { 125 static void Iterate(MemoryChunk* chunk, Callback callback) {
128 SlotSet* slots = GetSlotSet(chunk); 126 SlotSet* slots = chunk->slot_set<type>();
129 if (slots != nullptr) { 127 if (slots != nullptr) {
130 size_t pages = (chunk->size() + Page::kPageSize - 1) / Page::kPageSize; 128 size_t pages = (chunk->size() + Page::kPageSize - 1) / Page::kPageSize;
131 int new_count = 0; 129 int new_count = 0;
132 for (size_t page = 0; page < pages; page++) { 130 for (size_t page = 0; page < pages; page++) {
133 new_count += 131 new_count +=
134 slots[page].Iterate(callback, SlotSet::PREFREE_EMPTY_BUCKETS); 132 slots[page].Iterate(callback, SlotSet::PREFREE_EMPTY_BUCKETS);
135 } 133 }
136 // Only old-to-old slot sets are released eagerly. Old-new-slot sets are 134 // Only old-to-old slot sets are released eagerly. Old-new-slot sets are
137 // released by the sweeper threads. 135 // released by the sweeper threads.
138 if (direction == OLD_TO_OLD && new_count == 0) { 136 if (type == OLD_TO_OLD && new_count == 0) {
139 chunk->ReleaseOldToOldSlots(); 137 chunk->ReleaseSlotSet<OLD_TO_OLD>();
140 } 138 }
141 } 139 }
142 } 140 }
143 141
144 // Given a page and a typed slot in that page, this function adds the slot 142 // Given a page and a typed slot in that page, this function adds the slot
145 // to the remembered set. 143 // to the remembered set.
146 static void InsertTyped(Page* page, Address host_addr, SlotType slot_type, 144 static void InsertTyped(Page* page, Address host_addr, SlotType slot_type,
147 Address slot_addr) { 145 Address slot_addr) {
148 TypedSlotSet* slot_set = GetTypedSlotSet(page); 146 TypedSlotSet* slot_set = page->typed_slot_set<type>();
149 if (slot_set == nullptr) { 147 if (slot_set == nullptr) {
150 AllocateTypedSlotSet(page); 148 slot_set = page->AllocateTypedSlotSet<type>();
151 slot_set = GetTypedSlotSet(page);
152 } 149 }
153 if (host_addr == nullptr) { 150 if (host_addr == nullptr) {
154 host_addr = page->address(); 151 host_addr = page->address();
155 } 152 }
156 uintptr_t offset = slot_addr - page->address(); 153 uintptr_t offset = slot_addr - page->address();
157 uintptr_t host_offset = host_addr - page->address(); 154 uintptr_t host_offset = host_addr - page->address();
158 DCHECK_LT(offset, static_cast<uintptr_t>(TypedSlotSet::kMaxOffset)); 155 DCHECK_LT(offset, static_cast<uintptr_t>(TypedSlotSet::kMaxOffset));
159 DCHECK_LT(host_offset, static_cast<uintptr_t>(TypedSlotSet::kMaxOffset)); 156 DCHECK_LT(host_offset, static_cast<uintptr_t>(TypedSlotSet::kMaxOffset));
160 slot_set->Insert(slot_type, static_cast<uint32_t>(host_offset), 157 slot_set->Insert(slot_type, static_cast<uint32_t>(host_offset),
161 static_cast<uint32_t>(offset)); 158 static_cast<uint32_t>(offset));
162 } 159 }
163 160
164 // Given a page and a range of typed slots in that page, this function removes 161 // Given a page and a range of typed slots in that page, this function removes
165 // the slots from the remembered set. 162 // the slots from the remembered set.
166 static void RemoveRangeTyped(MemoryChunk* page, Address start, Address end) { 163 static void RemoveRangeTyped(MemoryChunk* page, Address start, Address end) {
167 TypedSlotSet* slots = GetTypedSlotSet(page); 164 TypedSlotSet* slots = page->typed_slot_set<type>();
168 if (slots != nullptr) { 165 if (slots != nullptr) {
169 slots->Iterate( 166 slots->Iterate(
170 [start, end](SlotType slot_type, Address host_addr, 167 [start, end](SlotType slot_type, Address host_addr,
171 Address slot_addr) { 168 Address slot_addr) {
172 return start <= slot_addr && slot_addr < end ? REMOVE_SLOT 169 return start <= slot_addr && slot_addr < end ? REMOVE_SLOT
173 : KEEP_SLOT; 170 : KEEP_SLOT;
174 }, 171 },
175 TypedSlotSet::PREFREE_EMPTY_CHUNKS); 172 TypedSlotSet::PREFREE_EMPTY_CHUNKS);
176 } 173 }
177 } 174 }
178 175
179 // Iterates and filters the remembered set with the given callback. 176 // Iterates and filters the remembered set with the given callback.
180 // The callback should take (SlotType slot_type, SlotAddress slot) and return 177 // The callback should take (SlotType slot_type, SlotAddress slot) and return
181 // SlotCallbackResult. 178 // SlotCallbackResult.
182 template <typename Callback> 179 template <typename Callback>
183 static void IterateTyped(Heap* heap, Callback callback) { 180 static void IterateTyped(Heap* heap, Callback callback) {
184 IterateMemoryChunks(heap, [callback](MemoryChunk* chunk) { 181 IterateMemoryChunks(heap, [callback](MemoryChunk* chunk) {
185 IterateTyped(chunk, callback); 182 IterateTyped(chunk, callback);
186 }); 183 });
187 } 184 }
188 185
189 // Iterates and filters typed old to old pointers in the given memory chunk 186 // Iterates and filters typed old to old pointers in the given memory chunk
190 // with the given callback. The callback should take (SlotType slot_type, 187 // with the given callback. The callback should take (SlotType slot_type,
191 // Address slot_addr) and return SlotCallbackResult. 188 // Address slot_addr) and return SlotCallbackResult.
192 template <typename Callback> 189 template <typename Callback>
193 static void IterateTyped(MemoryChunk* chunk, Callback callback) { 190 static void IterateTyped(MemoryChunk* chunk, Callback callback) {
194 TypedSlotSet* slots = GetTypedSlotSet(chunk); 191 TypedSlotSet* slots = chunk->typed_slot_set<type>();
195 if (slots != nullptr) { 192 if (slots != nullptr) {
196 int new_count = slots->Iterate(callback, TypedSlotSet::KEEP_EMPTY_CHUNKS); 193 int new_count = slots->Iterate(callback, TypedSlotSet::KEEP_EMPTY_CHUNKS);
197 if (new_count == 0) { 194 if (new_count == 0) {
198 ReleaseTypedSlotSet(chunk); 195 chunk->ReleaseTypedSlotSet<type>();
199 } 196 }
200 } 197 }
201 } 198 }
202 199
203 // Clear all old to old slots from the remembered set. 200 // Clear all old to old slots from the remembered set.
204 static void ClearAll(Heap* heap) { 201 static void ClearAll(Heap* heap) {
205 STATIC_ASSERT(direction == OLD_TO_OLD); 202 STATIC_ASSERT(type == OLD_TO_OLD);
206 MemoryChunkIterator it(heap); 203 MemoryChunkIterator it(heap);
207 MemoryChunk* chunk; 204 MemoryChunk* chunk;
208 while ((chunk = it.next()) != nullptr) { 205 while ((chunk = it.next()) != nullptr) {
209 chunk->ReleaseOldToOldSlots(); 206 chunk->ReleaseSlotSet<OLD_TO_OLD>();
210 chunk->ReleaseTypedOldToOldSlots(); 207 chunk->ReleaseTypedSlotSet<OLD_TO_OLD>();
211 } 208 }
212 } 209 }
213 210
214 // Eliminates all stale slots from the remembered set, i.e. 211 // Eliminates all stale slots from the remembered set, i.e.
215 // slots that are not part of live objects anymore. This method must be 212 // slots that are not part of live objects anymore. This method must be
216 // called after marking, when the whole transitive closure is known and 213 // called after marking, when the whole transitive closure is known and
217 // must be called before sweeping when mark bits are still intact. 214 // must be called before sweeping when mark bits are still intact.
218 static void ClearInvalidTypedSlots(Heap* heap, MemoryChunk* chunk); 215 static void ClearInvalidTypedSlots(Heap* heap, MemoryChunk* chunk);
219 216
220 private: 217 private:
221 static SlotSet* GetSlotSet(MemoryChunk* chunk) {
222 if (direction == OLD_TO_OLD) {
223 return chunk->old_to_old_slots();
224 } else {
225 return chunk->old_to_new_slots();
226 }
227 }
228
229 static TypedSlotSet* GetTypedSlotSet(MemoryChunk* chunk) {
230 if (direction == OLD_TO_OLD) {
231 return chunk->typed_old_to_old_slots();
232 } else {
233 return chunk->typed_old_to_new_slots();
234 }
235 }
236
237 static void ReleaseTypedSlotSet(MemoryChunk* chunk) {
238 if (direction == OLD_TO_OLD) {
239 chunk->ReleaseTypedOldToOldSlots();
240 }
241 }
242
243 static SlotSet* AllocateSlotSet(MemoryChunk* chunk) {
244 if (direction == OLD_TO_OLD) {
245 chunk->AllocateOldToOldSlots();
246 return chunk->old_to_old_slots();
247 } else {
248 chunk->AllocateOldToNewSlots();
249 return chunk->old_to_new_slots();
250 }
251 }
252
253 static TypedSlotSet* AllocateTypedSlotSet(MemoryChunk* chunk) {
254 if (direction == OLD_TO_OLD) {
255 chunk->AllocateTypedOldToOldSlots();
256 return chunk->typed_old_to_old_slots();
257 } else {
258 chunk->AllocateTypedOldToNewSlots();
259 return chunk->typed_old_to_new_slots();
260 }
261 }
262
263 static bool IsValidSlot(Heap* heap, MemoryChunk* chunk, Object** slot); 218 static bool IsValidSlot(Heap* heap, MemoryChunk* chunk, Object** slot);
264 }; 219 };
265 220
266 class UpdateTypedSlotHelper { 221 class UpdateTypedSlotHelper {
267 public: 222 public:
268 // Updates a cell slot using an untyped slot callback. 223 // Updates a cell slot using an untyped slot callback.
269 // The callback accepts Object** and returns SlotCallbackResult. 224 // The callback accepts Object** and returns SlotCallbackResult.
270 template <typename Callback> 225 template <typename Callback>
271 static SlotCallbackResult UpdateCell(RelocInfo* rinfo, Callback callback) { 226 static SlotCallbackResult UpdateCell(RelocInfo* rinfo, Callback callback) {
272 DCHECK(rinfo->rmode() == RelocInfo::CELL); 227 DCHECK(rinfo->rmode() == RelocInfo::CELL);
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 return DEBUG_TARGET_SLOT; 347 return DEBUG_TARGET_SLOT;
393 } 348 }
394 UNREACHABLE(); 349 UNREACHABLE();
395 return CLEARED_SLOT; 350 return CLEARED_SLOT;
396 } 351 }
397 352
398 } // namespace internal 353 } // namespace internal
399 } // namespace v8 354 } // namespace v8
400 355
401 #endif // V8_REMEMBERED_SET_H 356 #endif // V8_REMEMBERED_SET_H
OLDNEW
« no previous file with comments | « src/heap/mark-compact.cc ('k') | src/heap/spaces.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698