Line data Source code
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 60782 : StoreBuffer::StoreBuffer(Heap* heap)
19 : : heap_(heap),
20 : top_(nullptr),
21 : current_(0),
22 : mode_(NOT_IN_GC),
23 60782 : virtual_memory_(nullptr) {
24 182346 : for (int i = 0; i < kStoreBuffers; i++) {
25 121564 : start_[i] = nullptr;
26 121564 : limit_[i] = nullptr;
27 121564 : lazy_top_[i] = nullptr;
28 : }
29 60782 : task_running_ = false;
30 60782 : insertion_callback = &InsertDuringRuntime;
31 60782 : deletion_callback = &DeleteDuringRuntime;
32 60782 : }
33 :
34 60782 : 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 60782 : virtual_memory_ = new base::VirtualMemory(kStoreBufferSize * 3);
39 : uintptr_t start_as_int =
40 60782 : reinterpret_cast<uintptr_t>(virtual_memory_->address());
41 : start_[0] =
42 60782 : reinterpret_cast<Address*>(RoundUp(start_as_int, kStoreBufferSize));
43 60782 : limit_[0] = start_[0] + (kStoreBufferSize / kPointerSize);
44 60782 : start_[1] = limit_[0];
45 60782 : 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 60782 : if (!virtual_memory_->Commit(reinterpret_cast<Address>(start_[0]),
61 : kStoreBufferSize * kStoreBuffers,
62 60782 : false)) { // Not executable.
63 0 : V8::FatalProcessOutOfMemory("StoreBuffer::SetUp");
64 : }
65 60782 : current_ = 0;
66 60782 : top_ = start_[current_];
67 60782 : }
68 :
69 :
70 59285 : void StoreBuffer::TearDown() {
71 59285 : delete virtual_memory_;
72 59285 : top_ = nullptr;
73 177855 : for (int i = 0; i < kStoreBuffers; i++) {
74 118570 : start_[i] = nullptr;
75 118570 : limit_[i] = nullptr;
76 118570 : lazy_top_[i] = nullptr;
77 : }
78 59285 : }
79 :
80 :
81 244878 : void StoreBuffer::StoreBufferOverflow(Isolate* isolate) {
82 122439 : isolate->heap()->store_buffer()->FlipStoreBuffers();
83 122439 : isolate->counters()->store_buffer_overflows()->Increment();
84 122439 : }
85 :
86 122439 : void StoreBuffer::FlipStoreBuffers() {
87 122439 : base::LockGuard<base::Mutex> guard(&mutex_);
88 122439 : int other = (current_ + 1) % kStoreBuffers;
89 122439 : MoveEntriesToRememberedSet(other);
90 122439 : lazy_top_[current_] = top_;
91 122439 : current_ = other;
92 122439 : top_ = start_[current_];
93 :
94 122439 : if (!task_running_ && FLAG_concurrent_store_buffer) {
95 119046 : task_running_ = true;
96 238092 : Task* task = new Task(heap_->isolate(), this);
97 119046 : V8::GetCurrentPlatform()->CallOnBackgroundThread(
98 119046 : task, v8::Platform::kShortRunningTask);
99 : }
100 122439 : }
101 :
102 486529 : void StoreBuffer::MoveEntriesToRememberedSet(int index) {
103 973049 : if (!lazy_top_[index]) return;
104 : DCHECK_GE(index, 0);
105 : DCHECK_LT(index, kStoreBuffers);
106 284244375 : for (Address* current = start_[index]; current < lazy_top_[index];
107 : current++) {
108 283999428 : Address addr = *current;
109 283999428 : Page* page = Page::FromAnyPointerAddress(heap_, addr);
110 283999436 : if (IsDeletionAddress(addr)) {
111 122926 : current++;
112 122926 : Address end = *current;
113 : DCHECK(!IsDeletionAddress(end));
114 : addr = UnmarkDeletionAddress(addr);
115 122926 : if (end) {
116 : RememberedSet<OLD_TO_NEW>::RemoveRange(page, addr, end,
117 120167 : SlotSet::PREFREE_EMPTY_BUCKETS);
118 : } else {
119 2759 : RememberedSet<OLD_TO_NEW>::Remove(page, addr);
120 : }
121 : } else {
122 : DCHECK(!IsDeletionAddress(addr));
123 283876510 : RememberedSet<OLD_TO_NEW>::Insert(page, addr);
124 : }
125 : }
126 244947 : lazy_top_[index] = nullptr;
127 : }
128 :
129 122535 : void StoreBuffer::MoveAllEntriesToRememberedSet() {
130 122535 : base::LockGuard<base::Mutex> guard(&mutex_);
131 122535 : int other = (current_ + 1) % kStoreBuffers;
132 122535 : MoveEntriesToRememberedSet(other);
133 122535 : lazy_top_[current_] = top_;
134 122535 : MoveEntriesToRememberedSet(current_);
135 122535 : top_ = start_[current_];
136 122535 : }
137 :
138 119020 : void StoreBuffer::ConcurrentlyProcessStoreBuffer() {
139 119020 : base::LockGuard<base::Mutex> guard(&mutex_);
140 119020 : int other = (current_ + 1) % kStoreBuffers;
141 119020 : MoveEntriesToRememberedSet(other);
142 119020 : task_running_ = false;
143 119020 : }
144 :
145 : } // namespace internal
146 : } // namespace v8
|