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