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"
16#include "cppgc/macros.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
43template <typename K, typename V>
46
47 EphemeronPair(K* k, V* v) : key(k), value(v) {}
50
52 if (!broker.IsHeapObjectAlive(key)) value = nullptr;
53 }
54
55 void Trace(Visitor* visitor) const;
56};
57
76 public:
77 class Key {
78 private:
79 Key() = default;
80 friend class internal::VisitorFactory;
81 };
82
83 explicit Visitor(Key) {}
84
85 virtual ~Visitor() = default;
86
92 template <typename T>
93 void Trace(const Member<T>& member) {
94 const T* value = member.GetAtomic();
96 TraceImpl(value);
97 }
98
104 template <typename T>
105 void Trace(const WeakMember<T>& weak_member) {
106 static_assert(sizeof(T), "Pointee type must be fully defined.");
108 "T must be GarbageCollected or GarbageCollectedMixin type");
110 "Weak references to compactable objects are not allowed");
111
112 const T* value = weak_member.GetAtomic();
113
114 // Bailout assumes that WeakMember emits write barrier.
115 if (!value) {
116 return;
117 }
118
120 VisitWeak(value, TraceTrait<T>::GetTraceDescriptor(value),
121 &HandleWeak<WeakMember<T>>, &weak_member);
122 }
123
124#if defined(CPPGC_POINTER_COMPRESSION)
130 template <typename T>
131 void Trace(const subtle::UncompressedMember<T>& member) {
132 const T* value = member.GetAtomic();
133 CPPGC_DCHECK(value != kSentinelPointer);
134 TraceImpl(value);
135 }
136#endif // defined(CPPGC_POINTER_COMPRESSION)
137
138 template <typename T>
139 void TraceMultiple(const subtle::UncompressedMember<T>* start, size_t len) {
140 static_assert(sizeof(T), "Pointee type must be fully defined.");
142 "T must be GarbageCollected or GarbageCollectedMixin type");
143 VisitMultipleUncompressedMember(start, len,
145 }
146
147 template <typename T,
148 std::enable_if_t<!std::is_same_v<
150 void TraceMultiple(const Member<T>* start, size_t len) {
151 static_assert(sizeof(T), "Pointee type must be fully defined.");
153 "T must be GarbageCollected or GarbageCollectedMixin type");
154#if defined(CPPGC_POINTER_COMPRESSION)
155 static_assert(std::is_same_v<Member<T>, subtle::CompressedMember<T>>,
156 "Member and CompressedMember must be the same.");
157 VisitMultipleCompressedMember(start, len,
159#endif // defined(CPPGC_POINTER_COMPRESSION)
160 }
161
168 template <typename T>
169 void Trace(const T& object) {
170 static_assert(!IsGarbageCollectedOrMixinTypeV<T>);
171#if V8_ENABLE_CHECKS
172 // This object is embedded in potentially multiple nested objects. The
173 // outermost object must not be in construction as such objects are (a) not
174 // processed immediately, and (b) only processed conservatively if not
175 // otherwise possible.
176 CheckObjectNotInConstruction(&object);
177#endif // V8_ENABLE_CHECKS
178 TraceTrait<T>::Trace(this, &object);
179 }
180
181 template <typename T>
182 void TraceMultiple(const T* start, size_t len) {
183#if V8_ENABLE_CHECKS
184 // This object is embedded in potentially multiple nested objects. The
185 // outermost object must not be in construction as such objects are (a) not
186 // processed immediately, and (b) only processed conservatively if not
187 // otherwise possible.
188 CheckObjectNotInConstruction(start);
189#endif // V8_ENABLE_CHECKS
190 for (size_t i = 0; i < len; ++i) {
191 const T* object = &start[i];
192 if constexpr (std::is_polymorphic_v<T>) {
193 // The object's vtable may be uninitialized in which case the object is
194 // not traced.
195 if (*reinterpret_cast<const uintptr_t*>(object) == 0) continue;
196 }
197 TraceTrait<T>::Trace(this, object);
198 }
199 }
200
207 template <typename T, void (T::*method)(const LivenessBroker&)>
208 void RegisterWeakCallbackMethod(const T* object) {
209 RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>, object);
210 }
211
218 template <typename K, typename V>
219 void Trace(const EphemeronPair<K, V>& ephemeron_pair) {
220 TraceEphemeron(ephemeron_pair.key, &ephemeron_pair.value);
221 RegisterWeakCallbackMethod<EphemeronPair<K, V>,
223 &ephemeron_pair);
224 }
225
233 template <typename KeyType, typename ValueType>
234 void TraceEphemeron(const WeakMember<KeyType>& weak_member_key,
235 const Member<ValueType>* member_value) {
236 const KeyType* key = weak_member_key.GetAtomic();
237 if (!key) return;
238
239 // `value` must always be non-null.
240 CPPGC_DCHECK(member_value);
241 const ValueType* value = member_value->GetAtomic();
242 if (!value) return;
243
244 // KeyType and ValueType may refer to GarbageCollectedMixin.
245 TraceDescriptor value_desc =
248 const void* key_base_object_payload =
249 TraceTrait<KeyType>::GetTraceDescriptor(key).base_object_payload;
250 CPPGC_DCHECK(key_base_object_payload);
251
252 VisitEphemeron(key_base_object_payload, value, value_desc);
253 }
254
266 template <typename KeyType, typename ValueType>
267 void TraceEphemeron(const WeakMember<KeyType>& weak_member_key,
268 const ValueType* value) {
269 static_assert(!IsGarbageCollectedOrMixinTypeV<ValueType>,
270 "garbage-collected types must use WeakMember and Member");
271 const KeyType* key = weak_member_key.GetAtomic();
272 if (!key) return;
273
274 // `value` must always be non-null.
275 CPPGC_DCHECK(value);
276 TraceDescriptor value_desc =
278 // `value_desc.base_object_payload` must be null as this override is only
279 // taken for non-garbage-collected values.
281
282 // KeyType might be a GarbageCollectedMixin.
283 const void* key_base_object_payload =
284 TraceTrait<KeyType>::GetTraceDescriptor(key).base_object_payload;
285 CPPGC_DCHECK(key_base_object_payload);
286
287 VisitEphemeron(key_base_object_payload, value, value_desc);
288 }
289
295 template <typename T>
296 void TraceStrongly(const WeakMember<T>& weak_member) {
297 const T* value = weak_member.GetAtomic();
299 TraceImpl(value);
300 }
301
307 template <typename T>
308 void TraceStrongContainer(const T* object) {
309 TraceImpl(object);
310 }
311
320 template <typename T>
321 void TraceWeakContainer(const T* object, WeakCallback callback,
322 const void* callback_data) {
323 if (!object) return;
324 VisitWeakContainer(object, TraceTrait<T>::GetTraceDescriptor(object),
326 callback_data);
327 }
328
336 template <typename T>
337 void RegisterMovableReference(const T** slot) {
339 "Only references to objects allocated on compactable spaces "
340 "should be registered as movable slots.");
341 static_assert(!IsGarbageCollectedMixinTypeV<T>,
342 "Mixin types do not support compaction.");
343 HandleMovableReference(reinterpret_cast<const void**>(slot));
344 }
345
352 virtual void RegisterWeakCallback(WeakCallback callback, const void* data) {}
353
368 const void* parameter, TraceCallback callback, size_t deferred_size) {
369 // By default tracing is not deferred.
370 return false;
371 }
372
376 virtual bool IsConcurrent() const { return false; }
377
378 protected:
379 virtual void Visit(const void* self, TraceDescriptor) {}
380 virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback,
381 const void* weak_member) {}
382 virtual void VisitEphemeron(const void* key, const void* value,
383 TraceDescriptor value_desc) {}
384 virtual void VisitWeakContainer(const void* self, TraceDescriptor strong_desc,
385 TraceDescriptor weak_desc,
386 WeakCallback callback, const void* data) {}
387 virtual void HandleMovableReference(const void**) {}
388
390 const void* start, size_t len,
391 TraceDescriptorCallback get_trace_descriptor) {
392 // Default implementation merely delegates to Visit().
393 const char* it = static_cast<const char*>(start);
394 const char* end = it + len * internal::kSizeOfUncompressedMember;
395 for (; it < end; it += internal::kSizeOfUncompressedMember) {
396 const auto* current = reinterpret_cast<const internal::RawPointer*>(it);
397 const void* object = current->LoadAtomic();
398 if (!object) continue;
399
400 Visit(object, get_trace_descriptor(object));
401 }
402 }
403
404#if defined(CPPGC_POINTER_COMPRESSION)
405 virtual void VisitMultipleCompressedMember(
406 const void* start, size_t len,
407 TraceDescriptorCallback get_trace_descriptor) {
408 // Default implementation merely delegates to Visit().
409 const char* it = static_cast<const char*>(start);
410 const char* end = it + len * internal::kSizeofCompressedMember;
411 for (; it < end; it += internal::kSizeofCompressedMember) {
412 const auto* current =
413 reinterpret_cast<const internal::CompressedPointer*>(it);
414 const void* object = current->LoadAtomic();
415 if (!object) continue;
416
417 Visit(object, get_trace_descriptor(object));
418 }
419 }
420#endif // defined(CPPGC_POINTER_COMPRESSION)
421
422 private:
423 template <typename T, void (T::*method)(const LivenessBroker&)>
424 static void WeakCallbackMethodDelegate(const LivenessBroker& info,
425 const void* self) {
426 // Callback is registered through a potential const Trace method but needs
427 // to be able to modify fields. See HandleWeak.
428 (const_cast<T*>(static_cast<const T*>(self))->*method)(info);
429 }
430
431 template <typename PointerType>
432 static void HandleWeak(const LivenessBroker& info, const void* object) {
433 const PointerType* weak = static_cast<const PointerType*>(object);
434 if (!info.IsHeapObjectAlive(weak->GetFromGC())) {
435 weak->ClearFromGC();
436 }
437 }
438
439 template <typename T>
440 void TraceImpl(const T* t) {
441 static_assert(sizeof(T), "Pointee type must be fully defined.");
442 static_assert(internal::IsGarbageCollectedOrMixinType<T>::value,
443 "T must be GarbageCollected or GarbageCollectedMixin type");
444 if (!t) {
445 return;
446 }
447 Visit(t, TraceTrait<T>::GetTraceDescriptor(t));
448 }
449
450#if V8_ENABLE_CHECKS
451 void CheckObjectNotInConstruction(const void* address);
452#endif // V8_ENABLE_CHECKS
453
454 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
455 typename CheckingPolicy>
457 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
458 typename CheckingPolicy>
460 friend class internal::ConservativeTracingVisitor;
461 friend class internal::VisitorBase;
462};
463
464template <typename K, typename V>
466 visitor->TraceEphemeron(key, value);
467}
468
469namespace internal {
470
472 public:
474
475 virtual ~RootVisitor() = default;
476
477 template <typename AnyStrongPersistentType,
478 std::enable_if_t<
479 AnyStrongPersistentType::IsStrongPersistent::value>* = nullptr>
480 void Trace(const AnyStrongPersistentType& p) {
481 using PointeeType = typename AnyStrongPersistentType::PointeeType;
482 const void* object = Extract(p);
483 if (!object) {
484 return;
485 }
486 VisitRoot(object, TraceTrait<PointeeType>::GetTraceDescriptor(object),
487 p.Location());
488 }
489
490 template <typename AnyWeakPersistentType,
491 std::enable_if_t<
492 !AnyWeakPersistentType::IsStrongPersistent::value>* = nullptr>
493 void Trace(const AnyWeakPersistentType& p) {
494 using PointeeType = typename AnyWeakPersistentType::PointeeType;
496 "Weak references to compactable objects are not allowed");
497 const void* object = Extract(p);
498 if (!object) {
499 return;
500 }
501 VisitWeakRoot(object, TraceTrait<PointeeType>::GetTraceDescriptor(object),
502 &HandleWeak<AnyWeakPersistentType>, &p, p.Location());
503 }
504
505 protected:
506 virtual void VisitRoot(const void*, TraceDescriptor, SourceLocation) {}
507 virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback,
508 const void* weak_root, SourceLocation) {}
509
510 private:
511 template <typename AnyPersistentType>
512 static const void* Extract(AnyPersistentType& p) {
513 using PointeeType = typename AnyPersistentType::PointeeType;
514 static_assert(sizeof(PointeeType),
515 "Persistent's pointee type must be fully defined");
517 "Persistent's pointee type must be GarbageCollected or "
518 "GarbageCollectedMixin");
519 return p.GetFromGC();
520 }
521
522 template <typename PointerType>
523 static void HandleWeak(const LivenessBroker& info, const void* object) {
524 const PointerType* weak = static_cast<const PointerType*>(object);
525 if (!info.IsHeapObjectAlive(weak->GetFromGC())) {
526 weak->ClearFromGC();
527 }
528 }
529};
530
531} // namespace internal
532} // namespace cppgc
533
534#endif // INCLUDE_CPPGC_VISITOR_H_
Definition: liveness-broker.h:44
bool IsHeapObjectAlive(const T *object) const
Definition: liveness-broker.h:47
Definition: visitor.h:77
Definition: visitor.h:75
void Trace(const Member< T > &member)
Definition: visitor.h:93
void TraceWeakContainer(const T *object, WeakCallback callback, const void *callback_data)
Definition: visitor.h:321
void TraceEphemeron(const WeakMember< KeyType > &weak_member_key, const Member< ValueType > *member_value)
Definition: visitor.h:234
void TraceEphemeron(const WeakMember< KeyType > &weak_member_key, const ValueType *value)
Definition: visitor.h:267
void TraceMultiple(const Member< T > *start, size_t len)
Definition: visitor.h:150
virtual void Visit(const void *self, TraceDescriptor)
Definition: visitor.h:379
virtual void VisitEphemeron(const void *key, const void *value, TraceDescriptor value_desc)
Definition: visitor.h:382
void Trace(const T &object)
Definition: visitor.h:169
void TraceStrongly(const WeakMember< T > &weak_member)
Definition: visitor.h:296
virtual void RegisterWeakCallback(WeakCallback callback, const void *data)
Definition: visitor.h:352
virtual void VisitWeak(const void *self, TraceDescriptor, WeakCallback, const void *weak_member)
Definition: visitor.h:380
void RegisterMovableReference(const T **slot)
Definition: visitor.h:337
virtual bool DeferTraceToMutatorThreadIfConcurrent(const void *parameter, TraceCallback callback, size_t deferred_size)
Definition: visitor.h:367
virtual void HandleMovableReference(const void **)
Definition: visitor.h:387
virtual void VisitMultipleUncompressedMember(const void *start, size_t len, TraceDescriptorCallback get_trace_descriptor)
Definition: visitor.h:389
virtual void VisitWeakContainer(const void *self, TraceDescriptor strong_desc, TraceDescriptor weak_desc, WeakCallback callback, const void *data)
Definition: visitor.h:384
void TraceMultiple(const T *start, size_t len)
Definition: visitor.h:182
void RegisterWeakCallbackMethod(const T *object)
Definition: visitor.h:208
void TraceStrongContainer(const T *object)
Definition: visitor.h:308
void Trace(const WeakMember< T > &weak_member)
Definition: visitor.h:105
void Trace(const EphemeronPair< K, V > &ephemeron_pair)
Definition: visitor.h:219
Visitor(Key)
Definition: visitor.h:83
virtual ~Visitor()=default
virtual bool IsConcurrent() const
Definition: visitor.h:376
void TraceMultiple(const subtle::UncompressedMember< T > *start, size_t len)
Definition: visitor.h:139
Definition: cross-thread-persistent.h:74
Definition: member.h:79
Definition: persistent.h:54
Definition: member-storage.h:228
const void * LoadAtomic() const
Definition: member-storage.h:243
Definition: visitor.h:471
virtual void VisitWeakRoot(const void *self, TraceDescriptor, WeakCallback, const void *weak_root, SourceLocation)
Definition: visitor.h:507
virtual ~RootVisitor()=default
RootVisitor(Visitor::Key)
Definition: visitor.h:473
void Trace(const AnyWeakPersistentType &p)
Definition: visitor.h:493
void Trace(const AnyStrongPersistentType &p)
Definition: visitor.h:480
virtual void VisitRoot(const void *, TraceDescriptor, SourceLocation)
Definition: visitor.h:506
Definition: v8-source-location.h:22
#define CPPGC_DCHECK(condition)
Definition: logging.h:36
#define CPPGC_DISALLOW_NEW()
Definition: macros.h:14
Definition: allocation.h:38
void(*)(Visitor *visitor, const void *object) TraceCallback
Definition: trace-trait.h:37
TraceDescriptor(*)(const void *address) TraceDescriptorCallback
Definition: trace-trait.h:61
void(*)(const LivenessBroker &, const void *) WeakCallback
Definition: visitor.h:37
constexpr internal::SentinelPointer kSentinelPointer
Definition: sentinel-pointer.h:35
Definition: visitor.h:44
EphemeronPair(K *k, V *v)
Definition: visitor.h:47
WeakMember< K > key
Definition: visitor.h:48
void ClearValueIfKeyIsDead(const LivenessBroker &broker)
Definition: visitor.h:51
Member< V > value
Definition: visitor.h:49
void Trace(Visitor *visitor) const
Definition: visitor.h:465
Definition: trace-trait.h:43
const void * base_object_payload
Definition: trace-trait.h:48
Definition: trace-trait.h:104
#define V(Name)
#define V8_EXPORT
Definition: v8config.h:855
#define V8_WARN_UNUSED_RESULT
Definition: v8config.h:679