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)) {
53 key = nullptr;
54 value = nullptr;
55 }
56 }
57
58 void Trace(Visitor* visitor) const;
59};
60
79 public:
80 class Key {
81 private:
82 Key() = default;
83 friend class internal::VisitorFactory;
84 };
85
86 explicit Visitor(Key) {}
87
88 virtual ~Visitor() = default;
89
95 template <typename T>
96 void Trace(const Member<T>& member) {
97 const T* value = member.GetAtomic();
99 TraceImpl(value);
100 }
101
107 template <typename T>
108 void Trace(const WeakMember<T>& weak_member) {
109 static_assert(sizeof(T), "Pointee type must be fully defined.");
111 "T must be GarbageCollected or GarbageCollectedMixin type");
113 "Weak references to compactable objects are not allowed");
114
115 const T* value = weak_member.GetAtomic();
116
117 // Bailout assumes that WeakMember emits write barrier.
118 if (!value) {
119 return;
120 }
121
123 VisitWeak(value, TraceTrait<T>::GetTraceDescriptor(value),
124 &HandleWeak<WeakMember<T>>, &weak_member);
125 }
126
127#if defined(CPPGC_POINTER_COMPRESSION)
133 template <typename T>
134 void Trace(const subtle::UncompressedMember<T>& member) {
135 const T* value = member.GetAtomic();
136 CPPGC_DCHECK(value != kSentinelPointer);
137 TraceImpl(value);
138 }
139#endif // defined(CPPGC_POINTER_COMPRESSION)
140
141 template <typename T>
142 void TraceMultiple(const subtle::UncompressedMember<T>* start, size_t len) {
143 static_assert(sizeof(T), "Pointee type must be fully defined.");
145 "T must be GarbageCollected or GarbageCollectedMixin type");
146 VisitMultipleUncompressedMember(start, len,
148 }
149
150 template <typename T,
151 std::enable_if_t<!std::is_same_v<
153 void TraceMultiple(const Member<T>* start, size_t len) {
154 static_assert(sizeof(T), "Pointee type must be fully defined.");
156 "T must be GarbageCollected or GarbageCollectedMixin type");
157#if defined(CPPGC_POINTER_COMPRESSION)
158 static_assert(std::is_same_v<Member<T>, subtle::CompressedMember<T>>,
159 "Member and CompressedMember must be the same.");
160 VisitMultipleCompressedMember(start, len,
162#endif // defined(CPPGC_POINTER_COMPRESSION)
163 }
164
171 template <typename T>
172 void Trace(const T& object) {
173 static_assert(!IsGarbageCollectedOrMixinTypeV<T>);
174#if V8_ENABLE_CHECKS
175 // This object is embedded in potentially multiple nested objects. The
176 // outermost object must not be in construction as such objects are (a) not
177 // processed immediately, and (b) only processed conservatively if not
178 // otherwise possible.
179 CheckObjectNotInConstruction(&object);
180#endif // V8_ENABLE_CHECKS
181 TraceTrait<T>::Trace(this, &object);
182 }
183
184 template <typename T>
185 void TraceMultiple(const T* start, size_t len) {
186#if V8_ENABLE_CHECKS
187 // This object is embedded in potentially multiple nested objects. The
188 // outermost object must not be in construction as such objects are (a) not
189 // processed immediately, and (b) only processed conservatively if not
190 // otherwise possible.
191 CheckObjectNotInConstruction(start);
192#endif // V8_ENABLE_CHECKS
193 for (size_t i = 0; i < len; ++i) {
194 const T* object = &start[i];
195 if constexpr (std::is_polymorphic_v<T>) {
196 // The object's vtable may be uninitialized in which case the object is
197 // not traced.
198 if (*reinterpret_cast<const uintptr_t*>(object) == 0) continue;
199 }
200 TraceTrait<T>::Trace(this, object);
201 }
202 }
203
210 template <typename T, void (T::*method)(const LivenessBroker&)>
211 void RegisterWeakCallbackMethod(const T* object) {
212 RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>, object);
213 }
214
221 template <typename K, typename V>
222 void Trace(const EphemeronPair<K, V>& ephemeron_pair) {
223 TraceEphemeron(ephemeron_pair.key, &ephemeron_pair.value);
224 RegisterWeakCallbackMethod<
226 &ephemeron_pair);
227 }
228
236 template <typename KeyType, typename ValueType>
237 void TraceEphemeron(const WeakMember<KeyType>& weak_member_key,
238 const Member<ValueType>* member_value) {
239 const KeyType* key = weak_member_key.GetAtomic();
240 if (!key) return;
241
242 // `value` must always be non-null.
243 CPPGC_DCHECK(member_value);
244 const ValueType* value = member_value->GetAtomic();
245 if (!value) return;
246
247 // KeyType and ValueType may refer to GarbageCollectedMixin.
248 TraceDescriptor value_desc =
251 const void* key_base_object_payload =
252 TraceTrait<KeyType>::GetTraceDescriptor(key).base_object_payload;
253 CPPGC_DCHECK(key_base_object_payload);
254
255 VisitEphemeron(key_base_object_payload, value, value_desc);
256 }
257
269 template <typename KeyType, typename ValueType>
270 void TraceEphemeron(const WeakMember<KeyType>& weak_member_key,
271 const ValueType* value) {
272 static_assert(!IsGarbageCollectedOrMixinTypeV<ValueType>,
273 "garbage-collected types must use WeakMember and Member");
274 const KeyType* key = weak_member_key.GetAtomic();
275 if (!key) return;
276
277 // `value` must always be non-null.
278 CPPGC_DCHECK(value);
279 TraceDescriptor value_desc =
281 // `value_desc.base_object_payload` must be null as this override is only
282 // taken for non-garbage-collected values.
284
285 // KeyType might be a GarbageCollectedMixin.
286 const void* key_base_object_payload =
287 TraceTrait<KeyType>::GetTraceDescriptor(key).base_object_payload;
288 CPPGC_DCHECK(key_base_object_payload);
289
290 VisitEphemeron(key_base_object_payload, value, value_desc);
291 }
292
298 template <typename T>
299 void TraceStrongly(const WeakMember<T>& weak_member) {
300 const T* value = weak_member.GetAtomic();
302 TraceImpl(value);
303 }
304
310 template <typename T>
311 void TraceStrongContainer(const T* object) {
312 TraceImpl(object);
313 }
314
323 template <typename T>
324 void TraceWeakContainer(const T* object, WeakCallback callback,
325 const void* callback_data) {
326 if (!object) return;
327 VisitWeakContainer(object, TraceTrait<T>::GetTraceDescriptor(object),
329 callback_data);
330 }
331
339 template <typename T>
340 void RegisterMovableReference(const T** slot) {
342 "Only references to objects allocated on compactable spaces "
343 "should be registered as movable slots.");
344 static_assert(!IsGarbageCollectedMixinTypeV<T>,
345 "Mixin types do not support compaction.");
346 HandleMovableReference(reinterpret_cast<const void**>(slot));
347 }
348
355 virtual void RegisterWeakCallback(WeakCallback callback, const void* data) {}
356
371 const void* parameter, TraceCallback callback, size_t deferred_size) {
372 // By default tracing is not deferred.
373 return false;
374 }
375
379 virtual bool IsConcurrent() const { return false; }
380
381 protected:
382 virtual void Visit(const void* self, TraceDescriptor) {}
383 virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback,
384 const void* weak_member) {}
385 virtual void VisitEphemeron(const void* key, const void* value,
386 TraceDescriptor value_desc) {}
387 virtual void VisitWeakContainer(const void* self, TraceDescriptor strong_desc,
388 TraceDescriptor weak_desc,
389 WeakCallback callback, const void* data) {}
390 virtual void HandleMovableReference(const void**) {}
391
393 const void* start, size_t len,
394 TraceDescriptorCallback get_trace_descriptor) {
395 // Default implementation merely delegates to Visit().
396 const char* it = static_cast<const char*>(start);
397 const char* end = it + len * internal::kSizeOfUncompressedMember;
398 for (; it < end; it += internal::kSizeOfUncompressedMember) {
399 const auto* current = reinterpret_cast<const internal::RawPointer*>(it);
400 const void* object = current->LoadAtomic();
401 if (!object) continue;
402
403 Visit(object, get_trace_descriptor(object));
404 }
405 }
406
407#if defined(CPPGC_POINTER_COMPRESSION)
408 virtual void VisitMultipleCompressedMember(
409 const void* start, size_t len,
410 TraceDescriptorCallback get_trace_descriptor) {
411 // Default implementation merely delegates to Visit().
412 const char* it = static_cast<const char*>(start);
413 const char* end = it + len * internal::kSizeofCompressedMember;
414 for (; it < end; it += internal::kSizeofCompressedMember) {
415 const auto* current =
416 reinterpret_cast<const internal::CompressedPointer*>(it);
417 const void* object = current->LoadAtomic();
418 if (!object) continue;
419
420 Visit(object, get_trace_descriptor(object));
421 }
422 }
423#endif // defined(CPPGC_POINTER_COMPRESSION)
424
425 private:
426 template <typename T, void (T::*method)(const LivenessBroker&)>
427 static void WeakCallbackMethodDelegate(const LivenessBroker& info,
428 const void* self) {
429 // Callback is registered through a potential const Trace method but needs
430 // to be able to modify fields. See HandleWeak.
431 (const_cast<T*>(static_cast<const T*>(self))->*method)(info);
432 }
433
434 template <typename PointerType>
435 static void HandleWeak(const LivenessBroker& info, const void* object) {
436 const PointerType* weak = static_cast<const PointerType*>(object);
437 if (!info.IsHeapObjectAlive(weak->GetFromGC())) {
438 weak->ClearFromGC();
439 }
440 }
441
442 template <typename T>
443 void TraceImpl(const T* t) {
444 static_assert(sizeof(T), "Pointee type must be fully defined.");
445 static_assert(internal::IsGarbageCollectedOrMixinType<T>::value,
446 "T must be GarbageCollected or GarbageCollectedMixin type");
447 if (!t) {
448 return;
449 }
450 Visit(t, TraceTrait<T>::GetTraceDescriptor(t));
451 }
452
453#if V8_ENABLE_CHECKS
454 void CheckObjectNotInConstruction(const void* address);
455#endif // V8_ENABLE_CHECKS
456
457 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
458 typename CheckingPolicy>
460 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
461 typename CheckingPolicy>
463 friend class internal::ConservativeTracingVisitor;
464 friend class internal::VisitorBase;
465};
466
467template <typename K, typename V>
469 visitor->TraceEphemeron(key, value);
470}
471
472namespace internal {
473
475 public:
477
478 virtual ~RootVisitor() = default;
479
480 template <typename AnyStrongPersistentType,
481 std::enable_if_t<
482 AnyStrongPersistentType::IsStrongPersistent::value>* = nullptr>
483 void Trace(const AnyStrongPersistentType& p) {
484 using PointeeType = typename AnyStrongPersistentType::PointeeType;
485 const void* object = Extract(p);
486 if (!object) {
487 return;
488 }
489 VisitRoot(object, TraceTrait<PointeeType>::GetTraceDescriptor(object),
490 p.Location());
491 }
492
493 template <typename AnyWeakPersistentType,
494 std::enable_if_t<
495 !AnyWeakPersistentType::IsStrongPersistent::value>* = nullptr>
496 void Trace(const AnyWeakPersistentType& p) {
497 using PointeeType = typename AnyWeakPersistentType::PointeeType;
499 "Weak references to compactable objects are not allowed");
500 const void* object = Extract(p);
501 if (!object) {
502 return;
503 }
504 VisitWeakRoot(object, TraceTrait<PointeeType>::GetTraceDescriptor(object),
505 &HandleWeak<AnyWeakPersistentType>, &p, p.Location());
506 }
507
508 protected:
509 virtual void VisitRoot(const void*, TraceDescriptor, SourceLocation) {}
510 virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback,
511 const void* weak_root, SourceLocation) {}
512
513 private:
514 template <typename AnyPersistentType>
515 static const void* Extract(AnyPersistentType& p) {
516 using PointeeType = typename AnyPersistentType::PointeeType;
517 static_assert(sizeof(PointeeType),
518 "Persistent's pointee type must be fully defined");
520 "Persistent's pointee type must be GarbageCollected or "
521 "GarbageCollectedMixin");
522 return p.GetFromGC();
523 }
524
525 template <typename PointerType>
526 static void HandleWeak(const LivenessBroker& info, const void* object) {
527 const PointerType* weak = static_cast<const PointerType*>(object);
528 if (!info.IsHeapObjectAlive(weak->GetFromGC())) {
529 weak->ClearFromGC();
530 }
531 }
532};
533
534} // namespace internal
535} // namespace cppgc
536
537#endif // INCLUDE_CPPGC_VISITOR_H_
Definition: liveness-broker.h:44
bool IsHeapObjectAlive(const T *object) const
Definition: liveness-broker.h:47
Definition: visitor.h:80
Definition: visitor.h:78
void Trace(const Member< T > &member)
Definition: visitor.h:96
void TraceWeakContainer(const T *object, WeakCallback callback, const void *callback_data)
Definition: visitor.h:324
void TraceEphemeron(const WeakMember< KeyType > &weak_member_key, const Member< ValueType > *member_value)
Definition: visitor.h:237
void TraceEphemeron(const WeakMember< KeyType > &weak_member_key, const ValueType *value)
Definition: visitor.h:270
void TraceMultiple(const Member< T > *start, size_t len)
Definition: visitor.h:153
virtual void Visit(const void *self, TraceDescriptor)
Definition: visitor.h:382
virtual void VisitEphemeron(const void *key, const void *value, TraceDescriptor value_desc)
Definition: visitor.h:385
void Trace(const T &object)
Definition: visitor.h:172
void TraceStrongly(const WeakMember< T > &weak_member)
Definition: visitor.h:299
virtual void RegisterWeakCallback(WeakCallback callback, const void *data)
Definition: visitor.h:355
virtual void VisitWeak(const void *self, TraceDescriptor, WeakCallback, const void *weak_member)
Definition: visitor.h:383
void RegisterMovableReference(const T **slot)
Definition: visitor.h:340
virtual bool DeferTraceToMutatorThreadIfConcurrent(const void *parameter, TraceCallback callback, size_t deferred_size)
Definition: visitor.h:370
virtual void HandleMovableReference(const void **)
Definition: visitor.h:390
virtual void VisitMultipleUncompressedMember(const void *start, size_t len, TraceDescriptorCallback get_trace_descriptor)
Definition: visitor.h:392
virtual void VisitWeakContainer(const void *self, TraceDescriptor strong_desc, TraceDescriptor weak_desc, WeakCallback callback, const void *data)
Definition: visitor.h:387
void TraceMultiple(const T *start, size_t len)
Definition: visitor.h:185
void RegisterWeakCallbackMethod(const T *object)
Definition: visitor.h:211
void TraceStrongContainer(const T *object)
Definition: visitor.h:311
void Trace(const WeakMember< T > &weak_member)
Definition: visitor.h:108
void Trace(const EphemeronPair< K, V > &ephemeron_pair)
Definition: visitor.h:222
Visitor(Key)
Definition: visitor.h:86
virtual ~Visitor()=default
virtual bool IsConcurrent() const
Definition: visitor.h:379
void TraceMultiple(const subtle::UncompressedMember< T > *start, size_t len)
Definition: visitor.h:142
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:474
virtual void VisitWeakRoot(const void *self, TraceDescriptor, WeakCallback, const void *weak_root, SourceLocation)
Definition: visitor.h:510
virtual ~RootVisitor()=default
RootVisitor(Visitor::Key)
Definition: visitor.h:476
void Trace(const AnyWeakPersistentType &p)
Definition: visitor.h:496
void Trace(const AnyStrongPersistentType &p)
Definition: visitor.h:483
virtual void VisitRoot(const void *, TraceDescriptor, SourceLocation)
Definition: visitor.h:509
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
void ClearKeyAndValueIfKeyIsDead(const LivenessBroker &broker)
Definition: visitor.h:51
EphemeronPair(K *k, V *v)
Definition: visitor.h:47
WeakMember< K > key
Definition: visitor.h:48
Member< V > value
Definition: visitor.h:49
void Trace(Visitor *visitor) const
Definition: visitor.h:468
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:854
#define V8_WARN_UNUSED_RESULT
Definition: v8config.h:678