/src/node/deps/v8/include/cppgc/internal/gc-info.h
Line  | Count  | Source  | 
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_INTERNAL_GC_INFO_H_  | 
6  |  | #define INCLUDE_CPPGC_INTERNAL_GC_INFO_H_  | 
7  |  |  | 
8  |  | #include <atomic>  | 
9  |  | #include <cstdint>  | 
10  |  | #include <type_traits>  | 
11  |  |  | 
12  |  | #include "cppgc/internal/finalizer-trait.h"  | 
13  |  | #include "cppgc/internal/logging.h"  | 
14  |  | #include "cppgc/internal/name-trait.h"  | 
15  |  | #include "cppgc/trace-trait.h"  | 
16  |  | #include "v8config.h"  // NOLINT(build/include_directory)  | 
17  |  |  | 
18  |  | namespace cppgc { | 
19  |  | namespace internal { | 
20  |  |  | 
21  |  | using GCInfoIndex = uint16_t;  | 
22  |  |  | 
23  |  | struct V8_EXPORT EnsureGCInfoIndexTrait final { | 
24  |  |   // Acquires a new GC info object and updates `registered_index` with the index  | 
25  |  |   // that identifies that new info accordingly.  | 
26  |  |   template <typename T>  | 
27  |  |   V8_INLINE static GCInfoIndex EnsureIndex(  | 
28  | 0  |       std::atomic<GCInfoIndex>& registered_index) { | 
29  | 0  |     return EnsureGCInfoIndexTraitDispatch<T>{}(registered_index); | 
30  | 0  |   }  | 
31  |  |  | 
32  |  |  private:  | 
33  |  |   template <typename T, bool = FinalizerTrait<T>::HasFinalizer(),  | 
34  |  |             bool = NameTrait<T>::HasNonHiddenName()>  | 
35  |  |   struct EnsureGCInfoIndexTraitDispatch;  | 
36  |  |  | 
37  |  |   static GCInfoIndex V8_PRESERVE_MOST  | 
38  |  |   EnsureGCInfoIndex(std::atomic<GCInfoIndex>&, TraceCallback,  | 
39  |  |                     FinalizationCallback, NameCallback);  | 
40  |  |   static GCInfoIndex V8_PRESERVE_MOST EnsureGCInfoIndex(  | 
41  |  |       std::atomic<GCInfoIndex>&, TraceCallback, FinalizationCallback);  | 
42  |  |   static GCInfoIndex V8_PRESERVE_MOST  | 
43  |  |   EnsureGCInfoIndex(std::atomic<GCInfoIndex>&, TraceCallback, NameCallback);  | 
44  |  |   static GCInfoIndex V8_PRESERVE_MOST  | 
45  |  |   EnsureGCInfoIndex(std::atomic<GCInfoIndex>&, TraceCallback);  | 
46  |  | };  | 
47  |  |  | 
48  |  | #define DISPATCH(has_finalizer, has_non_hidden_name, function)   \  | 
49  |  |   template <typename T>                                          \  | 
50  |  |   struct EnsureGCInfoIndexTrait::EnsureGCInfoIndexTraitDispatch< \  | 
51  |  |       T, has_finalizer, has_non_hidden_name> {                   \ | 
52  |  |     V8_INLINE GCInfoIndex                                        \  | 
53  | 0  |     operator()(std::atomic<GCInfoIndex>& registered_index) {     \ | 
54  | 0  |       return function;                                           \  | 
55  | 0  |     }                                                            \  | 
56  |  |   };  | 
57  |  |  | 
58  |  | // ------------------------------------------------------- //  | 
59  |  | // DISPATCH(has_finalizer, has_non_hidden_name, function)  //  | 
60  |  | // ------------------------------------------------------- //  | 
61  |  | DISPATCH(true, true,                                       //  | 
62  |  |          EnsureGCInfoIndex(registered_index,               //  | 
63  |  |                            TraceTrait<T>::Trace,           //  | 
64  |  |                            FinalizerTrait<T>::kCallback,   //  | 
65  |  |                            NameTrait<T>::GetName))         //  | 
66  |  | DISPATCH(true, false,                                      //  | 
67  |  |          EnsureGCInfoIndex(registered_index,               //  | 
68  |  |                            TraceTrait<T>::Trace,           //  | 
69  |  |                            FinalizerTrait<T>::kCallback))  //  | 
70  |  | DISPATCH(false, true,                                      //  | 
71  |  |          EnsureGCInfoIndex(registered_index,               //  | 
72  |  |                            TraceTrait<T>::Trace,           //  | 
73  |  |                            NameTrait<T>::GetName))         //  | 
74  |  | DISPATCH(false, false,                                     //  | 
75  |  |          EnsureGCInfoIndex(registered_index,               //  | 
76  |  |                            TraceTrait<T>::Trace))          //  | 
77  |  |  | 
78  |  | #undef DISPATCH  | 
79  |  |  | 
80  |  | // Trait determines how the garbage collector treats objects wrt. to traversing,  | 
81  |  | // finalization, and naming.  | 
82  |  | template <typename T>  | 
83  |  | struct GCInfoTrait final { | 
84  | 0  |   V8_INLINE static GCInfoIndex Index() { | 
85  | 0  |     static_assert(sizeof(T), "T must be fully defined");  | 
86  | 0  |     static std::atomic<GCInfoIndex>  | 
87  | 0  |         registered_index;  // Uses zero initialization.  | 
88  | 0  |     GCInfoIndex index = registered_index.load(std::memory_order_acquire);  | 
89  | 0  |     if (V8_UNLIKELY(!index)) { | 
90  | 0  |       index = EnsureGCInfoIndexTrait::EnsureIndex<T>(registered_index);  | 
91  | 0  |       CPPGC_DCHECK(index != 0);  | 
92  | 0  |       CPPGC_DCHECK(index == registered_index.load(std::memory_order_acquire));  | 
93  | 0  |     }  | 
94  | 0  |     return index;  | 
95  | 0  |   }  | 
96  |  |  | 
97  | 0  |   static constexpr void CheckCallbacksAreDefined() { | 
98  | 0  |     // No USE() macro available.  | 
99  | 0  |     (void)static_cast<TraceCallback>(TraceTrait<T>::Trace);  | 
100  | 0  |     (void)static_cast<FinalizationCallback>(FinalizerTrait<T>::kCallback);  | 
101  | 0  |     (void)static_cast<NameCallback>(NameTrait<T>::GetName);  | 
102  | 0  |   } Unexecuted instantiation: cppgc::internal::GCInfoTrait<node::contextify::ContextifyContext>::CheckCallbacksAreDefined() Unexecuted instantiation: cppgc::internal::GCInfoTrait<v8::Object::Wrappable>::CheckCallbacksAreDefined() Unexecuted instantiation: cppgc::internal::GCInfoTrait<node::contextify::ContextifyScript>::CheckCallbacksAreDefined()  | 
103  |  | };  | 
104  |  |  | 
105  |  | // Fold types based on finalizer behavior. Note that finalizer characteristics  | 
106  |  | // align with trace behavior, i.e., destructors are virtual when trace methods  | 
107  |  | // are and vice versa.  | 
108  |  | template <typename T, typename ParentMostGarbageCollectedType>  | 
109  |  | struct GCInfoFolding final { | 
110  |  |   static constexpr bool kHasVirtualDestructorAtBase =  | 
111  |  |       std::has_virtual_destructor_v<ParentMostGarbageCollectedType>;  | 
112  |  |   static constexpr bool kBothTypesAreTriviallyDestructible =  | 
113  |  |       std::is_trivially_destructible_v<ParentMostGarbageCollectedType> &&  | 
114  |  |       std::is_trivially_destructible_v<T>;  | 
115  |  |   static constexpr bool kHasCustomFinalizerDispatchAtBase =  | 
116  |  |       internal::HasFinalizeGarbageCollectedObject<  | 
117  |  |           ParentMostGarbageCollectedType>::value;  | 
118  |  | #ifdef CPPGC_SUPPORTS_OBJECT_NAMES  | 
119  |  |   static constexpr bool kWantsDetailedObjectNames = true;  | 
120  |  | #else   // !CPPGC_SUPPORTS_OBJECT_NAMES  | 
121  |  |   static constexpr bool kWantsDetailedObjectNames = false;  | 
122  |  | #endif  // !CPPGC_SUPPORTS_OBJECT_NAMES  | 
123  |  |  | 
124  |  |   // Always true. Forces the compiler to resolve callbacks which ensures that  | 
125  |  |   // both modes don't break without requiring compiling a separate  | 
126  |  |   // configuration. Only a single GCInfo (for `ResultType` below) will actually  | 
127  |  |   // be instantiated but existence (and well-formedness) of all callbacks is  | 
128  |  |   // checked.  | 
129  | 0  |   static constexpr bool WantToFold() { | 
130  | 0  |     if constexpr ((kHasVirtualDestructorAtBase ||  | 
131  | 0  |                    kBothTypesAreTriviallyDestructible ||  | 
132  | 0  |                    kHasCustomFinalizerDispatchAtBase) &&  | 
133  | 0  |                   !kWantsDetailedObjectNames) { | 
134  | 0  |       GCInfoTrait<T>::CheckCallbacksAreDefined();  | 
135  | 0  |       GCInfoTrait<ParentMostGarbageCollectedType>::CheckCallbacksAreDefined();  | 
136  | 0  |       return true;  | 
137  | 0  |     }  | 
138  | 0  |     return false;  | 
139  | 0  |   } Unexecuted instantiation: cppgc::internal::GCInfoFolding<node::contextify::ContextifyContext, v8::Object::Wrappable>::WantToFold() Unexecuted instantiation: cppgc::internal::GCInfoFolding<node::contextify::ContextifyScript, v8::Object::Wrappable>::WantToFold()  | 
140  |  |  | 
141  |  |   // Folding would regress name resolution when deriving names from C++  | 
142  |  |   // class names as it would just folds a name to the base class name.  | 
143  |  |   using ResultType =  | 
144  |  |       std::conditional_t<WantToFold(), ParentMostGarbageCollectedType, T>;  | 
145  |  | };  | 
146  |  |  | 
147  |  | }  // namespace internal  | 
148  |  | }  // namespace cppgc  | 
149  |  |  | 
150  |  | #endif  // INCLUDE_CPPGC_INTERNAL_GC_INFO_H_  |