Home | History | Annotate | Download | only in heap
      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