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

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

Issue 2360513002: [heap] Make typed slot set state and operations atomic. (Closed)
Patch Set: remove include 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
« no previous file with comments | « src/heap/remembered-set.h ('k') | test/unittests/heap/slot-set-unittest.cc » ('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_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/atomic-utils.h"
10 #include "src/base/bits.h" 10 #include "src/base/bits.h"
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 Address page_start_; 240 Address page_start_;
241 }; 241 };
242 242
243 enum SlotType { 243 enum SlotType {
244 EMBEDDED_OBJECT_SLOT, 244 EMBEDDED_OBJECT_SLOT,
245 OBJECT_SLOT, 245 OBJECT_SLOT,
246 CELL_TARGET_SLOT, 246 CELL_TARGET_SLOT,
247 CODE_TARGET_SLOT, 247 CODE_TARGET_SLOT,
248 CODE_ENTRY_SLOT, 248 CODE_ENTRY_SLOT,
249 DEBUG_TARGET_SLOT, 249 DEBUG_TARGET_SLOT,
250 NUMBER_OF_SLOT_TYPES 250 CLEARED_SLOT
251 }; 251 };
252 252
253 // Data structure for maintaining a multiset of typed slots in a page. 253 // Data structure for maintaining a multiset of typed slots in a page.
254 // Typed slots can only appear in Code and JSFunction objects, so 254 // Typed slots can only appear in Code and JSFunction objects, so
255 // the maximum possible offset is limited by the LargePage::kMaxCodePageSize. 255 // the maximum possible offset is limited by the LargePage::kMaxCodePageSize.
256 // The implementation is a chain of chunks, where each chunks is an array of 256 // The implementation is a chain of chunks, where each chunks is an array of
257 // encoded (slot type, slot offset) pairs. 257 // encoded (slot type, slot offset) pairs.
258 // There is no duplicate detection and we do not expect many duplicates because 258 // There is no duplicate detection and we do not expect many duplicates because
259 // typed slots contain V8 internal pointers that are not directly exposed to JS. 259 // typed slots contain V8 internal pointers that are not directly exposed to JS.
260 class TypedSlotSet { 260 class TypedSlotSet {
261 public: 261 public:
262 typedef std::pair<SlotType, uint32_t> TypeAndOffset;
263
262 struct TypedSlot { 264 struct TypedSlot {
263 TypedSlot() : type_and_offset_(0), host_offset_(0) {} 265 TypedSlot() {
266 type_and_offset_.SetValue(0);
267 host_offset_.SetValue(0);
268 }
264 269
265 TypedSlot(SlotType type, uint32_t host_offset, uint32_t offset) 270 TypedSlot(SlotType type, uint32_t host_offset, uint32_t offset) {
266 : type_and_offset_(TypeField::encode(type) | 271 type_and_offset_.SetValue(TypeField::encode(type) |
267 OffsetField::encode(offset)), 272 OffsetField::encode(offset));
268 host_offset_(host_offset) {} 273 host_offset_.SetValue(host_offset);
274 }
269 275
270 bool operator==(const TypedSlot other) { 276 bool operator==(const TypedSlot other) {
271 return type_and_offset_ == other.type_and_offset_ && 277 return type_and_offset_.Value() == other.type_and_offset_.Value() &&
272 host_offset_ == other.host_offset_; 278 host_offset_.Value() == other.host_offset_.Value();
273 } 279 }
274 280
275 bool operator!=(const TypedSlot other) { return !(*this == other); } 281 bool operator!=(const TypedSlot other) { return !(*this == other); }
276 282
277 SlotType type() { return TypeField::decode(type_and_offset_); } 283 SlotType type() { return TypeField::decode(type_and_offset_.Value()); }
278 284
279 uint32_t offset() { return OffsetField::decode(type_and_offset_); } 285 uint32_t offset() { return OffsetField::decode(type_and_offset_.Value()); }
280 286
281 uint32_t host_offset() { return host_offset_; } 287 TypeAndOffset GetTypeAndOffset() {
288 uint32_t type_and_offset = type_and_offset_.Value();
289 return std::make_pair(TypeField::decode(type_and_offset),
290 OffsetField::decode(type_and_offset));
291 }
282 292
283 uint32_t type_and_offset_; 293 uint32_t host_offset() { return host_offset_.Value(); }
284 uint32_t host_offset_; 294
295 void Set(TypedSlot slot) {
296 type_and_offset_.SetValue(slot.type_and_offset_.Value());
297 host_offset_.SetValue(slot.host_offset_.Value());
298 }
299
300 void Clear() {
301 type_and_offset_.SetValue(TypeField::encode(CLEARED_SLOT) |
302 OffsetField::encode(0));
303 host_offset_.SetValue(0);
304 }
305
306 base::AtomicValue<uint32_t> type_and_offset_;
307 base::AtomicValue<uint32_t> host_offset_;
285 }; 308 };
286 static const int kMaxOffset = 1 << 29; 309 static const int kMaxOffset = 1 << 29;
287 310
288 explicit TypedSlotSet(Address page_start) : page_start_(page_start) { 311 explicit TypedSlotSet(Address page_start) : page_start_(page_start) {
289 chunk_ = new Chunk(nullptr, kInitialBufferSize); 312 chunk_.SetValue(new Chunk(nullptr, kInitialBufferSize));
290 } 313 }
291 314
292 ~TypedSlotSet() { 315 ~TypedSlotSet() {
293 Chunk* chunk = chunk_; 316 Chunk* chunk = chunk_.Value();
294 while (chunk != nullptr) { 317 while (chunk != nullptr) {
295 Chunk* next = chunk->next; 318 Chunk* next = chunk->next.Value();
296 delete chunk; 319 delete chunk;
297 chunk = next; 320 chunk = next;
298 } 321 }
299 } 322 }
300 323
301 // The slot offset specifies a slot at address page_start_ + offset. 324 // The slot offset specifies a slot at address page_start_ + offset.
325 // This method can only be called on the main thread.
302 void Insert(SlotType type, uint32_t host_offset, uint32_t offset) { 326 void Insert(SlotType type, uint32_t host_offset, uint32_t offset) {
303 TypedSlot slot(type, host_offset, offset); 327 TypedSlot slot(type, host_offset, offset);
304 if (!chunk_->AddSlot(slot)) { 328 Chunk* top_chunk = chunk_.Value();
305 chunk_ = new Chunk(chunk_, NextCapacity(chunk_->capacity)); 329 if (!top_chunk->AddSlot(slot)) {
306 bool added = chunk_->AddSlot(slot); 330 Chunk* new_top_chunk =
331 new Chunk(top_chunk, NextCapacity(top_chunk->capacity.Value()));
332 bool added = new_top_chunk->AddSlot(slot);
333 chunk_.SetValue(new_top_chunk);
307 DCHECK(added); 334 DCHECK(added);
308 USE(added); 335 USE(added);
309 } 336 }
310 } 337 }
311 338
312 // Iterate over all slots in the set and for each slot invoke the callback. 339 // Iterate over all slots in the set and for each slot invoke the callback.
313 // If the callback returns REMOVE_SLOT then the slot is removed from the set. 340 // If the callback returns REMOVE_SLOT then the slot is removed from the set.
314 // Returns the new number of slots. 341 // Returns the new number of slots.
315 // 342 //
316 // Sample usage: 343 // Sample usage:
317 // Iterate([](SlotType slot_type, Address slot_address) { 344 // Iterate([](SlotType slot_type, Address slot_address) {
318 // if (good(slot_type, slot_address)) return KEEP_SLOT; 345 // if (good(slot_type, slot_address)) return KEEP_SLOT;
319 // else return REMOVE_SLOT; 346 // else return REMOVE_SLOT;
320 // }); 347 // });
321 template <typename Callback> 348 template <typename Callback>
322 int Iterate(Callback callback) { 349 int Iterate(Callback callback) {
323 STATIC_ASSERT(NUMBER_OF_SLOT_TYPES < 8); 350 STATIC_ASSERT(CLEARED_SLOT < 8);
324 const TypedSlot kRemovedSlot(NUMBER_OF_SLOT_TYPES, 0, 0); 351 Chunk* chunk = chunk_.Value();
325 Chunk* chunk = chunk_;
326 int new_count = 0; 352 int new_count = 0;
327 while (chunk != nullptr) { 353 while (chunk != nullptr) {
328 TypedSlot* buffer = chunk->buffer; 354 TypedSlot* buffer = chunk->buffer.Value();
329 int count = chunk->count; 355 int count = chunk->count.Value();
330 for (int i = 0; i < count; i++) { 356 for (int i = 0; i < count; i++) {
331 TypedSlot slot = buffer[i]; 357 // Order is important here. We have to read out the slot type last to
332 if (slot != kRemovedSlot) { 358 // observe the concurrent removal case consistently.
333 SlotType type = slot.type(); 359 Address host_addr = page_start_ + buffer[i].host_offset();
334 Address addr = page_start_ + slot.offset(); 360 TypeAndOffset type_and_offset = buffer[i].GetTypeAndOffset();
335 Address host_addr = page_start_ + slot.host_offset(); 361 SlotType type = type_and_offset.first;
362 if (type != CLEARED_SLOT) {
363 Address addr = page_start_ + type_and_offset.second;
336 if (callback(type, host_addr, addr) == KEEP_SLOT) { 364 if (callback(type, host_addr, addr) == KEEP_SLOT) {
337 new_count++; 365 new_count++;
338 } else { 366 } else {
339 buffer[i] = kRemovedSlot; 367 buffer[i].Clear();
340 } 368 }
341 } 369 }
342 } 370 }
343 chunk = chunk->next; 371 chunk = chunk->next.Value();
344 } 372 }
345 return new_count; 373 return new_count;
346 } 374 }
347 375
348 private: 376 private:
349 static const int kInitialBufferSize = 100; 377 static const int kInitialBufferSize = 100;
350 static const int kMaxBufferSize = 16 * KB; 378 static const int kMaxBufferSize = 16 * KB;
351 379
352 static int NextCapacity(int capacity) { 380 static int NextCapacity(int capacity) {
353 return Min(kMaxBufferSize, capacity * 2); 381 return Min(kMaxBufferSize, capacity * 2);
354 } 382 }
355 383
356 class OffsetField : public BitField<int, 0, 29> {}; 384 class OffsetField : public BitField<int, 0, 29> {};
357 class TypeField : public BitField<SlotType, 29, 3> {}; 385 class TypeField : public BitField<SlotType, 29, 3> {};
358 386
359 struct Chunk : Malloced { 387 struct Chunk : Malloced {
360 explicit Chunk(Chunk* next_chunk, int capacity) 388 explicit Chunk(Chunk* next_chunk, int chunk_capacity) {
361 : next(next_chunk), count(0), capacity(capacity) { 389 count.SetValue(0);
362 buffer = NewArray<TypedSlot>(capacity); 390 capacity.SetValue(chunk_capacity);
391 buffer.SetValue(NewArray<TypedSlot>(chunk_capacity));
392 next.SetValue(next_chunk);
363 } 393 }
364 bool AddSlot(TypedSlot slot) { 394 bool AddSlot(TypedSlot slot) {
365 if (count == capacity) return false; 395 int current_count = count.Value();
366 buffer[count++] = slot; 396 if (current_count == capacity.Value()) return false;
397 TypedSlot* current_buffer = buffer.Value();
398 // Order is important here. We have to write the slot first before
399 // increasing the counter to guarantee that a consistent state is
400 // observed by concurrent threads.
401 current_buffer[current_count].Set(slot);
402 count.SetValue(current_count + 1);
367 return true; 403 return true;
368 } 404 }
369 ~Chunk() { DeleteArray(buffer); } 405 ~Chunk() { DeleteArray(buffer.Value()); }
370 Chunk* next; 406 base::AtomicValue<Chunk*> next;
371 int count; 407 base::AtomicValue<int> count;
372 int capacity; 408 base::AtomicValue<int> capacity;
373 TypedSlot* buffer; 409 base::AtomicValue<TypedSlot*> buffer;
374 }; 410 };
375 411
376 Address page_start_; 412 Address page_start_;
377 Chunk* chunk_; 413 base::AtomicValue<Chunk*> chunk_;
378 }; 414 };
379 415
380 } // namespace internal 416 } // namespace internal
381 } // namespace v8 417 } // namespace v8
382 418
383 #endif // V8_SLOT_SET_H 419 #endif // V8_SLOT_SET_H
OLDNEW
« no previous file with comments | « src/heap/remembered-set.h ('k') | test/unittests/heap/slot-set-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698