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/base/macros.h"
10 : #include "src/counters.h"
11 : #include "src/heap/incremental-marking.h"
12 : #include "src/isolate.h"
13 : #include "src/objects-inl.h"
14 : #include "src/v8.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 :
19 54999 : StoreBuffer::StoreBuffer(Heap* heap)
20 54999 : : heap_(heap), top_(nullptr), current_(0), mode_(NOT_IN_GC) {
21 164997 : for (int i = 0; i < kStoreBuffers; i++) {
22 109998 : start_[i] = nullptr;
23 109998 : limit_[i] = nullptr;
24 109998 : lazy_top_[i] = nullptr;
25 : }
26 54999 : task_running_ = false;
27 54999 : insertion_callback = &InsertDuringRuntime;
28 54999 : deletion_callback = &DeleteDuringRuntime;
29 54999 : }
30 :
31 54999 : void StoreBuffer::SetUp() {
32 : // Allocate 3x the buffer size, so that we can start the new store buffer
33 : // aligned to 2x the size. This lets us use a bit test to detect the end of
34 : // the area.
35 54999 : VirtualMemory reservation;
36 54999 : if (!AllocVirtualMemory(kStoreBufferSize * 3, heap_->GetRandomMmapAddr(),
37 54999 : &reservation)) {
38 0 : V8::FatalProcessOutOfMemory("StoreBuffer::SetUp");
39 : }
40 54999 : uintptr_t start_as_int = reinterpret_cast<uintptr_t>(reservation.address());
41 : start_[0] =
42 54999 : reinterpret_cast<Address*>(::RoundUp(start_as_int, kStoreBufferSize));
43 54999 : limit_[0] = start_[0] + (kStoreBufferSize / kPointerSize);
44 54999 : start_[1] = limit_[0];
45 54999 : limit_[1] = start_[1] + (kStoreBufferSize / kPointerSize);
46 :
47 : Address* vm_limit = reinterpret_cast<Address*>(
48 : reinterpret_cast<char*>(reservation.address()) + reservation.size());
49 :
50 : USE(vm_limit);
51 : for (int i = 0; i < kStoreBuffers; i++) {
52 : DCHECK(reinterpret_cast<Address>(start_[i]) >= reservation.address());
53 : DCHECK(reinterpret_cast<Address>(limit_[i]) >= reservation.address());
54 : DCHECK(start_[i] <= vm_limit);
55 : DCHECK(limit_[i] <= vm_limit);
56 : DCHECK_EQ(0, reinterpret_cast<uintptr_t>(limit_[i]) & kStoreBufferMask);
57 : }
58 :
59 54999 : if (!reservation.Commit(reinterpret_cast<Address>(start_[0]),
60 : kStoreBufferSize * kStoreBuffers,
61 54999 : false)) { // Not executable.
62 0 : V8::FatalProcessOutOfMemory("StoreBuffer::SetUp");
63 : }
64 54999 : current_ = 0;
65 54999 : top_ = start_[current_];
66 54999 : virtual_memory_.TakeControl(&reservation);
67 54999 : }
68 :
69 :
70 53365 : void StoreBuffer::TearDown() {
71 53365 : if (virtual_memory_.IsReserved()) virtual_memory_.Release();
72 53365 : top_ = nullptr;
73 160095 : for (int i = 0; i < kStoreBuffers; i++) {
74 106730 : start_[i] = nullptr;
75 106730 : limit_[i] = nullptr;
76 106730 : lazy_top_[i] = nullptr;
77 : }
78 53365 : }
79 :
80 85008 : int StoreBuffer::StoreBufferOverflow(Isolate* isolate) {
81 85008 : isolate->heap()->store_buffer()->FlipStoreBuffers();
82 85008 : isolate->counters()->store_buffer_overflows()->Increment();
83 : // Called by RecordWriteCodeStubAssembler, which doesnt accept void type
84 85008 : return 0;
85 : }
86 :
87 85008 : void StoreBuffer::FlipStoreBuffers() {
88 85008 : base::LockGuard<base::Mutex> guard(&mutex_);
89 85008 : int other = (current_ + 1) % kStoreBuffers;
90 85008 : MoveEntriesToRememberedSet(other);
91 85008 : lazy_top_[current_] = top_;
92 85008 : current_ = other;
93 85008 : top_ = start_[current_];
94 :
95 85008 : if (!task_running_ && FLAG_concurrent_store_buffer) {
96 79556 : task_running_ = true;
97 159112 : Task* task = new Task(heap_->isolate(), this);
98 79556 : V8::GetCurrentPlatform()->CallOnBackgroundThread(
99 79556 : task, v8::Platform::kShortRunningTask);
100 : }
101 85008 : }
102 :
103 337457 : void StoreBuffer::MoveEntriesToRememberedSet(int index) {
104 674911 : if (!lazy_top_[index]) return;
105 : DCHECK_GE(index, 0);
106 : DCHECK_LT(index, kStoreBuffers);
107 : Address last_inserted_addr = nullptr;
108 202358378 : for (Address* current = start_[index]; current < lazy_top_[index];
109 : current++) {
110 202186928 : Address addr = *current;
111 202186928 : Page* page = Page::FromAnyPointerAddress(heap_, addr);
112 202186920 : if (IsDeletionAddress(addr)) {
113 : last_inserted_addr = nullptr;
114 30336 : current++;
115 30336 : Address end = *current;
116 : DCHECK(!IsDeletionAddress(end));
117 : addr = UnmarkDeletionAddress(addr);
118 30336 : if (end) {
119 : RememberedSet<OLD_TO_NEW>::RemoveRange(page, addr, end,
120 29766 : SlotSet::PREFREE_EMPTY_BUCKETS);
121 : } else {
122 570 : RememberedSet<OLD_TO_NEW>::Remove(page, addr);
123 : }
124 : } else {
125 : DCHECK(!IsDeletionAddress(addr));
126 202156584 : if (addr != last_inserted_addr) {
127 151737249 : RememberedSet<OLD_TO_NEW>::Insert(page, addr);
128 : last_inserted_addr = addr;
129 : }
130 : }
131 : }
132 171450 : lazy_top_[index] = nullptr;
133 : }
134 :
135 86452 : void StoreBuffer::MoveAllEntriesToRememberedSet() {
136 86452 : base::LockGuard<base::Mutex> guard(&mutex_);
137 86452 : int other = (current_ + 1) % kStoreBuffers;
138 86452 : MoveEntriesToRememberedSet(other);
139 86452 : lazy_top_[current_] = top_;
140 86452 : MoveEntriesToRememberedSet(current_);
141 86452 : top_ = start_[current_];
142 86452 : }
143 :
144 79545 : void StoreBuffer::ConcurrentlyProcessStoreBuffer() {
145 79545 : base::LockGuard<base::Mutex> guard(&mutex_);
146 79545 : int other = (current_ + 1) % kStoreBuffers;
147 79545 : MoveEntriesToRememberedSet(other);
148 79545 : task_running_ = false;
149 79545 : }
150 :
151 : } // namespace internal
152 : } // namespace v8
|