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> EnsureIndexcppgc::internal::final27 V8_INLINE static void EnsureIndex( 28 std::atomic<GCInfoIndex>& registered_index) { 29 EnsureGCInfoIndexTraitDispatch<T>{}(registered_index); 30 } 31 32 private: 33 template <typename T, bool = std::is_polymorphic<T>::value, 34 bool = FinalizerTrait<T>::HasFinalizer(), 35 bool = NameTrait<T>::HasNonHiddenName()> 36 struct EnsureGCInfoIndexTraitDispatch; 37 38 static void V8_PRESERVE_MOST 39 EnsureGCInfoIndexPolymorphic(std::atomic<GCInfoIndex>&, TraceCallback, 40 FinalizationCallback, NameCallback); 41 static void V8_PRESERVE_MOST EnsureGCInfoIndexPolymorphic( 42 std::atomic<GCInfoIndex>&, TraceCallback, FinalizationCallback); 43 static void V8_PRESERVE_MOST EnsureGCInfoIndexPolymorphic( 44 std::atomic<GCInfoIndex>&, TraceCallback, NameCallback); 45 static void V8_PRESERVE_MOST 46 EnsureGCInfoIndexPolymorphic(std::atomic<GCInfoIndex>&, TraceCallback); 47 static void V8_PRESERVE_MOST 48 EnsureGCInfoIndexNonPolymorphic(std::atomic<GCInfoIndex>&, TraceCallback, 49 FinalizationCallback, NameCallback); 50 static void V8_PRESERVE_MOST EnsureGCInfoIndexNonPolymorphic( 51 std::atomic<GCInfoIndex>&, TraceCallback, FinalizationCallback); 52 static void V8_PRESERVE_MOST EnsureGCInfoIndexNonPolymorphic( 53 std::atomic<GCInfoIndex>&, TraceCallback, NameCallback); 54 static void V8_PRESERVE_MOST 55 EnsureGCInfoIndexNonPolymorphic(std::atomic<GCInfoIndex>&, TraceCallback); 56 }; 57 58 #define DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function) \ 59 template <typename T> \ 60 struct EnsureGCInfoIndexTrait::EnsureGCInfoIndexTraitDispatch< \ 61 T, is_polymorphic, has_finalizer, has_non_hidden_name> { \ 62 V8_INLINE void operator()(std::atomic<GCInfoIndex>& registered_index) { \ 63 function; \ 64 } \ 65 }; 66 67 // --------------------------------------------------------------------- // 68 // DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function) 69 // --------------------------------------------------------------------- // 70 DISPATCH(true, true, true, // 71 EnsureGCInfoIndexPolymorphic(registered_index, // 72 TraceTrait<T>::Trace, // 73 FinalizerTrait<T>::kCallback, // 74 NameTrait<T>::GetName)) // 75 DISPATCH(true, true, false, // 76 EnsureGCInfoIndexPolymorphic(registered_index, // 77 TraceTrait<T>::Trace, // 78 FinalizerTrait<T>::kCallback)) // 79 DISPATCH(true, false, true, // 80 EnsureGCInfoIndexPolymorphic(registered_index, // 81 TraceTrait<T>::Trace, // 82 NameTrait<T>::GetName)) // 83 DISPATCH(true, false, false, // 84 EnsureGCInfoIndexPolymorphic(registered_index, // 85 TraceTrait<T>::Trace)) // 86 DISPATCH(false, true, true, // 87 EnsureGCInfoIndexNonPolymorphic(registered_index, // 88 TraceTrait<T>::Trace, // 89 FinalizerTrait<T>::kCallback, // 90 NameTrait<T>::GetName)) // 91 DISPATCH(false, true, false, // 92 EnsureGCInfoIndexNonPolymorphic(registered_index, // 93 TraceTrait<T>::Trace, // 94 FinalizerTrait<T>::kCallback)) // 95 DISPATCH(false, false, true, // 96 EnsureGCInfoIndexNonPolymorphic(registered_index, // 97 TraceTrait<T>::Trace, // 98 NameTrait<T>::GetName)) // 99 DISPATCH(false, false, false, // 100 EnsureGCInfoIndexNonPolymorphic(registered_index, // 101 TraceTrait<T>::Trace)) // 102 103 #undef DISPATCH 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 { 110 static constexpr bool kHasVirtualDestructorAtBase = 111 std::has_virtual_destructor<ParentMostGarbageCollectedType>::value; 112 static constexpr bool kBothTypesAreTriviallyDestructible = 113 std::is_trivially_destructible<ParentMostGarbageCollectedType>::value && 114 std::is_trivially_destructible<T>::value; 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 // Folding would regresses name resolution when deriving names from C++ 125 // class names as it would just folds a name to the base class name. 126 using ResultType = std::conditional_t<(kHasVirtualDestructorAtBase || 127 kBothTypesAreTriviallyDestructible || 128 kHasCustomFinalizerDispatchAtBase) && 129 !kWantsDetailedObjectNames, 130 ParentMostGarbageCollectedType, T>; 131 }; 132 133 // Trait determines how the garbage collector treats objects wrt. to traversing, 134 // finalization, and naming. 135 template <typename T> 136 struct GCInfoTrait final { Indexcppgc::internal::final137 V8_INLINE static GCInfoIndex Index() { 138 static_assert(sizeof(T), "T must be fully defined"); 139 static std::atomic<GCInfoIndex> 140 registered_index; // Uses zero initialization. 141 GCInfoIndex index = registered_index.load(std::memory_order_acquire); 142 if (V8_UNLIKELY(!index)) { 143 EnsureGCInfoIndexTrait::EnsureIndex<T>(registered_index); 144 // Slow path call uses V8_PRESERVE_MOST which does not support return 145 // values (also preserves RAX). Avoid out parameter by just reloading the 146 // value here which at this point is guaranteed to be set. 147 index = registered_index.load(std::memory_order_acquire); 148 CPPGC_DCHECK(index != 0); 149 } 150 return index; 151 } 152 }; 153 154 } // namespace internal 155 } // namespace cppgc 156 157 #endif // INCLUDE_CPPGC_INTERNAL_GC_INFO_H_ 158