1 // Copyright 2020 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/local-heap.h"
6
7 #include <memory>
8
9 #include "src/base/platform/mutex.h"
10 #include "src/common/globals.h"
11 #include "src/handles/local-handles.h"
12 #include "src/heap/heap-inl.h"
13 #include "src/heap/heap-write-barrier.h"
14 #include "src/heap/local-heap-inl.h"
15 #include "src/heap/marking-barrier.h"
16 #include "src/heap/safepoint.h"
17
18 namespace v8 {
19 namespace internal {
20
21 namespace {
22 thread_local LocalHeap* current_local_heap = nullptr;
23 } // namespace
24
Current()25 LocalHeap* LocalHeap::Current() { return current_local_heap; }
26
LocalHeap(Heap * heap,ThreadKind kind,std::unique_ptr<PersistentHandles> persistent_handles)27 LocalHeap::LocalHeap(Heap* heap, ThreadKind kind,
28 std::unique_ptr<PersistentHandles> persistent_handles)
29 : heap_(heap),
30 is_main_thread_(kind == ThreadKind::kMain),
31 state_(ThreadState::Parked),
32 safepoint_requested_(false),
33 allocation_failed_(false),
34 prev_(nullptr),
35 next_(nullptr),
36 handles_(new LocalHandles),
37 persistent_handles_(std::move(persistent_handles)),
38 marking_barrier_(new MarkingBarrier(this)),
39 old_space_allocator_(this, heap->old_space()) {
40 heap_->safepoint()->AddLocalHeap(this, [this] {
41 if (FLAG_local_heaps) {
42 WriteBarrier::SetForThread(marking_barrier_.get());
43 if (heap_->incremental_marking()->IsMarking()) {
44 marking_barrier_->Activate(
45 heap_->incremental_marking()->IsCompacting());
46 }
47 }
48 });
49
50 if (persistent_handles_) {
51 persistent_handles_->Attach(this);
52 }
53 DCHECK_NULL(current_local_heap);
54 current_local_heap = this;
55 }
56
~LocalHeap()57 LocalHeap::~LocalHeap() {
58 // Park thread since removing the local heap could block.
59 EnsureParkedBeforeDestruction();
60
61 heap_->safepoint()->RemoveLocalHeap(this, [this] {
62 old_space_allocator_.FreeLinearAllocationArea();
63
64 if (FLAG_local_heaps) {
65 marking_barrier_->Publish();
66 WriteBarrier::ClearForThread(marking_barrier_.get());
67 }
68 });
69
70 DCHECK_EQ(current_local_heap, this);
71 current_local_heap = nullptr;
72 }
73
EnsurePersistentHandles()74 void LocalHeap::EnsurePersistentHandles() {
75 if (!persistent_handles_) {
76 persistent_handles_.reset(
77 heap_->isolate()->NewPersistentHandles().release());
78 persistent_handles_->Attach(this);
79 }
80 }
81
AttachPersistentHandles(std::unique_ptr<PersistentHandles> persistent_handles)82 void LocalHeap::AttachPersistentHandles(
83 std::unique_ptr<PersistentHandles> persistent_handles) {
84 DCHECK_NULL(persistent_handles_);
85 persistent_handles_ = std::move(persistent_handles);
86 persistent_handles_->Attach(this);
87 }
88
DetachPersistentHandles()89 std::unique_ptr<PersistentHandles> LocalHeap::DetachPersistentHandles() {
90 if (persistent_handles_) persistent_handles_->Detach();
91 return std::move(persistent_handles_);
92 }
93
94 #ifdef DEBUG
ContainsPersistentHandle(Address * location)95 bool LocalHeap::ContainsPersistentHandle(Address* location) {
96 return persistent_handles_ ? persistent_handles_->Contains(location) : false;
97 }
98
ContainsLocalHandle(Address * location)99 bool LocalHeap::ContainsLocalHandle(Address* location) {
100 return handles_ ? handles_->Contains(location) : false;
101 }
102
IsHandleDereferenceAllowed()103 bool LocalHeap::IsHandleDereferenceAllowed() {
104 DCHECK_EQ(LocalHeap::Current(), this);
105 return state_ == ThreadState::Running;
106 }
107 #endif
108
IsParked()109 bool LocalHeap::IsParked() {
110 DCHECK_EQ(LocalHeap::Current(), this);
111 return state_ == ThreadState::Parked;
112 }
113
Park()114 void LocalHeap::Park() {
115 base::MutexGuard guard(&state_mutex_);
116 CHECK(state_ == ThreadState::Running);
117 state_ = ThreadState::Parked;
118 state_change_.NotifyAll();
119 }
120
Unpark()121 void LocalHeap::Unpark() {
122 base::MutexGuard guard(&state_mutex_);
123 CHECK(state_ == ThreadState::Parked);
124 state_ = ThreadState::Running;
125 }
126
EnsureParkedBeforeDestruction()127 void LocalHeap::EnsureParkedBeforeDestruction() {
128 if (IsParked()) return;
129 base::MutexGuard guard(&state_mutex_);
130 state_ = ThreadState::Parked;
131 state_change_.NotifyAll();
132 }
133
RequestSafepoint()134 void LocalHeap::RequestSafepoint() {
135 safepoint_requested_.store(true, std::memory_order_relaxed);
136 }
137
ClearSafepointRequested()138 void LocalHeap::ClearSafepointRequested() {
139 safepoint_requested_.store(false, std::memory_order_relaxed);
140 }
141
EnterSafepoint()142 void LocalHeap::EnterSafepoint() {
143 DCHECK_EQ(LocalHeap::Current(), this);
144 if (state_ == ThreadState::Running) heap_->safepoint()->EnterFromThread(this);
145 }
146
FreeLinearAllocationArea()147 void LocalHeap::FreeLinearAllocationArea() {
148 old_space_allocator_.FreeLinearAllocationArea();
149 }
150
MakeLinearAllocationAreaIterable()151 void LocalHeap::MakeLinearAllocationAreaIterable() {
152 old_space_allocator_.MakeLinearAllocationAreaIterable();
153 }
154
MarkLinearAllocationAreaBlack()155 void LocalHeap::MarkLinearAllocationAreaBlack() {
156 old_space_allocator_.MarkLinearAllocationAreaBlack();
157 }
158
UnmarkLinearAllocationArea()159 void LocalHeap::UnmarkLinearAllocationArea() {
160 old_space_allocator_.UnmarkLinearAllocationArea();
161 }
162
PerformCollection()163 void LocalHeap::PerformCollection() {
164 ParkedScope scope(this);
165 heap_->RequestCollectionBackground(this);
166 }
167
PerformCollectionAndAllocateAgain(int object_size,AllocationType type,AllocationOrigin origin,AllocationAlignment alignment)168 Address LocalHeap::PerformCollectionAndAllocateAgain(
169 int object_size, AllocationType type, AllocationOrigin origin,
170 AllocationAlignment alignment) {
171 allocation_failed_ = true;
172 static const int kMaxNumberOfRetries = 3;
173
174 for (int i = 0; i < kMaxNumberOfRetries; i++) {
175 PerformCollection();
176
177 AllocationResult result = AllocateRaw(object_size, type, origin, alignment);
178 if (!result.IsRetry()) {
179 allocation_failed_ = false;
180 return result.ToObjectChecked().address();
181 }
182 }
183
184 heap_->FatalProcessOutOfMemory("LocalHeap: allocation failed");
185 }
186
187 } // namespace internal
188 } // namespace v8
189