Chromium Code Reviews| 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 |