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

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

Issue 2352423002: [heap] Concurrently free empty typed slot set chunks. (Closed)
Patch Set: Allocate top level chunk 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.cc ('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 <stack>
9
8 #include "src/allocation.h" 10 #include "src/allocation.h"
9 #include "src/base/atomic-utils.h" 11 #include "src/base/atomic-utils.h"
10 #include "src/base/bits.h" 12 #include "src/base/bits.h"
11 #include "src/utils.h" 13 #include "src/utils.h"
12 14
13 namespace v8 { 15 namespace v8 {
14 namespace internal { 16 namespace internal {
15 17
16 enum SlotCallbackResult { KEEP_SLOT, REMOVE_SLOT }; 18 enum SlotCallbackResult { KEEP_SLOT, REMOVE_SLOT };
17 19
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
252 254
253 // Data structure for maintaining a multiset of typed slots in a page. 255 // Data structure for maintaining a multiset of typed slots in a page.
254 // Typed slots can only appear in Code and JSFunction objects, so 256 // Typed slots can only appear in Code and JSFunction objects, so
255 // the maximum possible offset is limited by the LargePage::kMaxCodePageSize. 257 // 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 258 // The implementation is a chain of chunks, where each chunks is an array of
257 // encoded (slot type, slot offset) pairs. 259 // encoded (slot type, slot offset) pairs.
258 // There is no duplicate detection and we do not expect many duplicates because 260 // 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. 261 // typed slots contain V8 internal pointers that are not directly exposed to JS.
260 class TypedSlotSet { 262 class TypedSlotSet {
261 public: 263 public:
264 enum IterationMode { PREFREE_EMPTY_CHUNKS, KEEP_EMPTY_CHUNKS };
265
262 typedef std::pair<SlotType, uint32_t> TypeAndOffset; 266 typedef std::pair<SlotType, uint32_t> TypeAndOffset;
263 267
264 struct TypedSlot { 268 struct TypedSlot {
265 TypedSlot() { 269 TypedSlot() {
266 type_and_offset_.SetValue(0); 270 type_and_offset_.SetValue(0);
267 host_offset_.SetValue(0); 271 host_offset_.SetValue(0);
268 } 272 }
269 273
270 TypedSlot(SlotType type, uint32_t host_offset, uint32_t offset) { 274 TypedSlot(SlotType type, uint32_t host_offset, uint32_t offset) {
271 type_and_offset_.SetValue(TypeField::encode(type) | 275 type_and_offset_.SetValue(TypeField::encode(type) |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 delete chunk; 323 delete chunk;
320 chunk = next; 324 chunk = next;
321 } 325 }
322 } 326 }
323 327
324 // The slot offset specifies a slot at address page_start_ + offset. 328 // The slot offset specifies a slot at address page_start_ + offset.
325 // This method can only be called on the main thread. 329 // This method can only be called on the main thread.
326 void Insert(SlotType type, uint32_t host_offset, uint32_t offset) { 330 void Insert(SlotType type, uint32_t host_offset, uint32_t offset) {
327 TypedSlot slot(type, host_offset, offset); 331 TypedSlot slot(type, host_offset, offset);
328 Chunk* top_chunk = chunk_.Value(); 332 Chunk* top_chunk = chunk_.Value();
333 if (!top_chunk) {
334 top_chunk = new Chunk(nullptr, kInitialBufferSize);
335 chunk_.SetValue(top_chunk);
336 }
329 if (!top_chunk->AddSlot(slot)) { 337 if (!top_chunk->AddSlot(slot)) {
330 Chunk* new_top_chunk = 338 Chunk* new_top_chunk =
331 new Chunk(top_chunk, NextCapacity(top_chunk->capacity.Value())); 339 new Chunk(top_chunk, NextCapacity(top_chunk->capacity.Value()));
332 bool added = new_top_chunk->AddSlot(slot); 340 bool added = new_top_chunk->AddSlot(slot);
333 chunk_.SetValue(new_top_chunk); 341 chunk_.SetValue(new_top_chunk);
334 DCHECK(added); 342 DCHECK(added);
335 USE(added); 343 USE(added);
336 } 344 }
337 } 345 }
338 346
339 // Iterate over all slots in the set and for each slot invoke the callback. 347 // Iterate over all slots in the set and for each slot invoke the callback.
340 // If the callback returns REMOVE_SLOT then the slot is removed from the set. 348 // If the callback returns REMOVE_SLOT then the slot is removed from the set.
341 // Returns the new number of slots. 349 // Returns the new number of slots.
342 // 350 //
343 // Sample usage: 351 // Sample usage:
344 // Iterate([](SlotType slot_type, Address slot_address) { 352 // Iterate([](SlotType slot_type, Address slot_address) {
345 // if (good(slot_type, slot_address)) return KEEP_SLOT; 353 // if (good(slot_type, slot_address)) return KEEP_SLOT;
346 // else return REMOVE_SLOT; 354 // else return REMOVE_SLOT;
347 // }); 355 // });
348 template <typename Callback> 356 template <typename Callback>
349 int Iterate(Callback callback) { 357 int Iterate(Callback callback, IterationMode mode) {
350 STATIC_ASSERT(CLEARED_SLOT < 8); 358 STATIC_ASSERT(CLEARED_SLOT < 8);
351 Chunk* chunk = chunk_.Value(); 359 Chunk* chunk = chunk_.Value();
360 Chunk* previous = nullptr;
352 int new_count = 0; 361 int new_count = 0;
353 while (chunk != nullptr) { 362 while (chunk != nullptr) {
354 TypedSlot* buffer = chunk->buffer.Value(); 363 TypedSlot* buffer = chunk->buffer.Value();
355 int count = chunk->count.Value(); 364 int count = chunk->count.Value();
365 bool empty = true;
356 for (int i = 0; i < count; i++) { 366 for (int i = 0; i < count; i++) {
357 // Order is important here. We have to read out the slot type last to 367 // Order is important here. We have to read out the slot type last to
358 // observe the concurrent removal case consistently. 368 // observe the concurrent removal case consistently.
359 Address host_addr = page_start_ + buffer[i].host_offset(); 369 Address host_addr = page_start_ + buffer[i].host_offset();
360 TypeAndOffset type_and_offset = buffer[i].GetTypeAndOffset(); 370 TypeAndOffset type_and_offset = buffer[i].GetTypeAndOffset();
361 SlotType type = type_and_offset.first; 371 SlotType type = type_and_offset.first;
362 if (type != CLEARED_SLOT) { 372 if (type != CLEARED_SLOT) {
363 Address addr = page_start_ + type_and_offset.second; 373 Address addr = page_start_ + type_and_offset.second;
364 if (callback(type, host_addr, addr) == KEEP_SLOT) { 374 if (callback(type, host_addr, addr) == KEEP_SLOT) {
365 new_count++; 375 new_count++;
376 empty = false;
366 } else { 377 } else {
367 buffer[i].Clear(); 378 buffer[i].Clear();
368 } 379 }
369 } 380 }
370 } 381 }
382
383 if (mode == PREFREE_EMPTY_CHUNKS && empty) {
384 // We remove the chunk from the list but let it still point its next
385 // chunk to allow concurrent iteration.
386 if (previous) {
387 previous->next.SetValue(chunk->next.Value());
388 } else {
389 chunk_.SetValue(chunk->next.Value());
390 }
391 base::LockGuard<base::Mutex> guard(&to_be_freed_chunks_mutex_);
392 to_be_freed_chunks_.push(chunk);
393 } else {
394 previous = chunk;
395 }
371 chunk = chunk->next.Value(); 396 chunk = chunk->next.Value();
372 } 397 }
373 return new_count; 398 return new_count;
374 } 399 }
375 400
401 void FreeToBeFreedChunks() {
402 base::LockGuard<base::Mutex> guard(&to_be_freed_chunks_mutex_);
403 while (!to_be_freed_chunks_.empty()) {
404 Chunk* top = to_be_freed_chunks_.top();
405 to_be_freed_chunks_.pop();
406 delete top;
407 }
408 }
409
376 private: 410 private:
377 static const int kInitialBufferSize = 100; 411 static const int kInitialBufferSize = 100;
378 static const int kMaxBufferSize = 16 * KB; 412 static const int kMaxBufferSize = 16 * KB;
379 413
380 static int NextCapacity(int capacity) { 414 static int NextCapacity(int capacity) {
381 return Min(kMaxBufferSize, capacity * 2); 415 return Min(kMaxBufferSize, capacity * 2);
382 } 416 }
383 417
384 class OffsetField : public BitField<int, 0, 29> {}; 418 class OffsetField : public BitField<int, 0, 29> {};
385 class TypeField : public BitField<SlotType, 29, 3> {}; 419 class TypeField : public BitField<SlotType, 29, 3> {};
(...skipping 18 matching lines...) Expand all
404 } 438 }
405 ~Chunk() { DeleteArray(buffer.Value()); } 439 ~Chunk() { DeleteArray(buffer.Value()); }
406 base::AtomicValue<Chunk*> next; 440 base::AtomicValue<Chunk*> next;
407 base::AtomicValue<int> count; 441 base::AtomicValue<int> count;
408 base::AtomicValue<int> capacity; 442 base::AtomicValue<int> capacity;
409 base::AtomicValue<TypedSlot*> buffer; 443 base::AtomicValue<TypedSlot*> buffer;
410 }; 444 };
411 445
412 Address page_start_; 446 Address page_start_;
413 base::AtomicValue<Chunk*> chunk_; 447 base::AtomicValue<Chunk*> chunk_;
448 base::Mutex to_be_freed_chunks_mutex_;
449 std::stack<Chunk*> to_be_freed_chunks_;
414 }; 450 };
415 451
416 } // namespace internal 452 } // namespace internal
417 } // namespace v8 453 } // namespace v8
418 454
419 #endif // V8_SLOT_SET_H 455 #endif // V8_SLOT_SET_H
OLDNEW
« no previous file with comments | « src/heap/remembered-set.cc ('k') | test/unittests/heap/slot-set-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698