11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#ifndef INCLUDE_CPPGC_INTERNAL_GC_INFO_H_
61cb0ef41Sopenharmony_ci#define INCLUDE_CPPGC_INTERNAL_GC_INFO_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include <atomic>
91cb0ef41Sopenharmony_ci#include <cstdint>
101cb0ef41Sopenharmony_ci#include <type_traits>
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ci#include "cppgc/internal/finalizer-trait.h"
131cb0ef41Sopenharmony_ci#include "cppgc/internal/logging.h"
141cb0ef41Sopenharmony_ci#include "cppgc/internal/name-trait.h"
151cb0ef41Sopenharmony_ci#include "cppgc/trace-trait.h"
161cb0ef41Sopenharmony_ci#include "v8config.h"  // NOLINT(build/include_directory)
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_cinamespace cppgc {
191cb0ef41Sopenharmony_cinamespace internal {
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ciusing GCInfoIndex = uint16_t;
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_cistruct V8_EXPORT EnsureGCInfoIndexTrait final {
241cb0ef41Sopenharmony_ci  // Acquires a new GC info object and updates `registered_index` with the index
251cb0ef41Sopenharmony_ci  // that identifies that new info accordingly.
261cb0ef41Sopenharmony_ci  template <typename T>
271cb0ef41Sopenharmony_ci  V8_INLINE static void EnsureIndex(
281cb0ef41Sopenharmony_ci      std::atomic<GCInfoIndex>& registered_index) {
291cb0ef41Sopenharmony_ci    EnsureGCInfoIndexTraitDispatch<T>{}(registered_index);
301cb0ef41Sopenharmony_ci  }
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci private:
331cb0ef41Sopenharmony_ci  template <typename T, bool = std::is_polymorphic<T>::value,
341cb0ef41Sopenharmony_ci            bool = FinalizerTrait<T>::HasFinalizer(),
351cb0ef41Sopenharmony_ci            bool = NameTrait<T>::HasNonHiddenName()>
361cb0ef41Sopenharmony_ci  struct EnsureGCInfoIndexTraitDispatch;
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  static void V8_PRESERVE_MOST
391cb0ef41Sopenharmony_ci  EnsureGCInfoIndexPolymorphic(std::atomic<GCInfoIndex>&, TraceCallback,
401cb0ef41Sopenharmony_ci                               FinalizationCallback, NameCallback);
411cb0ef41Sopenharmony_ci  static void V8_PRESERVE_MOST EnsureGCInfoIndexPolymorphic(
421cb0ef41Sopenharmony_ci      std::atomic<GCInfoIndex>&, TraceCallback, FinalizationCallback);
431cb0ef41Sopenharmony_ci  static void V8_PRESERVE_MOST EnsureGCInfoIndexPolymorphic(
441cb0ef41Sopenharmony_ci      std::atomic<GCInfoIndex>&, TraceCallback, NameCallback);
451cb0ef41Sopenharmony_ci  static void V8_PRESERVE_MOST
461cb0ef41Sopenharmony_ci  EnsureGCInfoIndexPolymorphic(std::atomic<GCInfoIndex>&, TraceCallback);
471cb0ef41Sopenharmony_ci  static void V8_PRESERVE_MOST
481cb0ef41Sopenharmony_ci  EnsureGCInfoIndexNonPolymorphic(std::atomic<GCInfoIndex>&, TraceCallback,
491cb0ef41Sopenharmony_ci                                  FinalizationCallback, NameCallback);
501cb0ef41Sopenharmony_ci  static void V8_PRESERVE_MOST EnsureGCInfoIndexNonPolymorphic(
511cb0ef41Sopenharmony_ci      std::atomic<GCInfoIndex>&, TraceCallback, FinalizationCallback);
521cb0ef41Sopenharmony_ci  static void V8_PRESERVE_MOST EnsureGCInfoIndexNonPolymorphic(
531cb0ef41Sopenharmony_ci      std::atomic<GCInfoIndex>&, TraceCallback, NameCallback);
541cb0ef41Sopenharmony_ci  static void V8_PRESERVE_MOST
551cb0ef41Sopenharmony_ci  EnsureGCInfoIndexNonPolymorphic(std::atomic<GCInfoIndex>&, TraceCallback);
561cb0ef41Sopenharmony_ci};
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci#define DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function) \
591cb0ef41Sopenharmony_ci  template <typename T>                                                        \
601cb0ef41Sopenharmony_ci  struct EnsureGCInfoIndexTrait::EnsureGCInfoIndexTraitDispatch<               \
611cb0ef41Sopenharmony_ci      T, is_polymorphic, has_finalizer, has_non_hidden_name> {                 \
621cb0ef41Sopenharmony_ci    V8_INLINE void operator()(std::atomic<GCInfoIndex>& registered_index) {    \
631cb0ef41Sopenharmony_ci      function;                                                                \
641cb0ef41Sopenharmony_ci    }                                                                          \
651cb0ef41Sopenharmony_ci  };
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci// --------------------------------------------------------------------- //
681cb0ef41Sopenharmony_ci// DISPATCH(is_polymorphic, has_finalizer, has_non_hidden_name, function)
691cb0ef41Sopenharmony_ci// --------------------------------------------------------------------- //
701cb0ef41Sopenharmony_ciDISPATCH(true, true, true,                                               //
711cb0ef41Sopenharmony_ci         EnsureGCInfoIndexPolymorphic(registered_index,                  //
721cb0ef41Sopenharmony_ci                                      TraceTrait<T>::Trace,              //
731cb0ef41Sopenharmony_ci                                      FinalizerTrait<T>::kCallback,      //
741cb0ef41Sopenharmony_ci                                      NameTrait<T>::GetName))            //
751cb0ef41Sopenharmony_ciDISPATCH(true, true, false,                                              //
761cb0ef41Sopenharmony_ci         EnsureGCInfoIndexPolymorphic(registered_index,                  //
771cb0ef41Sopenharmony_ci                                      TraceTrait<T>::Trace,              //
781cb0ef41Sopenharmony_ci                                      FinalizerTrait<T>::kCallback))     //
791cb0ef41Sopenharmony_ciDISPATCH(true, false, true,                                              //
801cb0ef41Sopenharmony_ci         EnsureGCInfoIndexPolymorphic(registered_index,                  //
811cb0ef41Sopenharmony_ci                                      TraceTrait<T>::Trace,              //
821cb0ef41Sopenharmony_ci                                      NameTrait<T>::GetName))            //
831cb0ef41Sopenharmony_ciDISPATCH(true, false, false,                                             //
841cb0ef41Sopenharmony_ci         EnsureGCInfoIndexPolymorphic(registered_index,                  //
851cb0ef41Sopenharmony_ci                                      TraceTrait<T>::Trace))             //
861cb0ef41Sopenharmony_ciDISPATCH(false, true, true,                                              //
871cb0ef41Sopenharmony_ci         EnsureGCInfoIndexNonPolymorphic(registered_index,               //
881cb0ef41Sopenharmony_ci                                         TraceTrait<T>::Trace,           //
891cb0ef41Sopenharmony_ci                                         FinalizerTrait<T>::kCallback,   //
901cb0ef41Sopenharmony_ci                                         NameTrait<T>::GetName))         //
911cb0ef41Sopenharmony_ciDISPATCH(false, true, false,                                             //
921cb0ef41Sopenharmony_ci         EnsureGCInfoIndexNonPolymorphic(registered_index,               //
931cb0ef41Sopenharmony_ci                                         TraceTrait<T>::Trace,           //
941cb0ef41Sopenharmony_ci                                         FinalizerTrait<T>::kCallback))  //
951cb0ef41Sopenharmony_ciDISPATCH(false, false, true,                                             //
961cb0ef41Sopenharmony_ci         EnsureGCInfoIndexNonPolymorphic(registered_index,               //
971cb0ef41Sopenharmony_ci                                         TraceTrait<T>::Trace,           //
981cb0ef41Sopenharmony_ci                                         NameTrait<T>::GetName))         //
991cb0ef41Sopenharmony_ciDISPATCH(false, false, false,                                            //
1001cb0ef41Sopenharmony_ci         EnsureGCInfoIndexNonPolymorphic(registered_index,               //
1011cb0ef41Sopenharmony_ci                                         TraceTrait<T>::Trace))          //
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci#undef DISPATCH
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci// Fold types based on finalizer behavior. Note that finalizer characteristics
1061cb0ef41Sopenharmony_ci// align with trace behavior, i.e., destructors are virtual when trace methods
1071cb0ef41Sopenharmony_ci// are and vice versa.
1081cb0ef41Sopenharmony_citemplate <typename T, typename ParentMostGarbageCollectedType>
1091cb0ef41Sopenharmony_cistruct GCInfoFolding {
1101cb0ef41Sopenharmony_ci  static constexpr bool kHasVirtualDestructorAtBase =
1111cb0ef41Sopenharmony_ci      std::has_virtual_destructor<ParentMostGarbageCollectedType>::value;
1121cb0ef41Sopenharmony_ci  static constexpr bool kBothTypesAreTriviallyDestructible =
1131cb0ef41Sopenharmony_ci      std::is_trivially_destructible<ParentMostGarbageCollectedType>::value &&
1141cb0ef41Sopenharmony_ci      std::is_trivially_destructible<T>::value;
1151cb0ef41Sopenharmony_ci  static constexpr bool kHasCustomFinalizerDispatchAtBase =
1161cb0ef41Sopenharmony_ci      internal::HasFinalizeGarbageCollectedObject<
1171cb0ef41Sopenharmony_ci          ParentMostGarbageCollectedType>::value;
1181cb0ef41Sopenharmony_ci#ifdef CPPGC_SUPPORTS_OBJECT_NAMES
1191cb0ef41Sopenharmony_ci  static constexpr bool kWantsDetailedObjectNames = true;
1201cb0ef41Sopenharmony_ci#else   // !CPPGC_SUPPORTS_OBJECT_NAMES
1211cb0ef41Sopenharmony_ci  static constexpr bool kWantsDetailedObjectNames = false;
1221cb0ef41Sopenharmony_ci#endif  // !CPPGC_SUPPORTS_OBJECT_NAMES
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci  // Folding would regresses name resolution when deriving names from C++
1251cb0ef41Sopenharmony_ci  // class names as it would just folds a name to the base class name.
1261cb0ef41Sopenharmony_ci  using ResultType = std::conditional_t<(kHasVirtualDestructorAtBase ||
1271cb0ef41Sopenharmony_ci                                         kBothTypesAreTriviallyDestructible ||
1281cb0ef41Sopenharmony_ci                                         kHasCustomFinalizerDispatchAtBase) &&
1291cb0ef41Sopenharmony_ci                                            !kWantsDetailedObjectNames,
1301cb0ef41Sopenharmony_ci                                        ParentMostGarbageCollectedType, T>;
1311cb0ef41Sopenharmony_ci};
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci// Trait determines how the garbage collector treats objects wrt. to traversing,
1341cb0ef41Sopenharmony_ci// finalization, and naming.
1351cb0ef41Sopenharmony_citemplate <typename T>
1361cb0ef41Sopenharmony_cistruct GCInfoTrait final {
1371cb0ef41Sopenharmony_ci  V8_INLINE static GCInfoIndex Index() {
1381cb0ef41Sopenharmony_ci    static_assert(sizeof(T), "T must be fully defined");
1391cb0ef41Sopenharmony_ci    static std::atomic<GCInfoIndex>
1401cb0ef41Sopenharmony_ci        registered_index;  // Uses zero initialization.
1411cb0ef41Sopenharmony_ci    GCInfoIndex index = registered_index.load(std::memory_order_acquire);
1421cb0ef41Sopenharmony_ci    if (V8_UNLIKELY(!index)) {
1431cb0ef41Sopenharmony_ci      EnsureGCInfoIndexTrait::EnsureIndex<T>(registered_index);
1441cb0ef41Sopenharmony_ci      // Slow path call uses V8_PRESERVE_MOST which does not support return
1451cb0ef41Sopenharmony_ci      // values (also preserves RAX). Avoid out parameter by just reloading the
1461cb0ef41Sopenharmony_ci      // value here which at this point is guaranteed to be set.
1471cb0ef41Sopenharmony_ci      index = registered_index.load(std::memory_order_acquire);
1481cb0ef41Sopenharmony_ci      CPPGC_DCHECK(index != 0);
1491cb0ef41Sopenharmony_ci    }
1501cb0ef41Sopenharmony_ci    return index;
1511cb0ef41Sopenharmony_ci  }
1521cb0ef41Sopenharmony_ci};
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci}  // namespace internal
1551cb0ef41Sopenharmony_ci}  // namespace cppgc
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci#endif  // INCLUDE_CPPGC_INTERNAL_GC_INFO_H_
158