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

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

Issue 2353553003: [heap] Make slot set state and operations atomic. (Closed)
Patch Set: add check Created 4 years, 3 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
« src/base/atomic-utils.h ('K') | « src/base/atomic-utils.h ('k') | no next file » | 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_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 "src/allocation.h" 8 #include "src/allocation.h"
9 #include "src/base/atomic-utils.h"
9 #include "src/base/bits.h" 10 #include "src/base/bits.h"
10 #include "src/utils.h" 11 #include "src/utils.h"
11 12
12 namespace v8 { 13 namespace v8 {
13 namespace internal { 14 namespace internal {
14 15
15 enum SlotCallbackResult { KEEP_SLOT, REMOVE_SLOT }; 16 enum SlotCallbackResult { KEEP_SLOT, REMOVE_SLOT };
16 17
17 // Data structure for maintaining a set of slots in a standard (non-large) 18 // Data structure for maintaining a set of slots in a standard (non-large)
18 // page. The base address of the page must be set with SetPageStart before any 19 // page. The base address of the page must be set with SetPageStart before any
19 // operation. 20 // operation.
20 // The data structure assumes that the slots are pointer size aligned and 21 // The data structure assumes that the slots are pointer size aligned and
21 // splits the valid slot offset range into kBuckets buckets. 22 // splits the valid slot offset range into kBuckets buckets.
22 // Each bucket is a bitmap with a bit corresponding to a single slot offset. 23 // Each bucket is a bitmap with a bit corresponding to a single slot offset.
23 class SlotSet : public Malloced { 24 class SlotSet : public Malloced {
24 public: 25 public:
25 SlotSet() { 26 SlotSet() {
26 for (int i = 0; i < kBuckets; i++) { 27 for (int i = 0; i < kBuckets; i++) {
27 bucket[i] = nullptr; 28 bucket[i].SetValue(nullptr);
28 } 29 }
29 } 30 }
30 31
31 ~SlotSet() { 32 ~SlotSet() {
32 for (int i = 0; i < kBuckets; i++) { 33 for (int i = 0; i < kBuckets; i++) {
33 ReleaseBucket(i); 34 ReleaseBucket(i);
34 } 35 }
35 } 36 }
36 37
37 void SetPageStart(Address page_start) { page_start_ = page_start; } 38 void SetPageStart(Address page_start) { page_start_ = page_start; }
38 39
39 // The slot offset specifies a slot at address page_start_ + slot_offset. 40 // The slot offset specifies a slot at address page_start_ + slot_offset.
40 void Insert(int slot_offset) { 41 void Insert(int slot_offset) {
ulan 2016/09/20 12:33:02 Could you please add a comment that this method sh
Hannes Payer (out of office) 2016/09/20 13:51:29 Done.
41 int bucket_index, cell_index, bit_index; 42 int bucket_index, cell_index, bit_index;
42 SlotToIndices(slot_offset, &bucket_index, &cell_index, &bit_index); 43 SlotToIndices(slot_offset, &bucket_index, &cell_index, &bit_index);
43 if (bucket[bucket_index] == nullptr) { 44 base::AtomicValue<uint32_t>* current_bucket = bucket[bucket_index].Value();
44 bucket[bucket_index] = AllocateBucket(); 45 if (current_bucket == nullptr) {
46 current_bucket = AllocateBucket();
47 bucket[bucket_index].SetValue(current_bucket);
45 } 48 }
46 bucket[bucket_index][cell_index] |= 1u << bit_index; 49 current_bucket[cell_index].SetBit(bit_index);
47 } 50 }
48 51
49 // The slot offset specifies a slot at address page_start_ + slot_offset. 52 // The slot offset specifies a slot at address page_start_ + slot_offset.
50 void Remove(int slot_offset) { 53 void Remove(int slot_offset) {
51 int bucket_index, cell_index, bit_index; 54 int bucket_index, cell_index, bit_index;
52 SlotToIndices(slot_offset, &bucket_index, &cell_index, &bit_index); 55 SlotToIndices(slot_offset, &bucket_index, &cell_index, &bit_index);
53 if (bucket[bucket_index] != nullptr) { 56 base::AtomicValue<uint32_t>* current_bucket = bucket[bucket_index].Value();
54 uint32_t cell = bucket[bucket_index][cell_index]; 57 if (current_bucket != nullptr) {
58 uint32_t cell = current_bucket[cell_index].Value();
55 if (cell) { 59 if (cell) {
56 uint32_t bit_mask = 1u << bit_index; 60 uint32_t bit_mask = 1u << bit_index;
57 if (cell & bit_mask) { 61 if (cell & bit_mask) {
58 bucket[bucket_index][cell_index] ^= bit_mask; 62 current_bucket[cell_index].ClearBit(bit_index);
59 } 63 }
60 } 64 }
61 } 65 }
62 } 66 }
63 67
64 // The slot offsets specify a range of slots at addresses: 68 // The slot offsets specify a range of slots at addresses:
65 // [page_start_ + start_offset ... page_start_ + end_offset). 69 // [page_start_ + start_offset ... page_start_ + end_offset).
66 void RemoveRange(int start_offset, int end_offset) { 70 void RemoveRange(int start_offset, int end_offset) {
67 CHECK_LE(end_offset, 1 << kPageSizeBits); 71 CHECK_LE(end_offset, 1 << kPageSizeBits);
68 DCHECK_LE(start_offset, end_offset); 72 DCHECK_LE(start_offset, end_offset);
69 int start_bucket, start_cell, start_bit; 73 int start_bucket, start_cell, start_bit;
70 SlotToIndices(start_offset, &start_bucket, &start_cell, &start_bit); 74 SlotToIndices(start_offset, &start_bucket, &start_cell, &start_bit);
71 int end_bucket, end_cell, end_bit; 75 int end_bucket, end_cell, end_bit;
72 SlotToIndices(end_offset, &end_bucket, &end_cell, &end_bit); 76 SlotToIndices(end_offset, &end_bucket, &end_cell, &end_bit);
73 uint32_t start_mask = (1u << start_bit) - 1; 77 uint32_t start_mask = (1u << start_bit) - 1;
74 uint32_t end_mask = ~((1u << end_bit) - 1); 78 uint32_t end_mask = ~((1u << end_bit) - 1);
75 if (start_bucket == end_bucket && start_cell == end_cell) { 79 if (start_bucket == end_bucket && start_cell == end_cell) {
76 MaskCell(start_bucket, start_cell, start_mask | end_mask); 80 ClearCell(start_bucket, start_cell, ~(start_mask | end_mask));
77 return; 81 return;
78 } 82 }
79 int current_bucket = start_bucket; 83 int current_bucket = start_bucket;
80 int current_cell = start_cell; 84 int current_cell = start_cell;
81 MaskCell(current_bucket, current_cell, start_mask); 85 ClearCell(current_bucket, current_cell, ~start_mask);
82 current_cell++; 86 current_cell++;
83 if (current_bucket < end_bucket) { 87 if (current_bucket < end_bucket) {
84 if (bucket[current_bucket] != nullptr) { 88 if (bucket[current_bucket].Value() != nullptr) {
85 while (current_cell < kCellsPerBucket) { 89 while (current_cell < kCellsPerBucket) {
86 bucket[current_bucket][current_cell] = 0; 90 bucket[current_bucket].Value()[current_cell].SetValue(0);
87 current_cell++; 91 current_cell++;
88 } 92 }
89 } 93 }
90 // The rest of the current bucket is cleared. 94 // The rest of the current bucket is cleared.
91 // Move on to the next bucket. 95 // Move on to the next bucket.
92 current_bucket++; 96 current_bucket++;
93 current_cell = 0; 97 current_cell = 0;
94 } 98 }
95 DCHECK(current_bucket == end_bucket || 99 DCHECK(current_bucket == end_bucket ||
96 (current_bucket < end_bucket && current_cell == 0)); 100 (current_bucket < end_bucket && current_cell == 0));
97 while (current_bucket < end_bucket) { 101 while (current_bucket < end_bucket) {
98 ReleaseBucket(current_bucket); 102 ReleaseBucket(current_bucket);
99 current_bucket++; 103 current_bucket++;
100 } 104 }
101 // All buckets between start_bucket and end_bucket are cleared. 105 // All buckets between start_bucket and end_bucket are cleared.
102 DCHECK(current_bucket == end_bucket && current_cell <= end_cell); 106 DCHECK(current_bucket == end_bucket && current_cell <= end_cell);
103 if (current_bucket == kBuckets || bucket[current_bucket] == nullptr) { 107 if (current_bucket == kBuckets ||
108 bucket[current_bucket].Value() == nullptr) {
104 return; 109 return;
105 } 110 }
106 while (current_cell < end_cell) { 111 while (current_cell < end_cell) {
107 bucket[current_bucket][current_cell] = 0; 112 bucket[current_bucket].Value()[current_cell].SetValue(0);
108 current_cell++; 113 current_cell++;
109 } 114 }
110 // All cells between start_cell and end_cell are cleared. 115 // All cells between start_cell and end_cell are cleared.
111 DCHECK(current_bucket == end_bucket && current_cell == end_cell); 116 DCHECK(current_bucket == end_bucket && current_cell == end_cell);
112 MaskCell(end_bucket, end_cell, end_mask); 117 ClearCell(end_bucket, end_cell, ~end_mask);
113 } 118 }
114 119
115 // The slot offset specifies a slot at address page_start_ + slot_offset. 120 // The slot offset specifies a slot at address page_start_ + slot_offset.
116 bool Lookup(int slot_offset) { 121 bool Lookup(int slot_offset) {
117 int bucket_index, cell_index, bit_index; 122 int bucket_index, cell_index, bit_index;
118 SlotToIndices(slot_offset, &bucket_index, &cell_index, &bit_index); 123 SlotToIndices(slot_offset, &bucket_index, &cell_index, &bit_index);
119 if (bucket[bucket_index] != nullptr) { 124 if (bucket[bucket_index].Value() != nullptr) {
120 uint32_t cell = bucket[bucket_index][cell_index]; 125 uint32_t cell = bucket[bucket_index].Value()[cell_index].Value();
121 return (cell & (1u << bit_index)) != 0; 126 return (cell & (1u << bit_index)) != 0;
122 } 127 }
123 return false; 128 return false;
124 } 129 }
125 130
126 // Iterate over all slots in the set and for each slot invoke the callback. 131 // Iterate over all slots in the set and for each slot invoke the callback.
127 // If the callback returns REMOVE_SLOT then the slot is removed from the set. 132 // If the callback returns REMOVE_SLOT then the slot is removed from the set.
128 // Returns the new number of slots. 133 // Returns the new number of slots.
129 // 134 //
130 // Sample usage: 135 // Sample usage:
131 // Iterate([](Address slot_address) { 136 // Iterate([](Address slot_address) {
132 // if (good(slot_address)) return KEEP_SLOT; 137 // if (good(slot_address)) return KEEP_SLOT;
133 // else return REMOVE_SLOT; 138 // else return REMOVE_SLOT;
134 // }); 139 // });
135 template <typename Callback> 140 template <typename Callback>
136 int Iterate(Callback callback) { 141 int Iterate(Callback callback) {
137 int new_count = 0; 142 int new_count = 0;
138 for (int bucket_index = 0; bucket_index < kBuckets; bucket_index++) { 143 for (int bucket_index = 0; bucket_index < kBuckets; bucket_index++) {
139 if (bucket[bucket_index] != nullptr) { 144 if (bucket[bucket_index].Value() != nullptr) {
140 int in_bucket_count = 0; 145 int in_bucket_count = 0;
141 uint32_t* current_bucket = bucket[bucket_index]; 146 base::AtomicValue<uint32_t>* current_bucket =
147 bucket[bucket_index].Value();
142 int cell_offset = bucket_index * kBitsPerBucket; 148 int cell_offset = bucket_index * kBitsPerBucket;
143 for (int i = 0; i < kCellsPerBucket; i++, cell_offset += kBitsPerCell) { 149 for (int i = 0; i < kCellsPerBucket; i++, cell_offset += kBitsPerCell) {
144 if (current_bucket[i]) { 150 if (current_bucket[i].Value()) {
145 uint32_t cell = current_bucket[i]; 151 uint32_t cell = current_bucket[i].Value();
146 uint32_t old_cell = cell; 152 uint32_t old_cell = cell;
147 uint32_t new_cell = cell; 153 uint32_t new_cell = cell;
148 while (cell) { 154 while (cell) {
149 int bit_offset = base::bits::CountTrailingZeros32(cell); 155 int bit_offset = base::bits::CountTrailingZeros32(cell);
150 uint32_t bit_mask = 1u << bit_offset; 156 uint32_t bit_mask = 1u << bit_offset;
151 uint32_t slot = (cell_offset + bit_offset) << kPointerSizeLog2; 157 uint32_t slot = (cell_offset + bit_offset) << kPointerSizeLog2;
152 if (callback(page_start_ + slot) == KEEP_SLOT) { 158 if (callback(page_start_ + slot) == KEEP_SLOT) {
153 ++in_bucket_count; 159 ++in_bucket_count;
154 } else { 160 } else {
155 new_cell ^= bit_mask; 161 new_cell ^= bit_mask;
156 } 162 }
157 cell ^= bit_mask; 163 cell ^= bit_mask;
158 } 164 }
159 if (old_cell != new_cell) { 165 if (old_cell != new_cell) {
160 current_bucket[i] = new_cell; 166 current_bucket[i].SetValue(new_cell);
ulan 2016/09/20 12:33:02 As discussed offline, we should use CAS here.
Hannes Payer (out of office) 2016/09/20 13:51:29 Done.
161 } 167 }
162 } 168 }
163 } 169 }
164 if (in_bucket_count == 0) { 170 if (in_bucket_count == 0) {
165 ReleaseBucket(bucket_index); 171 ReleaseBucket(bucket_index);
166 } 172 }
167 new_count += in_bucket_count; 173 new_count += in_bucket_count;
168 } 174 }
169 } 175 }
170 return new_count; 176 return new_count;
171 } 177 }
172 178
173 private: 179 private:
174 static const int kMaxSlots = (1 << kPageSizeBits) / kPointerSize; 180 static const int kMaxSlots = (1 << kPageSizeBits) / kPointerSize;
175 static const int kCellsPerBucket = 32; 181 static const int kCellsPerBucket = 32;
176 static const int kCellsPerBucketLog2 = 5; 182 static const int kCellsPerBucketLog2 = 5;
177 static const int kBitsPerCell = 32; 183 static const int kBitsPerCell = 32;
178 static const int kBitsPerCellLog2 = 5; 184 static const int kBitsPerCellLog2 = 5;
179 static const int kBitsPerBucket = kCellsPerBucket * kBitsPerCell; 185 static const int kBitsPerBucket = kCellsPerBucket * kBitsPerCell;
180 static const int kBitsPerBucketLog2 = kCellsPerBucketLog2 + kBitsPerCellLog2; 186 static const int kBitsPerBucketLog2 = kCellsPerBucketLog2 + kBitsPerCellLog2;
181 static const int kBuckets = kMaxSlots / kCellsPerBucket / kBitsPerCell; 187 static const int kBuckets = kMaxSlots / kCellsPerBucket / kBitsPerCell;
182 188
183 uint32_t* AllocateBucket() { 189 base::AtomicValue<uint32_t>* AllocateBucket() {
184 uint32_t* result = NewArray<uint32_t>(kCellsPerBucket); 190 base::AtomicValue<uint32_t>* result =
191 NewArray<base::AtomicValue<uint32_t>>(kCellsPerBucket);
185 for (int i = 0; i < kCellsPerBucket; i++) { 192 for (int i = 0; i < kCellsPerBucket; i++) {
186 result[i] = 0; 193 result[i].SetValue(0);
187 } 194 }
188 return result; 195 return result;
189 } 196 }
190 197
191 void ReleaseBucket(int bucket_index) { 198 void ReleaseBucket(int bucket_index) {
192 DeleteArray<uint32_t>(bucket[bucket_index]); 199 DeleteArray<base::AtomicValue<uint32_t>>(bucket[bucket_index].Value());
193 bucket[bucket_index] = nullptr; 200 bucket[bucket_index].SetValue(nullptr);
194 } 201 }
195 202
196 void MaskCell(int bucket_index, int cell_index, uint32_t mask) { 203 void ClearCell(int bucket_index, int cell_index, uint32_t mask) {
197 if (bucket_index < kBuckets) { 204 if (bucket_index < kBuckets) {
198 uint32_t* cells = bucket[bucket_index]; 205 base::AtomicValue<uint32_t>* cells = bucket[bucket_index].Value();
199 if (cells != nullptr && cells[cell_index] != 0) { 206 if (cells != nullptr) {
200 cells[cell_index] &= mask; 207 uint32_t cell = cells[cell_index].Value();
208 if (cell) cells[cell_index].SetBits(0, mask);
201 } 209 }
202 } else { 210 } else {
203 // GCC bug 59124: Emits wrong warnings 211 // GCC bug 59124: Emits wrong warnings
204 // "array subscript is above array bounds" 212 // "array subscript is above array bounds"
205 UNREACHABLE(); 213 UNREACHABLE();
206 } 214 }
207 } 215 }
208 216
209 // Converts the slot offset into bucket/cell/bit index. 217 // Converts the slot offset into bucket/cell/bit index.
210 void SlotToIndices(int slot_offset, int* bucket_index, int* cell_index, 218 void SlotToIndices(int slot_offset, int* bucket_index, int* cell_index,
211 int* bit_index) { 219 int* bit_index) {
212 DCHECK_EQ(slot_offset % kPointerSize, 0); 220 DCHECK_EQ(slot_offset % kPointerSize, 0);
213 int slot = slot_offset >> kPointerSizeLog2; 221 int slot = slot_offset >> kPointerSizeLog2;
214 DCHECK(slot >= 0 && slot <= kMaxSlots); 222 DCHECK(slot >= 0 && slot <= kMaxSlots);
215 *bucket_index = slot >> kBitsPerBucketLog2; 223 *bucket_index = slot >> kBitsPerBucketLog2;
216 *cell_index = (slot >> kBitsPerCellLog2) & (kCellsPerBucket - 1); 224 *cell_index = (slot >> kBitsPerCellLog2) & (kCellsPerBucket - 1);
217 *bit_index = slot & (kBitsPerCell - 1); 225 *bit_index = slot & (kBitsPerCell - 1);
218 } 226 }
219 227
220 uint32_t* bucket[kBuckets]; 228 base::AtomicValue<base::AtomicValue<uint32_t>*> bucket[kBuckets];
221 Address page_start_; 229 Address page_start_;
222 }; 230 };
223 231
224 enum SlotType { 232 enum SlotType {
225 EMBEDDED_OBJECT_SLOT, 233 EMBEDDED_OBJECT_SLOT,
226 OBJECT_SLOT, 234 OBJECT_SLOT,
227 CELL_TARGET_SLOT, 235 CELL_TARGET_SLOT,
228 CODE_TARGET_SLOT, 236 CODE_TARGET_SLOT,
229 CODE_ENTRY_SLOT, 237 CODE_ENTRY_SLOT,
230 DEBUG_TARGET_SLOT, 238 DEBUG_TARGET_SLOT,
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 }; 363 };
356 364
357 Address page_start_; 365 Address page_start_;
358 Chunk* chunk_; 366 Chunk* chunk_;
359 }; 367 };
360 368
361 } // namespace internal 369 } // namespace internal
362 } // namespace v8 370 } // namespace v8
363 371
364 #endif // V8_SLOT_SET_H 372 #endif // V8_SLOT_SET_H
OLDNEW
« src/base/atomic-utils.h ('K') | « src/base/atomic-utils.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698