v8 12.4.254 (node 22.4.1)
V8 is Google's open source JavaScript engine
Loading...
Searching...
No Matches
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