v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
local-heap.cc
Go to the documentation of this file.
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
6
7#include <atomic>
8#include <memory>
9#include <optional>
10
11#include "src/base/logging.h"
13#include "src/common/globals.h"
18#include "src/heap/gc-tracer.h"
19#include "src/heap/heap-inl.h"
21#include "src/heap/heap.h"
26#include "src/heap/safepoint.h"
27
28namespace v8 {
29namespace internal {
30
31thread_local LocalHeap* g_current_local_heap_ V8_CONSTINIT = nullptr;
32
33V8_TLS_DEFINE_GETTER(LocalHeap::Current, LocalHeap*, g_current_local_heap_)
34
35// static
36void LocalHeap::SetCurrent(LocalHeap* local_heap) {
37 g_current_local_heap_ = local_heap;
38}
39
40#ifdef DEBUG
41void LocalHeap::VerifyCurrent() const {
42 LocalHeap* current = LocalHeap::Current();
43
44 if (is_main_thread())
45 DCHECK_NULL(current);
46 else
47 DCHECK_EQ(current, this);
48}
49#endif
50
52 std::unique_ptr<PersistentHandles> persistent_handles)
53 : heap_(heap),
54 ptr_compr_cage_access_scope_(heap->isolate()),
55 is_main_thread_(kind == ThreadKind::kMain),
56 state_(ThreadState::Parked()),
57#if V8_OS_DARWIN
58 thread_handle_(pthread_self()),
59#endif
60 allocation_failed_(false),
61 nested_parked_scopes_(0),
62 prev_(nullptr),
63 next_(nullptr),
64 handles_(new LocalHandles),
65 persistent_handles_(std::move(persistent_handles)),
66 heap_allocator_(this) {
68 (v8_flags.concurrent_builtin_generation &&
69 heap->isolate()->IsGeneratingEmbeddedBuiltins()) ||
71 if (!is_main_thread()) {
74 }
75
76 heap_->safepoint()->AddLocalHeap(this, [this] {
77 if (!is_main_thread()) {
81 marking_barrier_->Activate(
84 }
85
87 }
88 });
89
91 persistent_handles_->Attach(this);
92 }
93 DCHECK_NULL(LocalHeap::Current());
94 if (!is_main_thread()) {
98 }
100}
101
103 // Park thread since removing the local heap could block.
105
106 heap_->safepoint()->RemoveLocalHeap(this, [this] {
108
109 if (!is_main_thread()) {
110 marking_barrier_->PublishIfNeeded();
111 marking_barrier_->PublishSharedIfNeeded();
112 MarkingBarrier* overwritten =
114 DCHECK_EQ(overwritten, marking_barrier_.get());
115 USE(overwritten);
116 }
117 });
118
119 if (!is_main_thread()) {
122 DCHECK_EQ(LocalHeap::Current(), this);
123 LocalHeap::SetCurrent(nullptr);
124 }
125
127}
128
137
139 LinearAllocationArea& old_allocation_info) {
141 DCHECK(IsRunning());
142 heap_allocator_.Setup(&new_allocation_info, &old_allocation_info);
145}
146
149 marking_barrier_ = std::make_unique<MarkingBarrier>(this);
150}
151
153#if DEBUG
154 // Ensure the thread is either in the running state or holds the safepoint
155 // lock. This guarantees that the state of incremental marking can't change
156 // concurrently (this requires a safepoint).
157 if (is_main_thread()) {
158 DCHECK(IsRunning());
159 } else {
161 }
162#endif // DEBUG
163
164 Isolate* isolate = heap_->isolate();
165
166 if (isolate->has_shared_space() && !isolate->is_shared_space_isolate()) {
167 if (isolate->shared_space_isolate()
168 ->heap()
169 ->incremental_marking()
170 ->IsMajorMarking()) {
171 marking_barrier_->ActivateShared();
172 }
173 }
174}
175
182
184 std::unique_ptr<PersistentHandles> persistent_handles) {
186 persistent_handles_ = std::move(persistent_handles);
187 persistent_handles_->Attach(this);
188}
189
190std::unique_ptr<PersistentHandles> LocalHeap::DetachPersistentHandles() {
192 return std::move(persistent_handles_);
193}
194
195#ifdef DEBUG
196bool LocalHeap::ContainsPersistentHandle(Address* location) {
197 return persistent_handles_ ? persistent_handles_->Contains(location) : false;
198}
199
200bool LocalHeap::ContainsLocalHandle(Address* location) {
201 return handles_ ? handles_->Contains(location) : false;
202}
203
204bool LocalHeap::IsHandleDereferenceAllowed() {
205 VerifyCurrent();
206 return IsRunning();
207}
208#endif
209
211#ifdef DEBUG
212 VerifyCurrent();
213#endif
214 return state_.load_relaxed().IsParked();
215}
216
218#ifdef DEBUG
219 VerifyCurrent();
220#endif
221 return state_.load_relaxed().IsRunning();
222}
223
225 while (true) {
226 ThreadState current_state = ThreadState::Running();
228 return;
229
230 // CAS above failed, so state is Running with some additional flag.
231 DCHECK(current_state.IsRunning());
232
233 if (is_main_thread()) {
234 DCHECK(current_state.IsSafepointRequested() ||
235 current_state.IsCollectionRequested());
236
237 if (current_state.IsSafepointRequested()) {
238 ThreadState old_state = state_.SetParked();
240 if (old_state.IsCollectionRequested())
241 heap_->collection_barrier_->CancelCollectionAndResumeThreads();
242 return;
243 }
244
245 if (current_state.IsCollectionRequested()) {
246 if (!heap()->ignore_local_gc_requests()) {
248 continue;
249 }
250
251 DCHECK(!current_state.IsSafepointRequested());
252
253 if (state_.CompareExchangeStrong(current_state,
254 current_state.SetParked())) {
255 heap_->collection_barrier_->CancelCollectionAndResumeThreads();
256 return;
257 } else {
258 continue;
259 }
260 }
261 } else {
262 DCHECK(current_state.IsSafepointRequested());
263 DCHECK(!current_state.IsCollectionRequested());
264
265 ThreadState old_state = state_.SetParked();
266 CHECK(old_state.IsRunning());
267 CHECK(old_state.IsSafepointRequested());
268 CHECK(!old_state.IsCollectionRequested());
269
271 return;
272 }
273 }
274}
275
277 while (true) {
278 ThreadState current_state = ThreadState::Parked();
280 return;
281
282 // CAS above failed, so state is Parked with some additional flag.
283 DCHECK(current_state.IsParked());
284
285 if (is_main_thread()) {
286 DCHECK(current_state.IsSafepointRequested() ||
287 current_state.IsCollectionRequested());
288
289 if (current_state.IsSafepointRequested()) {
291 continue;
292 }
293
294 if (current_state.IsCollectionRequested()) {
295 DCHECK(!current_state.IsSafepointRequested());
296
297 if (!state_.CompareExchangeStrong(current_state,
298 current_state.SetRunning()))
299 continue;
300
301 if (!heap()->ignore_local_gc_requests()) {
303 }
304
305 return;
306 }
307 } else {
308 DCHECK(current_state.IsSafepointRequested());
309 DCHECK(!current_state.IsCollectionRequested());
310
312 }
313 }
314}
315
318 ThreadKind thread_kind;
319
320 if (is_main_thread()) {
321 scope_id = GCTracer::Scope::UNPARK;
322 thread_kind = ThreadKind::kMain;
323 } else {
324 scope_id = GCTracer::Scope::BACKGROUND_UNPARK;
325 thread_kind = ThreadKind::kBackground;
326 }
327
328 TRACE_GC1(heap_->tracer(), scope_id, thread_kind);
330}
331
335
337 ThreadState current_state = state_.load_relaxed();
338 DCHECK(current_state.IsRunning());
339
340 if (is_main_thread()) {
341 DCHECK(current_state.IsSafepointRequested() ||
342 current_state.IsCollectionRequested());
343
344 if (current_state.IsSafepointRequested()) {
346 }
347
348 if (current_state.IsCollectionRequested()) {
350 }
351 } else {
352 DCHECK(current_state.IsSafepointRequested());
353 DCHECK(!current_state.IsCollectionRequested());
354
356 }
357}
358
361 ThreadKind thread_kind;
362
363 if (is_main_thread()) {
364 scope_id = GCTracer::Scope::SAFEPOINT;
365 thread_kind = ThreadKind::kMain;
366 } else {
367 scope_id = GCTracer::Scope::BACKGROUND_SAFEPOINT;
368 thread_kind = ThreadKind::kBackground;
369 }
370
371 TRACE_GC1(heap_->tracer(), scope_id, thread_kind);
372
373 ExecuteWithStackMarker([this]() {
374 // Parking the running thread here is an optimization. We do not need to
375 // wake this thread up to reach the next safepoint.
376 ThreadState old_state = state_.SetParked();
377 CHECK(old_state.IsRunning());
378 CHECK(old_state.IsSafepointRequested());
380
382
383 std::optional<IgnoreLocalGCRequests> ignore_gc_requests;
384 if (is_main_thread()) ignore_gc_requests.emplace(heap());
385 Unpark();
386 });
387}
388
389#ifdef DEBUG
390bool LocalHeap::IsSafeForConservativeStackScanning() const {
391#if defined(V8_ENABLE_DIRECT_HANDLE) && defined(ENABLE_SLOW_DCHECKS)
392 // There must be no direct handles on the stack below the stack marker.
393 if (DirectHandleBase::NumberOfHandles() > 0) return false;
394#endif // V8_ENABLE_DIRECT_HANDLE && ENABLE_SLOW_DCHECKS
395 // Check if we are inside at least one ParkedScope.
396 if (nested_parked_scopes_ > 0) {
397 // The main thread can avoid the trampoline, if it's not the main thread of
398 // a client isolate.
399 if (is_main_thread() && (heap()->isolate()->is_shared_space_isolate() ||
400 !heap()->isolate()->has_shared_space()))
401 return true;
402 // Otherwise, require that we're inside the trampoline.
403 return is_in_trampoline();
404 }
405 // Otherwise, we are reaching the initial parked state and the stack should
406 // not be interesting.
407 return true;
408}
409#endif // DEBUG
410
414
415#if DEBUG
416void LocalHeap::VerifyLinearAllocationAreas() const {
417 heap_allocator_.VerifyLinearAllocationAreas();
418}
419#endif // DEBUG
420
424
428
432
438
444
448
455
461
467
472
474 Tagged<HeapObject> object, int old_size, int new_size,
475 ClearRecordedSlots clear_recorded_slots) {
476 heap()->NotifyObjectSizeChange(object, old_size, new_size,
477 clear_recorded_slots);
478}
479
481 GlobalHandleVector<DescriptorArray> strong_descriptor_arrays) {
482 AsHeap()->WeakenDescriptorArrays(std::move(strong_descriptor_arrays));
483}
484
485} // namespace internal
486} // namespace v8
Builtins::Kind kind
Definition builtins.cc:40
void SetScanSimulatorCallback(StackVisitorCallback callback)
Definition stack.h:116
static Isolate * TryGetCurrent()
Definition api.cc:9954
void Remove(CallbackType callback, void *data)
void Invoke(GCType gc_type) const
void Add(CallbackType callback, void *data, GCType gc_type)
void Setup(LinearAllocationArea *new_allocation_info=nullptr, LinearAllocationArea *old_allocation_info=nullptr)
MainAllocator * shared_space_allocator()
std::unique_ptr< CollectionBarrier > collection_barrier_
Definition heap.h:2368
IncrementalMarking * incremental_marking() const
Definition heap.h:1062
void WeakenDescriptorArrays(GlobalHandleVector< DescriptorArray > strong_descriptor_arrays)
Definition heap.cc:5934
IsolateSafepoint * safepoint()
Definition heap.h:579
GCTracer * tracer()
Definition heap.h:800
Isolate * isolate() const
Definition heap-inl.h:61
void CollectGarbageForBackground(LocalHeap *local_heap)
Definition heap.cc:2106
void NotifyObjectSizeChange(Tagged< HeapObject >, int old_size, int new_size, ClearRecordedSlots clear_recorded_slots)
Definition heap.cc:4072
bool deserialization_complete() const
Definition heap.h:638
void AddLocalHeap(LocalHeap *local_heap, Callback callback)
Definition safepoint.h:120
void RemoveLocalHeap(LocalHeap *local_heap, Callback callback)
Definition safepoint.h:136
static void SetCurrent(Isolate *isolate)
Definition isolate.cc:528
static void IterateRegistersAndStackOfSimulator(::heap::base::StackVisitor *visitor)
Definition isolate.cc:3815
static V8_INLINE Isolate * Current()
Definition isolate-inl.h:35
std::unique_ptr< PersistentHandles > NewPersistentHandles()
Definition isolate.cc:5987
bool CompareExchangeStrong(ThreadState &expected, ThreadState updated)
Definition local-heap.h:292
constexpr bool IsRunning() const
Definition local-heap.h:252
constexpr bool IsCollectionRequested() const
Definition local-heap.h:268
constexpr ThreadState SetRunning() const V8_WARN_UNUSED_RESULT
Definition local-heap.h:254
static constexpr ThreadState Parked()
Definition local-heap.h:247
constexpr bool IsParked() const
Definition local-heap.h:258
constexpr ThreadState SetParked() const V8_WARN_UNUSED_RESULT
Definition local-heap.h:260
constexpr bool IsSafepointRequested() const
Definition local-heap.h:264
static constexpr ThreadState Running()
Definition local-heap.h:250
void WeakenDescriptorArrays(GlobalHandleVector< DescriptorArray > strong_descriptor_arrays)
bool is_main_thread() const
Definition local-heap.h:194
void InvokeGCEpilogueCallbacksInSafepoint(GCCallbacksInSafepoint::GCType gc_type)
Isolate * saved_current_isolate_
Definition local-heap.h:389
void MarkSharedLinearAllocationAreasBlack()
LocalHeap(Heap *heap, ThreadKind kind, std::unique_ptr< PersistentHandles > persistent_handles=nullptr)
Definition local-heap.cc:51
void(void *) GCEpilogueCallback
Definition local-heap.h:52
std::unique_ptr< PersistentHandles > DetachPersistentHandles()
V8_INLINE bool is_in_trampoline() const
Heap * heap() const
Definition local-heap.h:122
::heap::base::Stack stack_
Definition local-heap.h:405
void FreeLinearAllocationAreasAndResetFreeLists()
AtomicThreadState state_
Definition local-heap.h:380
void MarkLinearAllocationAreasBlack()
void UnmarkSharedLinearAllocationsArea()
std::unique_ptr< MarkingBarrier > marking_barrier_
Definition local-heap.h:396
void NotifyObjectSizeChange(Tagged< HeapObject > object, int old_size, int new_size, ClearRecordedSlots clear_recorded_slots)
HeapAllocator heap_allocator_
Definition local-heap.h:400
void SetUpMainThread(LinearAllocationArea &new_allocation_info, LinearAllocationArea &old_allocation_info)
Heap * AsHeap() const
Definition local-heap.h:123
GCCallbacksInSafepoint gc_epilogue_callbacks_
Definition local-heap.h:398
void MakeLinearAllocationAreasIterable()
std::unique_ptr< LocalHandles > handles_
Definition local-heap.h:394
MarkingBarrier * saved_marking_barrier_
Definition local-heap.h:402
V8_INLINE void ExecuteWithStackMarker(Callback callback)
std::unique_ptr< PersistentHandles > persistent_handles_
Definition local-heap.h:395
void AttachPersistentHandles(std::unique_ptr< PersistentHandles > persistent_handles)
static void SetCurrent(LocalHeap *local_heap)
Definition local-heap.cc:36
void RemoveGCEpilogueCallback(GCEpilogueCallback *callback, void *data)
void AddGCEpilogueCallback(GCEpilogueCallback *callback, void *data, GCCallbacksInSafepoint::GCType gc_type=GCCallbacksInSafepoint::GCType::kAll)
void FreeSharedLinearAllocationAreasAndResetFreeLists()
V8_EXPORT_PRIVATE void MarkLinearAllocationAreaBlack()
V8_EXPORT_PRIVATE void UnmarkLinearAllocationArea()
V8_EXPORT_PRIVATE void FreeLinearAllocationAreaAndResetFreeList()
static MarkingBarrier * SetForThread(MarkingBarrier *marking_barrier)
enum v8::internal::@1270::DeoptimizableCodeIterator::@67 state_
#define TRACE_GC1(tracer, scope_id, thread_kind)
Definition gc-tracer.h:62
Isolate * isolate
TNode< Object > callback
STL namespace.
ClearRecordedSlots
Definition heap.h:137
thread_local Isolate::PerIsolateThreadData *g_current_per_isolate_thread_data_ V8_CONSTINIT
Definition isolate.cc:522
V8_EXPORT_PRIVATE FlagValues v8_flags
Node * prev_
#define DCHECK_NULL(val)
Definition logging.h:491
#define CHECK_IMPLIES(lhs, rhs)
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
#define V8_TLS_DEFINE_GETTER(Name, Type, Member)
Heap * heap_