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/name-trait.h" 14 #include "cppgc/trace-trait.h" 15 #include "v8config.h" // NOLINT(build/include_directory) 16 17 namespace cppgc { 18 namespace internal { 19 20 using GCInfoIndex = uint16_t; 21 22 struct V8_EXPORT EnsureGCInfoIndexTrait final { 23 // Acquires a new GC info object and returns the index. In addition, also 24 // updates `registered_index` atomically. 25 template <typename T> EnsureIndexfinal26 V8_INLINE static GCInfoIndex EnsureIndex( 27 std::atomic<GCInfoIndex>& registered_index) { 28 return EnsureGCInfoIndexTraitDispatch<T>{}(registered_index); 29 } 30 31 private: 32 template <typename T, bool = std::is_polymorphic<T>::value, 33 bool = FinalizerTrait<T>::HasFinalizer(), 34 bool = NameTrait<T>::HasNonHiddenName()> 35 struct EnsureGCInfoIndexTraitDispatch; 36 37 static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic<GCInfoIndex>&, 38 TraceCallback, 39 FinalizationCallback, 40 NameCallback); 41 static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic<GCInfoIndex>&, 42 TraceCallback, 43 FinalizationCallback); 44 static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic<GCInfoIndex>&, 45 TraceCallback, NameCallback); 46 static GCInfoIndex EnsureGCInfoIndexPolymorphic(std::atomic<GCInfoIndex>&, 47 TraceCallback); 48 static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic<GCInfoIndex>&, 49 TraceCallback, 50 FinalizationCallback, 51 52 NameCallback); 53 static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic<GCInfoIndex>&, 54 TraceCallback, 55 FinalizationCallback); 56 static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic<GCInfoIndex>&, 57 TraceCallback, 58 NameCallback); 59 static GCInfoIndex EnsureGCInfoIndexNonPolymorphic(std::atomic<GCInfoIndex>&, 60 TraceCallback); 61 }; 62 63 #define DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function) \ 64 template <typename T> \ 65 struct EnsureGCInfoIndexTrait::EnsureGCInfoIndexTraitDispatch< \ 66 T, is_polymorphic, has_finalizer, has_non_hidden_name> { \ 67 V8_INLINE GCInfoIndex \ 68 operator()(std::atomic<GCInfoIndex>& registered_index) { \ 69 return function; \ 70 } \ 71 }; 72 73 // --------------------------------------------------------------------- // 74 // DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function) 75 // --------------------------------------------------------------------- // 76 DISPATCH(true, true, true, // 77 EnsureGCInfoIndexPolymorphic(registered_index, // 78 TraceTrait<T>::Trace, // 79 FinalizerTrait<T>::kCallback, // 80 NameTrait<T>::GetName)) // 81 DISPATCH(true, true, false, // 82 EnsureGCInfoIndexPolymorphic(registered_index, // 83 TraceTrait<T>::Trace, // 84 FinalizerTrait<T>::kCallback)) // 85 DISPATCH(true, false, true, // 86 EnsureGCInfoIndexPolymorphic(registered_index, // 87 TraceTrait<T>::Trace, // 88 NameTrait<T>::GetName)) // 89 DISPATCH(true, false, false, // 90 EnsureGCInfoIndexPolymorphic(registered_index, // 91 TraceTrait<T>::Trace)) // 92 DISPATCH(false, true, true, // 93 EnsureGCInfoIndexNonPolymorphic(registered_index, // 94 TraceTrait<T>::Trace, // 95 FinalizerTrait<T>::kCallback, // 96 NameTrait<T>::GetName)) // 97 DISPATCH(false, true, false, // 98 EnsureGCInfoIndexNonPolymorphic(registered_index, // 99 TraceTrait<T>::Trace, // 100 FinalizerTrait<T>::kCallback)) // 101 DISPATCH(false, false, true, // 102 EnsureGCInfoIndexNonPolymorphic(registered_index, // 103 TraceTrait<T>::Trace, // 104 NameTrait<T>::GetName)) // 105 DISPATCH(false, false, false, // 106 EnsureGCInfoIndexNonPolymorphic(registered_index, // 107 TraceTrait<T>::Trace)) // 108 109 #undef DISPATCH 110 111 // Fold types based on finalizer behavior. Note that finalizer characteristics 112 // align with trace behavior, i.e., destructors are virtual when trace methods 113 // are and vice versa. 114 template <typename T, typename ParentMostGarbageCollectedType> 115 struct GCInfoFolding { 116 static constexpr bool kHasVirtualDestructorAtBase = 117 std::has_virtual_destructor<ParentMostGarbageCollectedType>::value; 118 static constexpr bool kBothTypesAreTriviallyDestructible = 119 std::is_trivially_destructible<ParentMostGarbageCollectedType>::value && 120 std::is_trivially_destructible<T>::value; 121 static constexpr bool kHasCustomFinalizerDispatchAtBase = 122 internal::HasFinalizeGarbageCollectedObject< 123 ParentMostGarbageCollectedType>::value; 124 #ifdef CPPGC_SUPPORTS_OBJECT_NAMES 125 static constexpr bool kWantsDetailedObjectNames = true; 126 #else // !CPPGC_SUPPORTS_OBJECT_NAMES 127 static constexpr bool kWantsDetailedObjectNames = false; 128 #endif // !CPPGC_SUPPORTS_OBJECT_NAMES 129 130 // Folding would regresses name resolution when deriving names from C++ 131 // class names as it would just folds a name to the base class name. 132 using ResultType = std::conditional_t<(kHasVirtualDestructorAtBase || 133 kBothTypesAreTriviallyDestructible || 134 kHasCustomFinalizerDispatchAtBase) && 135 !kWantsDetailedObjectNames, 136 ParentMostGarbageCollectedType, T>; 137 }; 138 139 // Trait determines how the garbage collector treats objects wrt. to traversing, 140 // finalization, and naming. 141 template <typename T> 142 struct GCInfoTrait final { Indexfinal143 V8_INLINE static GCInfoIndex Index() { 144 static_assert(sizeof(T), "T must be fully defined"); 145 static std::atomic<GCInfoIndex> 146 registered_index; // Uses zero initialization. 147 const GCInfoIndex index = registered_index.load(std::memory_order_acquire); 148 return index ? index 149 : EnsureGCInfoIndexTrait::EnsureIndex<T>(registered_index); 150 } 151 }; 152 153 } // namespace internal 154 } // namespace cppgc 155 156 #endif // INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ 157