• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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