Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-23 10:08:50

0001 // Copyright 2020 the V8 project authors. All rights reserved.
0002 // Use of this source code is governed by a BSD-style license that can be
0003 // found in the LICENSE file.
0004 
0005 #ifndef INCLUDE_CPPGC_INTERNAL_GC_INFO_H_
0006 #define INCLUDE_CPPGC_INTERNAL_GC_INFO_H_
0007 
0008 #include <atomic>
0009 #include <cstdint>
0010 #include <type_traits>
0011 
0012 #include "cppgc/internal/finalizer-trait.h"
0013 #include "cppgc/internal/logging.h"
0014 #include "cppgc/internal/name-trait.h"
0015 #include "cppgc/trace-trait.h"
0016 #include "v8config.h"  // NOLINT(build/include_directory)
0017 
0018 namespace cppgc {
0019 namespace internal {
0020 
0021 using GCInfoIndex = uint16_t;
0022 
0023 struct V8_EXPORT EnsureGCInfoIndexTrait final {
0024   // Acquires a new GC info object and updates `registered_index` with the index
0025   // that identifies that new info accordingly.
0026   template <typename T>
0027   V8_INLINE static GCInfoIndex EnsureIndex(
0028       std::atomic<GCInfoIndex>& registered_index) {
0029     return EnsureGCInfoIndexTraitDispatch<T>{}(registered_index);
0030   }
0031 
0032  private:
0033   template <typename T, bool = FinalizerTrait<T>::HasFinalizer(),
0034             bool = NameTrait<T>::HasNonHiddenName()>
0035   struct EnsureGCInfoIndexTraitDispatch;
0036 
0037   static GCInfoIndex V8_PRESERVE_MOST
0038   EnsureGCInfoIndex(std::atomic<GCInfoIndex>&, TraceCallback,
0039                     FinalizationCallback, NameCallback);
0040   static GCInfoIndex V8_PRESERVE_MOST EnsureGCInfoIndex(
0041       std::atomic<GCInfoIndex>&, TraceCallback, FinalizationCallback);
0042   static GCInfoIndex V8_PRESERVE_MOST
0043   EnsureGCInfoIndex(std::atomic<GCInfoIndex>&, TraceCallback, NameCallback);
0044   static GCInfoIndex V8_PRESERVE_MOST
0045   EnsureGCInfoIndex(std::atomic<GCInfoIndex>&, TraceCallback);
0046 };
0047 
0048 #define DISPATCH(has_finalizer, has_non_hidden_name, function)   \
0049   template <typename T>                                          \
0050   struct EnsureGCInfoIndexTrait::EnsureGCInfoIndexTraitDispatch< \
0051       T, has_finalizer, has_non_hidden_name> {                   \
0052     V8_INLINE GCInfoIndex                                        \
0053     operator()(std::atomic<GCInfoIndex>& registered_index) {     \
0054       return function;                                           \
0055     }                                                            \
0056   };
0057 
0058 // ------------------------------------------------------- //
0059 // DISPATCH(has_finalizer, has_non_hidden_name, function)  //
0060 // ------------------------------------------------------- //
0061 DISPATCH(true, true,                                       //
0062          EnsureGCInfoIndex(registered_index,               //
0063                            TraceTrait<T>::Trace,           //
0064                            FinalizerTrait<T>::kCallback,   //
0065                            NameTrait<T>::GetName))         //
0066 DISPATCH(true, false,                                      //
0067          EnsureGCInfoIndex(registered_index,               //
0068                            TraceTrait<T>::Trace,           //
0069                            FinalizerTrait<T>::kCallback))  //
0070 DISPATCH(false, true,                                      //
0071          EnsureGCInfoIndex(registered_index,               //
0072                            TraceTrait<T>::Trace,           //
0073                            NameTrait<T>::GetName))         //
0074 DISPATCH(false, false,                                     //
0075          EnsureGCInfoIndex(registered_index,               //
0076                            TraceTrait<T>::Trace))          //
0077 
0078 #undef DISPATCH
0079 
0080 // Trait determines how the garbage collector treats objects wrt. to traversing,
0081 // finalization, and naming.
0082 template <typename T>
0083 struct GCInfoTrait final {
0084   V8_INLINE static GCInfoIndex Index() {
0085     static_assert(sizeof(T), "T must be fully defined");
0086     static std::atomic<GCInfoIndex>
0087         registered_index;  // Uses zero initialization.
0088     GCInfoIndex index = registered_index.load(std::memory_order_acquire);
0089     if (V8_UNLIKELY(!index)) {
0090       index = EnsureGCInfoIndexTrait::EnsureIndex<T>(registered_index);
0091       CPPGC_DCHECK(index != 0);
0092       CPPGC_DCHECK(index == registered_index.load(std::memory_order_acquire));
0093     }
0094     return index;
0095   }
0096 
0097   static constexpr bool CheckCallbacksAreDefined() {
0098     // No USE() macro available.
0099     (void)static_cast<TraceCallback>(TraceTrait<T>::Trace);
0100     (void)static_cast<FinalizationCallback>(FinalizerTrait<T>::kCallback);
0101     (void)static_cast<NameCallback>(NameTrait<T>::GetName);
0102     return true;
0103   }
0104 };
0105 
0106 // Fold types based on finalizer behavior. Note that finalizer characteristics
0107 // align with trace behavior, i.e., destructors are virtual when trace methods
0108 // are and vice versa.
0109 template <typename T, typename ParentMostGarbageCollectedType>
0110 struct GCInfoFolding final {
0111   static constexpr bool kHasVirtualDestructorAtBase =
0112       std::has_virtual_destructor<ParentMostGarbageCollectedType>::value;
0113   static constexpr bool kBothTypesAreTriviallyDestructible =
0114       std::is_trivially_destructible<ParentMostGarbageCollectedType>::value &&
0115       std::is_trivially_destructible<T>::value;
0116   static constexpr bool kHasCustomFinalizerDispatchAtBase =
0117       internal::HasFinalizeGarbageCollectedObject<
0118           ParentMostGarbageCollectedType>::value;
0119 #ifdef CPPGC_SUPPORTS_OBJECT_NAMES
0120   static constexpr bool kWantsDetailedObjectNames = true;
0121 #else   // !CPPGC_SUPPORTS_OBJECT_NAMES
0122   static constexpr bool kWantsDetailedObjectNames = false;
0123 #endif  // !CPPGC_SUPPORTS_OBJECT_NAMES
0124 
0125   // Always true. Forces the compiler to resolve callbacks which ensures that
0126   // both modes don't break without requiring compiling a separate
0127   // configuration. Only a single GCInfo (for `ResultType` below) will actually
0128   // be instantiated but existence (and well-formedness) of all callbacks is
0129   // checked.
0130   static constexpr bool kCheckTypeGuardAlwaysTrue =
0131       GCInfoTrait<T>::CheckCallbacksAreDefined() &&
0132       GCInfoTrait<ParentMostGarbageCollectedType>::CheckCallbacksAreDefined();
0133 
0134   // Folding would regress name resolution when deriving names from C++
0135   // class names as it would just folds a name to the base class name.
0136   using ResultType =
0137       std::conditional_t<kCheckTypeGuardAlwaysTrue &&
0138                              (kHasVirtualDestructorAtBase ||
0139                               kBothTypesAreTriviallyDestructible ||
0140                               kHasCustomFinalizerDispatchAtBase) &&
0141                              !kWantsDetailedObjectNames,
0142                          ParentMostGarbageCollectedType, T>;
0143 };
0144 
0145 }  // namespace internal
0146 }  // namespace cppgc
0147 
0148 #endif  // INCLUDE_CPPGC_INTERNAL_GC_INFO_H_