v8 12.4.254 (node 22.4.1)
V8 is Google's open source JavaScript engine
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
visitor.h
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
5#ifndef INCLUDE_CPPGC_VISITOR_H_
6#define INCLUDE_CPPGC_VISITOR_H_
7
8#include <type_traits>
9
10#include "cppgc/custom-space.h"
17#include "cppgc/member.h"
20#include "cppgc/trace-trait.h"
21#include "cppgc/type-traits.h"
22
23namespace cppgc {
24
25namespace internal {
26template <typename T, typename WeaknessPolicy, typename LocationPolicy,
27 typename CheckingPolicy>
28class BasicCrossThreadPersistent;
29template <typename T, typename WeaknessPolicy, typename LocationPolicy,
30 typename CheckingPolicy>
31class BasicPersistent;
32class ConservativeTracingVisitor;
33class VisitorBase;
34class VisitorFactory;
35} // namespace internal
36
37using WeakCallback = void (*)(const LivenessBroker&, const void*);
38
57 public:
58 class Key {
59 private:
60 Key() = default;
61 friend class internal::VisitorFactory;
62 };
63
64 explicit Visitor(Key) {}
65
66 virtual ~Visitor() = default;
67
73 template <typename T>
74 void Trace(const Member<T>& member) {
75 const T* value = member.GetRawAtomic();
77 TraceImpl(value);
78 }
79
85 template <typename T>
86 void Trace(const WeakMember<T>& weak_member) {
87 static_assert(sizeof(T), "Pointee type must be fully defined.");
89 "T must be GarbageCollected or GarbageCollectedMixin type");
91 "Weak references to compactable objects are not allowed");
92
93 const T* value = weak_member.GetRawAtomic();
94
95 // Bailout assumes that WeakMember emits write barrier.
96 if (!value) {
97 return;
98 }
99
101 VisitWeak(value, TraceTrait<T>::GetTraceDescriptor(value),
102 &HandleWeak<WeakMember<T>>, &weak_member);
103 }
104
105#if defined(CPPGC_POINTER_COMPRESSION)
111 template <typename T>
112 void Trace(const subtle::UncompressedMember<T>& member) {
113 const T* value = member.GetRawAtomic();
114 CPPGC_DCHECK(value != kSentinelPointer);
115 TraceImpl(value);
116 }
117#endif // defined(CPPGC_POINTER_COMPRESSION)
118
119 template <typename T>
120 void TraceMultiple(const subtle::UncompressedMember<T>* start, size_t len) {
121 static_assert(sizeof(T), "Pointee type must be fully defined.");
123 "T must be GarbageCollected or GarbageCollectedMixin type");
124 VisitMultipleUncompressedMember(start, len,
126 }
127
128 template <typename T,
129 std::enable_if_t<!std::is_same_v<
131 void TraceMultiple(const Member<T>* start, size_t len) {
132 static_assert(sizeof(T), "Pointee type must be fully defined.");
134 "T must be GarbageCollected or GarbageCollectedMixin type");
135#if defined(CPPGC_POINTER_COMPRESSION)
136 static_assert(std::is_same_v<Member<T>, subtle::CompressedMember<T>>,
137 "Member and CompressedMember must be the same.");
138 VisitMultipleCompressedMember(start, len,
140#endif // defined(CPPGC_POINTER_COMPRESSION)
141 }
142
149 template <typename T>
150 void Trace(const T& object) {
151#if V8_ENABLE_CHECKS
152 // This object is embedded in potentially multiple nested objects. The
153 // outermost object must not be in construction as such objects are (a) not
154 // processed immediately, and (b) only processed conservatively if not
155 // otherwise possible.
156 CheckObjectNotInConstruction(&object);
157#endif // V8_ENABLE_CHECKS
158 TraceTrait<T>::Trace(this, &object);
159 }
160
161 template <typename T>
162 void TraceMultiple(const T* start, size_t len) {
163#if V8_ENABLE_CHECKS
164 // This object is embedded in potentially multiple nested objects. The
165 // outermost object must not be in construction as such objects are (a) not
166 // processed immediately, and (b) only processed conservatively if not
167 // otherwise possible.
168 CheckObjectNotInConstruction(start);
169#endif // V8_ENABLE_CHECKS
170 for (size_t i = 0; i < len; ++i) {
171 const T* object = &start[i];
172 if constexpr (std::is_polymorphic_v<T>) {
173 // The object's vtable may be uninitialized in which case the object is
174 // not traced.
175 if (*reinterpret_cast<const uintptr_t*>(object) == 0) continue;
176 }
177 TraceTrait<T>::Trace(this, object);
178 }
179 }
180
187 template <typename T, void (T::*method)(const LivenessBroker&)>
188 void RegisterWeakCallbackMethod(const T* object) {
189 RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>, object);
190 }
191
198 template <typename K, typename V>
199 void Trace(const EphemeronPair<K, V>& ephemeron_pair) {
200 TraceEphemeron(ephemeron_pair.key, &ephemeron_pair.value);
201 RegisterWeakCallbackMethod<EphemeronPair<K, V>,
203 &ephemeron_pair);
204 }
205
213 template <typename KeyType, typename ValueType>
214 void TraceEphemeron(const WeakMember<KeyType>& weak_member_key,
215 const Member<ValueType>* member_value) {
216 const KeyType* key = weak_member_key.GetRawAtomic();
217 if (!key) return;
218
219 // `value` must always be non-null.
220 CPPGC_DCHECK(member_value);
221 const ValueType* value = member_value->GetRawAtomic();
222 if (!value) return;
223
224 // KeyType and ValueType may refer to GarbageCollectedMixin.
225 TraceDescriptor value_desc =
228 const void* key_base_object_payload =
229 TraceTrait<KeyType>::GetTraceDescriptor(key).base_object_payload;
230 CPPGC_DCHECK(key_base_object_payload);
231
232 VisitEphemeron(key_base_object_payload, value, value_desc);
233 }
234
246 template <typename KeyType, typename ValueType>
247 void TraceEphemeron(const WeakMember<KeyType>& weak_member_key,
248 const ValueType* value) {
249 static_assert(!IsGarbageCollectedOrMixinTypeV<ValueType>,
250 "garbage-collected types must use WeakMember and Member");
251 const KeyType* key = weak_member_key.GetRawAtomic();
252 if (!key) return;
253
254 // `value` must always be non-null.
255 CPPGC_DCHECK(value);
256 TraceDescriptor value_desc =
258 // `value_desc.base_object_payload` must be null as this override is only
259 // taken for non-garbage-collected values.
261
262 // KeyType might be a GarbageCollectedMixin.
263 const void* key_base_object_payload =
264 TraceTrait<KeyType>::GetTraceDescriptor(key).base_object_payload;
265 CPPGC_DCHECK(key_base_object_payload);
266
267 VisitEphemeron(key_base_object_payload, value, value_desc);
268 }
269
275 template <typename T>
276 void TraceStrongly(const WeakMember<T>& weak_member) {
277 const T* value = weak_member.GetRawAtomic();
279 TraceImpl(value);
280 }
281
287 template <typename T>
288 void TraceStrongContainer(const T* object) {
289 TraceImpl(object);
290 }
291
300 template <typename T>
301 void TraceWeakContainer(const T* object, WeakCallback callback,
302 const void* callback_data) {
303 if (!object) return;
304 VisitWeakContainer(object, TraceTrait<T>::GetTraceDescriptor(object),
306 callback_data);
307 }
308
316 template <typename T>
317 void RegisterMovableReference(const T** slot) {
319 "Only references to objects allocated on compactable spaces "
320 "should be registered as movable slots.");
321 static_assert(!IsGarbageCollectedMixinTypeV<T>,
322 "Mixin types do not support compaction.");
323 HandleMovableReference(reinterpret_cast<const void**>(slot));
324 }
325
332 virtual void RegisterWeakCallback(WeakCallback callback, const void* data) {}
333
348 const void* parameter, TraceCallback callback, size_t deferred_size) {
349 // By default tracing is not deferred.
350 return false;
351 }
352
353 protected:
354 virtual void Visit(const void* self, TraceDescriptor) {}
355 virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback,
356 const void* weak_member) {}
357 virtual void VisitEphemeron(const void* key, const void* value,
358 TraceDescriptor value_desc) {}
359 virtual void VisitWeakContainer(const void* self, TraceDescriptor strong_desc,
360 TraceDescriptor weak_desc,
361 WeakCallback callback, const void* data) {}
362 virtual void HandleMovableReference(const void**) {}
363
365 const void* start, size_t len,
366 TraceDescriptorCallback get_trace_descriptor) {
367 // Default implementation merely delegates to Visit().
368 const char* it = static_cast<const char*>(start);
369 const char* end = it + len * internal::kSizeOfUncompressedMember;
370 for (; it < end; it += internal::kSizeOfUncompressedMember) {
371 const auto* current = reinterpret_cast<const internal::RawPointer*>(it);
372 const void* object = current->LoadAtomic();
373 if (!object) continue;
374
375 Visit(object, get_trace_descriptor(object));
376 }
377 }
378
379#if defined(CPPGC_POINTER_COMPRESSION)
380 virtual void VisitMultipleCompressedMember(
381 const void* start, size_t len,
382 TraceDescriptorCallback get_trace_descriptor) {
383 // Default implementation merely delegates to Visit().
384 const char* it = static_cast<const char*>(start);
385 const char* end = it + len * internal::kSizeofCompressedMember;
386 for (; it < end; it += internal::kSizeofCompressedMember) {
387 const auto* current =
388 reinterpret_cast<const internal::CompressedPointer*>(it);
389 const void* object = current->LoadAtomic();
390 if (!object) continue;
391
392 Visit(object, get_trace_descriptor(object));
393 }
394 }
395#endif // defined(CPPGC_POINTER_COMPRESSION)
396
397 private:
398 template <typename T, void (T::*method)(const LivenessBroker&)>
399 static void WeakCallbackMethodDelegate(const LivenessBroker& info,
400 const void* self) {
401 // Callback is registered through a potential const Trace method but needs
402 // to be able to modify fields. See HandleWeak.
403 (const_cast<T*>(static_cast<const T*>(self))->*method)(info);
404 }
405
406 template <typename PointerType>
407 static void HandleWeak(const LivenessBroker& info, const void* object) {
408 const PointerType* weak = static_cast<const PointerType*>(object);
409 if (!info.IsHeapObjectAlive(weak->GetFromGC())) {
410 weak->ClearFromGC();
411 }
412 }
413
414 template <typename T>
415 void TraceImpl(const T* t) {
416 static_assert(sizeof(T), "Pointee type must be fully defined.");
417 static_assert(internal::IsGarbageCollectedOrMixinType<T>::value,
418 "T must be GarbageCollected or GarbageCollectedMixin type");
419 if (!t) {
420 return;
421 }
422 Visit(t, TraceTrait<T>::GetTraceDescriptor(t));
423 }
424
425#if V8_ENABLE_CHECKS
426 void CheckObjectNotInConstruction(const void* address);
427#endif // V8_ENABLE_CHECKS
428
429 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
430 typename CheckingPolicy>
432 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
433 typename CheckingPolicy>
435 friend class internal::ConservativeTracingVisitor;
436 friend class internal::VisitorBase;
437};
438
439namespace internal {
440
442 public:
444
445 virtual ~RootVisitor() = default;
446
447 template <typename AnyStrongPersistentType,
448 std::enable_if_t<
449 AnyStrongPersistentType::IsStrongPersistent::value>* = nullptr>
450 void Trace(const AnyStrongPersistentType& p) {
451 using PointeeType = typename AnyStrongPersistentType::PointeeType;
452 const void* object = Extract(p);
453 if (!object) {
454 return;
455 }
456 VisitRoot(object, TraceTrait<PointeeType>::GetTraceDescriptor(object),
457 p.Location());
458 }
459
460 template <typename AnyWeakPersistentType,
461 std::enable_if_t<
462 !AnyWeakPersistentType::IsStrongPersistent::value>* = nullptr>
463 void Trace(const AnyWeakPersistentType& p) {
464 using PointeeType = typename AnyWeakPersistentType::PointeeType;
466 "Weak references to compactable objects are not allowed");
467 const void* object = Extract(p);
468 if (!object) {
469 return;
470 }
471 VisitWeakRoot(object, TraceTrait<PointeeType>::GetTraceDescriptor(object),
472 &HandleWeak<AnyWeakPersistentType>, &p, p.Location());
473 }
474
475 protected:
476 virtual void VisitRoot(const void*, TraceDescriptor, const SourceLocation&) {}
477 virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback,
478 const void* weak_root, const SourceLocation&) {}
479
480 private:
481 template <typename AnyPersistentType>
482 static const void* Extract(AnyPersistentType& p) {
483 using PointeeType = typename AnyPersistentType::PointeeType;
484 static_assert(sizeof(PointeeType),
485 "Persistent's pointee type must be fully defined");
487 "Persistent's pointee type must be GarbageCollected or "
488 "GarbageCollectedMixin");
489 return p.GetFromGC();
490 }
491
492 template <typename PointerType>
493 static void HandleWeak(const LivenessBroker& info, const void* object) {
494 const PointerType* weak = static_cast<const PointerType*>(object);
495 if (!info.IsHeapObjectAlive(weak->GetFromGC())) {
496 weak->ClearFromGC();
497 }
498 }
499};
500
501} // namespace internal
502} // namespace cppgc
503
504#endif // INCLUDE_CPPGC_VISITOR_H_
bool IsHeapObjectAlive(const T *object) const
virtual V8_WARN_UNUSED_RESULT bool DeferTraceToMutatorThreadIfConcurrent(const void *parameter, TraceCallback callback, size_t deferred_size)
Definition visitor.h:347
void TraceMultiple(const Member< T > *start, size_t len)
Definition visitor.h:131
void Trace(const WeakMember< T > &weak_member)
Definition visitor.h:86
void Trace(const EphemeronPair< K, V > &ephemeron_pair)
Definition visitor.h:199
void TraceStrongContainer(const T *object)
Definition visitor.h:288
void RegisterMovableReference(const T **slot)
Definition visitor.h:317
void Trace(const Member< T > &member)
Definition visitor.h:74
virtual void VisitEphemeron(const void *key, const void *value, TraceDescriptor value_desc)
Definition visitor.h:357
virtual void VisitMultipleUncompressedMember(const void *start, size_t len, TraceDescriptorCallback get_trace_descriptor)
Definition visitor.h:364
virtual ~Visitor()=default
void TraceEphemeron(const WeakMember< KeyType > &weak_member_key, const ValueType *value)
Definition visitor.h:247
void Trace(const T &object)
Definition visitor.h:150
void TraceMultiple(const T *start, size_t len)
Definition visitor.h:162
void RegisterWeakCallbackMethod(const T *object)
Definition visitor.h:188
virtual void VisitWeak(const void *self, TraceDescriptor, WeakCallback, const void *weak_member)
Definition visitor.h:355
void TraceWeakContainer(const T *object, WeakCallback callback, const void *callback_data)
Definition visitor.h:301
virtual void VisitWeakContainer(const void *self, TraceDescriptor strong_desc, TraceDescriptor weak_desc, WeakCallback callback, const void *data)
Definition visitor.h:359
virtual void HandleMovableReference(const void **)
Definition visitor.h:362
void TraceEphemeron(const WeakMember< KeyType > &weak_member_key, const Member< ValueType > *member_value)
Definition visitor.h:214
void TraceStrongly(const WeakMember< T > &weak_member)
Definition visitor.h:276
virtual void RegisterWeakCallback(WeakCallback callback, const void *data)
Definition visitor.h:332
void TraceMultiple(const subtle::UncompressedMember< T > *start, size_t len)
Definition visitor.h:120
virtual void Visit(const void *self, TraceDescriptor)
Definition visitor.h:354
V8_INLINE const void * LoadAtomic() const
virtual ~RootVisitor()=default
RootVisitor(Visitor::Key)
Definition visitor.h:443
void Trace(const AnyStrongPersistentType &p)
Definition visitor.h:450
void Trace(const AnyWeakPersistentType &p)
Definition visitor.h:463
virtual void VisitRoot(const void *, TraceDescriptor, const SourceLocation &)
Definition visitor.h:476
virtual void VisitWeakRoot(const void *self, TraceDescriptor, WeakCallback, const void *weak_root, const SourceLocation &)
Definition visitor.h:477
#define CPPGC_DCHECK(condition)
Definition logging.h:36
TraceDescriptor(*)(const void *address) TraceDescriptorCallback
Definition trace-trait.h:62
void(*)(Visitor *visitor, const void *object) TraceCallback
Definition trace-trait.h:38
void(*)(const LivenessBroker &, const void *) WeakCallback
Definition visitor.h:37
constexpr internal::SentinelPointer kSentinelPointer
WeakMember< K > key
const void * base_object_payload
Definition trace-trait.h:49
#define V8_EXPORT
Definition v8config.h:753
#define V8_WARN_UNUSED_RESULT
Definition v8config.h:628