Coverage Report

Created: 2025-10-31 09:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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_