1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/heap/store-buffer.h" 6 7 #include <algorithm> 8 9 #include "src/counters.h" 10 #include "src/heap/incremental-marking.h" 11 #include "src/isolate.h" 12 #include "src/objects-inl.h" 13 #include "src/v8.h" 14 15 namespace v8 { 16 namespace internal { 17 18 StoreBuffer::StoreBuffer(Heap* heap) 19 : heap_(heap), 20 top_(nullptr), 21 current_(0), 22 mode_(NOT_IN_GC), 23 virtual_memory_(nullptr) { 24 for (int i = 0; i < kStoreBuffers; i++) { 25 start_[i] = nullptr; 26 limit_[i] = nullptr; 27 lazy_top_[i] = nullptr; 28 } 29 task_running_ = false; 30 insertion_callback = &InsertDuringRuntime; 31 deletion_callback = &DeleteDuringRuntime; 32 } 33 34 void StoreBuffer::SetUp() { 35 // Allocate 3x the buffer size, so that we can start the new store buffer 36 // aligned to 2x the size. This lets us use a bit test to detect the end of 37 // the area. 38 virtual_memory_ = new base::VirtualMemory(kStoreBufferSize * 3); 39 uintptr_t start_as_int = 40 reinterpret_cast<uintptr_t>(virtual_memory_->address()); 41 start_[0] = 42 reinterpret_cast<Address*>(RoundUp(start_as_int, kStoreBufferSize)); 43 limit_[0] = start_[0] + (kStoreBufferSize / kPointerSize); 44 start_[1] = limit_[0]; 45 limit_[1] = start_[1] + (kStoreBufferSize / kPointerSize); 46 47 Address* vm_limit = reinterpret_cast<Address*>( 48 reinterpret_cast<char*>(virtual_memory_->address()) + 49 virtual_memory_->size()); 50 51 USE(vm_limit); 52 for (int i = 0; i < kStoreBuffers; i++) { 53 DCHECK(reinterpret_cast<Address>(start_[i]) >= virtual_memory_->address()); 54 DCHECK(reinterpret_cast<Address>(limit_[i]) >= virtual_memory_->address()); 55 DCHECK(start_[i] <= vm_limit); 56 DCHECK(limit_[i] <= vm_limit); 57 DCHECK((reinterpret_cast<uintptr_t>(limit_[i]) & kStoreBufferMask) == 0); 58 } 59 60 if (!virtual_memory_->Commit(reinterpret_cast<Address>(start_[0]), 61 kStoreBufferSize * kStoreBuffers, 62 false)) { // Not executable. 63 V8::FatalProcessOutOfMemory("StoreBuffer::SetUp"); 64 } 65 current_ = 0; 66 top_ = start_[current_]; 67 } 68 69 70 void StoreBuffer::TearDown() { 71 delete virtual_memory_; 72 top_ = nullptr; 73 for (int i = 0; i < kStoreBuffers; i++) { 74 start_[i] = nullptr; 75 limit_[i] = nullptr; 76 lazy_top_[i] = nullptr; 77 } 78 } 79 80 81 void StoreBuffer::StoreBufferOverflow(Isolate* isolate) { 82 isolate->heap()->store_buffer()->FlipStoreBuffers(); 83 isolate->counters()->store_buffer_overflows()->Increment(); 84 } 85 86 void StoreBuffer::FlipStoreBuffers() { 87 base::LockGuard<base::Mutex> guard(&mutex_); 88 int other = (current_ + 1) % kStoreBuffers; 89 MoveEntriesToRememberedSet(other); 90 lazy_top_[current_] = top_; 91 current_ = other; 92 top_ = start_[current_]; 93 94 if (!task_running_ && FLAG_concurrent_sweeping) { 95 task_running_ = true; 96 Task* task = new Task(heap_->isolate(), this); 97 V8::GetCurrentPlatform()->CallOnBackgroundThread( 98 task, v8::Platform::kShortRunningTask); 99 } 100 } 101 102 void StoreBuffer::MoveEntriesToRememberedSet(int index) { 103 if (!lazy_top_[index]) return; 104 DCHECK_GE(index, 0); 105 DCHECK_LT(index, kStoreBuffers); 106 for (Address* current = start_[index]; current < lazy_top_[index]; 107 current++) { 108 Address addr = *current; 109 Page* page = Page::FromAnyPointerAddress(heap_, addr); 110 if (IsDeletionAddress(addr)) { 111 current++; 112 Address end = *current; 113 DCHECK(!IsDeletionAddress(end)); 114 addr = UnmarkDeletionAddress(addr); 115 if (end) { 116 RememberedSet<OLD_TO_NEW>::RemoveRange(page, addr, end, 117 SlotSet::PREFREE_EMPTY_BUCKETS); 118 } else { 119 RememberedSet<OLD_TO_NEW>::Remove(page, addr); 120 } 121 } else { 122 DCHECK(!IsDeletionAddress(addr)); 123 RememberedSet<OLD_TO_NEW>::Insert(page, addr); 124 } 125 } 126 lazy_top_[index] = nullptr; 127 } 128 129 void StoreBuffer::MoveAllEntriesToRememberedSet() { 130 base::LockGuard<base::Mutex> guard(&mutex_); 131 int other = (current_ + 1) % kStoreBuffers; 132 MoveEntriesToRememberedSet(other); 133 lazy_top_[current_] = top_; 134 MoveEntriesToRememberedSet(current_); 135 top_ = start_[current_]; 136 } 137 138 void StoreBuffer::ConcurrentlyProcessStoreBuffer() { 139 base::LockGuard<base::Mutex> guard(&mutex_); 140 int other = (current_ + 1) % kStoreBuffers; 141 MoveEntriesToRememberedSet(other); 142 task_running_ = false; 143 } 144 145 } // namespace internal 146 } // namespace v8 147