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_SLOT_SET_H | 5 #ifndef V8_SLOT_SET_H |
6 #define V8_SLOT_SET_H | 6 #define V8_SLOT_SET_H |
7 | 7 |
8 #include <stack> | 8 #include <stack> |
9 | 9 |
10 #include "src/allocation.h" | 10 #include "src/allocation.h" |
11 #include "src/base/atomic-utils.h" | 11 #include "src/base/atomic-utils.h" |
12 #include "src/base/bits.h" | 12 #include "src/base/bits.h" |
13 #include "src/utils.h" | 13 #include "src/utils.h" |
14 | 14 |
15 namespace v8 { | 15 namespace v8 { |
16 namespace internal { | 16 namespace internal { |
17 | 17 |
18 enum SlotCallbackResult { KEEP_SLOT, REMOVE_SLOT }; | 18 enum SlotCallbackResult { KEEP_SLOT, REMOVE_SLOT }; |
19 | 19 |
20 // Data structure for maintaining a set of slots in a standard (non-large) | 20 // Data structure for maintaining a set of slots in a standard (non-large) |
21 // page. The base address of the page must be set with SetPageStart before any | 21 // page. The base address of the page must be set with SetPageStart before any |
22 // operation. | 22 // operation. |
23 // The data structure assumes that the slots are pointer size aligned and | 23 // The data structure assumes that the slots are pointer size aligned and |
24 // splits the valid slot offset range into kBuckets buckets. | 24 // splits the valid slot offset range into kBuckets buckets. |
25 // Each bucket is a bitmap with a bit corresponding to a single slot offset. | 25 // Each bucket is a bitmap with a bit corresponding to a single slot offset. |
26 class SlotSet : public Malloced { | 26 class SlotSet : public Malloced { |
27 public: | 27 public: |
28 enum IterationMode { PREFREE_EMPTY_BUCKETS, KEEP_EMPTY_BUCKETS }; | |
Hannes Payer (out of office)
2016/10/05 08:59:30
KEEP_EMPTY_BUCKETS will be used as soon as we move
| |
29 | |
28 SlotSet() { | 30 SlotSet() { |
29 for (int i = 0; i < kBuckets; i++) { | 31 for (int i = 0; i < kBuckets; i++) { |
30 bucket[i].SetValue(nullptr); | 32 bucket[i].SetValue(nullptr); |
31 } | 33 } |
32 } | 34 } |
33 | 35 |
34 ~SlotSet() { | 36 ~SlotSet() { |
35 for (int i = 0; i < kBuckets; i++) { | 37 for (int i = 0; i < kBuckets; i++) { |
36 ReleaseBucket(i); | 38 ReleaseBucket(i); |
37 } | 39 } |
40 FreeToBeFreedBuckets(); | |
38 } | 41 } |
39 | 42 |
40 void SetPageStart(Address page_start) { page_start_ = page_start; } | 43 void SetPageStart(Address page_start) { page_start_ = page_start; } |
41 | 44 |
42 // The slot offset specifies a slot at address page_start_ + slot_offset. | 45 // The slot offset specifies a slot at address page_start_ + slot_offset. |
43 // This method should only be called on the main thread because concurrent | 46 // This method should only be called on the main thread because concurrent |
44 // allocation of the bucket is not thread-safe. | 47 // allocation of the bucket is not thread-safe. |
45 void Insert(int slot_offset) { | 48 void Insert(int slot_offset) { |
46 int bucket_index, cell_index, bit_index; | 49 int bucket_index, cell_index, bit_index; |
47 SlotToIndices(slot_offset, &bucket_index, &cell_index, &bit_index); | 50 SlotToIndices(slot_offset, &bucket_index, &cell_index, &bit_index); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
138 // If the callback returns REMOVE_SLOT then the slot is removed from the set. | 141 // If the callback returns REMOVE_SLOT then the slot is removed from the set. |
139 // Returns the new number of slots. | 142 // Returns the new number of slots. |
140 // This method should only be called on the main thread. | 143 // This method should only be called on the main thread. |
141 // | 144 // |
142 // Sample usage: | 145 // Sample usage: |
143 // Iterate([](Address slot_address) { | 146 // Iterate([](Address slot_address) { |
144 // if (good(slot_address)) return KEEP_SLOT; | 147 // if (good(slot_address)) return KEEP_SLOT; |
145 // else return REMOVE_SLOT; | 148 // else return REMOVE_SLOT; |
146 // }); | 149 // }); |
147 template <typename Callback> | 150 template <typename Callback> |
148 int Iterate(Callback callback) { | 151 int Iterate(Callback callback, IterationMode mode) { |
149 int new_count = 0; | 152 int new_count = 0; |
150 for (int bucket_index = 0; bucket_index < kBuckets; bucket_index++) { | 153 for (int bucket_index = 0; bucket_index < kBuckets; bucket_index++) { |
151 if (bucket[bucket_index].Value() != nullptr) { | 154 if (bucket[bucket_index].Value() != nullptr) { |
152 int in_bucket_count = 0; | 155 int in_bucket_count = 0; |
153 base::AtomicValue<uint32_t>* current_bucket = | 156 base::AtomicValue<uint32_t>* current_bucket = |
154 bucket[bucket_index].Value(); | 157 bucket[bucket_index].Value(); |
155 int cell_offset = bucket_index * kBitsPerBucket; | 158 int cell_offset = bucket_index * kBitsPerBucket; |
156 for (int i = 0; i < kCellsPerBucket; i++, cell_offset += kBitsPerCell) { | 159 for (int i = 0; i < kCellsPerBucket; i++, cell_offset += kBitsPerCell) { |
157 if (current_bucket[i].Value()) { | 160 if (current_bucket[i].Value()) { |
158 uint32_t cell = current_bucket[i].Value(); | 161 uint32_t cell = current_bucket[i].Value(); |
(...skipping 16 matching lines...) Expand all Loading... | |
175 // have to read the current value of the cell, & it with the | 178 // have to read the current value of the cell, & it with the |
176 // computed value, and retry. We can do this, because this | 179 // computed value, and retry. We can do this, because this |
177 // method will only be called on the main thread and filtering | 180 // method will only be called on the main thread and filtering |
178 // threads will only remove slots. | 181 // threads will only remove slots. |
179 old_cell = current_bucket[i].Value(); | 182 old_cell = current_bucket[i].Value(); |
180 new_cell &= old_cell; | 183 new_cell &= old_cell; |
181 } | 184 } |
182 } | 185 } |
183 } | 186 } |
184 } | 187 } |
185 if (in_bucket_count == 0) { | 188 if (mode == PREFREE_EMPTY_BUCKETS && in_bucket_count == 0) { |
186 ReleaseBucket(bucket_index); | 189 base::LockGuard<base::Mutex> guard(&to_be_freed_buckets_mutex_); |
190 base::AtomicValue<uint32_t>* bucket_ptr = | |
191 bucket[bucket_index].Value(); | |
192 to_be_freed_buckets_.push(bucket_ptr); | |
193 bucket[bucket_index].SetValue(nullptr); | |
187 } | 194 } |
188 new_count += in_bucket_count; | 195 new_count += in_bucket_count; |
189 } | 196 } |
190 } | 197 } |
191 return new_count; | 198 return new_count; |
192 } | 199 } |
193 | 200 |
201 void FreeToBeFreedBuckets() { | |
202 base::LockGuard<base::Mutex> guard(&to_be_freed_buckets_mutex_); | |
203 while (!to_be_freed_buckets_.empty()) { | |
204 base::AtomicValue<uint32_t>* top = to_be_freed_buckets_.top(); | |
205 to_be_freed_buckets_.pop(); | |
206 DeleteArray<base::AtomicValue<uint32_t>>(top); | |
207 } | |
208 } | |
209 | |
194 private: | 210 private: |
195 static const int kMaxSlots = (1 << kPageSizeBits) / kPointerSize; | 211 static const int kMaxSlots = (1 << kPageSizeBits) / kPointerSize; |
196 static const int kCellsPerBucket = 32; | 212 static const int kCellsPerBucket = 32; |
197 static const int kCellsPerBucketLog2 = 5; | 213 static const int kCellsPerBucketLog2 = 5; |
198 static const int kBitsPerCell = 32; | 214 static const int kBitsPerCell = 32; |
199 static const int kBitsPerCellLog2 = 5; | 215 static const int kBitsPerCellLog2 = 5; |
200 static const int kBitsPerBucket = kCellsPerBucket * kBitsPerCell; | 216 static const int kBitsPerBucket = kCellsPerBucket * kBitsPerCell; |
201 static const int kBitsPerBucketLog2 = kCellsPerBucketLog2 + kBitsPerCellLog2; | 217 static const int kBitsPerBucketLog2 = kCellsPerBucketLog2 + kBitsPerCellLog2; |
202 static const int kBuckets = kMaxSlots / kCellsPerBucket / kBitsPerCell; | 218 static const int kBuckets = kMaxSlots / kCellsPerBucket / kBitsPerCell; |
203 | 219 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
235 DCHECK_EQ(slot_offset % kPointerSize, 0); | 251 DCHECK_EQ(slot_offset % kPointerSize, 0); |
236 int slot = slot_offset >> kPointerSizeLog2; | 252 int slot = slot_offset >> kPointerSizeLog2; |
237 DCHECK(slot >= 0 && slot <= kMaxSlots); | 253 DCHECK(slot >= 0 && slot <= kMaxSlots); |
238 *bucket_index = slot >> kBitsPerBucketLog2; | 254 *bucket_index = slot >> kBitsPerBucketLog2; |
239 *cell_index = (slot >> kBitsPerCellLog2) & (kCellsPerBucket - 1); | 255 *cell_index = (slot >> kBitsPerCellLog2) & (kCellsPerBucket - 1); |
240 *bit_index = slot & (kBitsPerCell - 1); | 256 *bit_index = slot & (kBitsPerCell - 1); |
241 } | 257 } |
242 | 258 |
243 base::AtomicValue<base::AtomicValue<uint32_t>*> bucket[kBuckets]; | 259 base::AtomicValue<base::AtomicValue<uint32_t>*> bucket[kBuckets]; |
244 Address page_start_; | 260 Address page_start_; |
261 base::Mutex to_be_freed_buckets_mutex_; | |
262 std::stack<base::AtomicValue<uint32_t>*> to_be_freed_buckets_; | |
245 }; | 263 }; |
246 | 264 |
247 enum SlotType { | 265 enum SlotType { |
248 EMBEDDED_OBJECT_SLOT, | 266 EMBEDDED_OBJECT_SLOT, |
249 OBJECT_SLOT, | 267 OBJECT_SLOT, |
250 CELL_TARGET_SLOT, | 268 CELL_TARGET_SLOT, |
251 CODE_TARGET_SLOT, | 269 CODE_TARGET_SLOT, |
252 CODE_ENTRY_SLOT, | 270 CODE_ENTRY_SLOT, |
253 DEBUG_TARGET_SLOT, | 271 DEBUG_TARGET_SLOT, |
254 CLEARED_SLOT | 272 CLEARED_SLOT |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
449 Address page_start_; | 467 Address page_start_; |
450 base::AtomicValue<Chunk*> chunk_; | 468 base::AtomicValue<Chunk*> chunk_; |
451 base::Mutex to_be_freed_chunks_mutex_; | 469 base::Mutex to_be_freed_chunks_mutex_; |
452 std::stack<Chunk*> to_be_freed_chunks_; | 470 std::stack<Chunk*> to_be_freed_chunks_; |
453 }; | 471 }; |
454 | 472 |
455 } // namespace internal | 473 } // namespace internal |
456 } // namespace v8 | 474 } // namespace v8 |
457 | 475 |
458 #endif // V8_SLOT_SET_H | 476 #endif // V8_SLOT_SET_H |
OLD | NEW |