v8  9.4.146 (node 16.13.0)
V8 is Google's open source JavaScript engine
v8-cppgc.h
Go to the documentation of this file.
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_V8_CPPGC_H_
6 #define INCLUDE_V8_CPPGC_H_
7 
8 #include <cstdint>
9 #include <memory>
10 #include <vector>
11 
12 #include "cppgc/common.h"
13 #include "cppgc/custom-space.h"
14 #include "cppgc/heap-statistics.h"
15 #include "cppgc/internal/write-barrier.h"
16 #include "cppgc/visitor.h"
17 #include "v8-internal.h" // NOLINT(build/include_directory)
18 #include "v8.h" // NOLINT(build/include_directory)
19 
20 namespace cppgc {
21 class AllocationHandle;
22 class HeapHandle;
23 } // namespace cppgc
24 
25 namespace v8 {
26 
27 namespace internal {
28 class CppHeap;
29 } // namespace internal
30 
32 
33 /**
34  * Describes how V8 wrapper objects maintain references to garbage-collected C++
35  * objects.
36  */
37 struct WrapperDescriptor final {
38  /**
39  * The index used on `v8::Ojbect::SetAlignedPointerFromInternalField()` and
40  * related APIs to add additional data to an object which is used to identify
41  * JS->C++ references.
42  */
43  using InternalFieldIndex = int;
44 
45  /**
46  * Unknown embedder id. The value is reserved for internal usages and must not
47  * be used with `CppHeap`.
48  */
49  static constexpr uint16_t kUnknownEmbedderId = UINT16_MAX;
50 
51  constexpr WrapperDescriptor(InternalFieldIndex wrappable_type_index,
52  InternalFieldIndex wrappable_instance_index,
53  uint16_t embedder_id_for_garbage_collected)
54  : wrappable_type_index(wrappable_type_index),
55  wrappable_instance_index(wrappable_instance_index),
56  embedder_id_for_garbage_collected(embedder_id_for_garbage_collected) {}
57 
58  /**
59  * Index of the wrappable type.
60  */
61  InternalFieldIndex wrappable_type_index;
62 
63  /**
64  * Index of the wrappable instance.
65  */
66  InternalFieldIndex wrappable_instance_index;
67 
68  /**
69  * Embedder id identifying instances of garbage-collected objects. It is
70  * expected that the first field of the wrappable type is a uint16_t holding
71  * the id. Only references to instances of wrappables types with an id of
72  * `embedder_id_for_garbage_collected` will be considered by CppHeap.
73  */
75 };
76 
80 
81  std::vector<std::unique_ptr<cppgc::CustomSpaceBase>> custom_spaces;
82  WrapperDescriptor wrapper_descriptor;
83 };
84 
85 /**
86  * A heap for allocating managed C++ objects.
87  */
89  public:
90  static std::unique_ptr<CppHeap> Create(v8::Platform* platform,
91  const CppHeapCreateParams& params);
92 
93  virtual ~CppHeap() = default;
94 
95  /**
96  * \returns the opaque handle for allocating objects using
97  * `MakeGarbageCollected()`.
98  */
99  cppgc::AllocationHandle& GetAllocationHandle();
100 
101  /**
102  * \returns the opaque heap handle which may be used to refer to this heap in
103  * other APIs. Valid as long as the underlying `CppHeap` is alive.
104  */
105  cppgc::HeapHandle& GetHeapHandle();
106 
107  /**
108  * Terminate clears all roots and performs multiple garbage collections to
109  * reclaim potentially newly created objects in destructors.
110  *
111  * After this call, object allocation is prohibited.
112  */
113  void Terminate();
114 
115  /**
116  * \param detail_level specifies whether should return detailed
117  * statistics or only brief summary statistics.
118  * \returns current CppHeap statistics regarding memory consumption
119  * and utilization.
120  */
121  cppgc::HeapStatistics CollectStatistics(
122  cppgc::HeapStatistics::DetailLevel detail_level);
123 
124  /**
125  * Collects statistics for the given spaces and reports them to the receiver.
126  *
127  * \param custom_spaces a collection of custom space indicies.
128  * \param receiver an object that gets the results.
129  */
131  std::vector<cppgc::CustomSpaceIndex> custom_spaces,
132  std::unique_ptr<CustomSpaceStatisticsReceiver> receiver);
133 
134  /**
135  * Enables a detached mode that allows testing garbage collection using
136  * `cppgc::testing` APIs. Once used, the heap cannot be attached to an
137  * `Isolate` anymore.
138  */
140 
141  /**
142  * Performs a stop-the-world garbage collection for testing purposes.
143  *
144  * \param stack_state The stack state to assume for the garbage collection.
145  */
147 
148  private:
149  CppHeap() = default;
150 
151  friend class internal::CppHeap;
152 };
153 
154 class JSVisitor : public cppgc::Visitor {
155  public:
156  explicit JSVisitor(cppgc::Visitor::Key key) : cppgc::Visitor(key) {}
157 
158  void Trace(const TracedReferenceBase& ref) {
159  if (ref.IsEmptyThreadSafe()) return;
160  Visit(ref);
161  }
162 
163  protected:
164  using cppgc::Visitor::Visit;
165 
166  virtual void Visit(const TracedReferenceBase& ref) {}
167 };
168 
169 /**
170  * **DO NOT USE: Use the appropriate managed types.**
171  *
172  * Consistency helpers that aid in maintaining a consistent internal state of
173  * the garbage collector.
174  */
175 class V8_EXPORT JSHeapConsistency final {
176  public:
177  using WriteBarrierParams = cppgc::internal::WriteBarrier::Params;
178  using WriteBarrierType = cppgc::internal::WriteBarrier::Type;
179 
180  /**
181  * Gets the required write barrier type for a specific write.
182  *
183  * Note: Handling for C++ to JS references.
184  *
185  * \param ref The reference being written to.
186  * \param params Parameters that may be used for actual write barrier calls.
187  * Only filled if return value indicates that a write barrier is needed. The
188  * contents of the `params` are an implementation detail.
189  * \param callback Callback returning the corresponding heap handle. The
190  * callback is only invoked if the heap cannot otherwise be figured out. The
191  * callback must not allocate.
192  * \returns whether a write barrier is needed and which barrier to invoke.
193  */
194  template <typename HeapHandleCallback>
195  static V8_INLINE WriteBarrierType
197  WriteBarrierParams& params, HeapHandleCallback callback) {
198  if (ref.IsEmpty()) return WriteBarrierType::kNone;
199 
200  if (V8_LIKELY(!cppgc::internal::WriteBarrier::
202  return cppgc::internal::WriteBarrier::Type::kNone;
203  }
204  cppgc::HeapHandle& handle = callback();
205  if (!cppgc::subtle::HeapState::IsMarking(handle)) {
206  return cppgc::internal::WriteBarrier::Type::kNone;
207  }
208  params.heap = &handle;
209 #if V8_ENABLE_CHECKS
210  params.type = cppgc::internal::WriteBarrier::Type::kMarking;
211 #endif // !V8_ENABLE_CHECKS
212  return cppgc::internal::WriteBarrier::Type::kMarking;
213  }
214 
215  /**
216  * Gets the required write barrier type for a specific write.
217  *
218  * Note: Handling for JS to C++ references.
219  *
220  * \param wrapper The wrapper that has been written into.
221  * \param wrapper_index The wrapper index in `wrapper` that has been written
222  * into.
223  * \param wrappable The value that was written.
224  * \param params Parameters that may be used for actual write barrier calls.
225  * Only filled if return value indicates that a write barrier is needed. The
226  * contents of the `params` are an implementation detail.
227  * \param callback Callback returning the corresponding heap handle. The
228  * callback is only invoked if the heap cannot otherwise be figured out. The
229  * callback must not allocate.
230  * \returns whether a write barrier is needed and which barrier to invoke.
231  */
232  template <typename HeapHandleCallback>
233  static V8_INLINE WriteBarrierType GetWriteBarrierType(
234  v8::Local<v8::Object>& wrapper, int wrapper_index, const void* wrappable,
235  WriteBarrierParams& params, HeapHandleCallback callback) {
236 #if V8_ENABLE_CHECKS
237  CheckWrapper(wrapper, wrapper_index, wrappable);
238 #endif // V8_ENABLE_CHECKS
239  return cppgc::internal::WriteBarrier::
240  GetWriteBarrierTypeForExternallyReferencedObject(wrappable, params,
241  callback);
242  }
243 
244  /**
245  * Conservative Dijkstra-style write barrier that processes an object if it
246  * has not yet been processed.
247  *
248  * \param params The parameters retrieved from `GetWriteBarrierType()`.
249  * \param ref The reference being written to.
250  */
251  static V8_INLINE void DijkstraMarkingBarrier(const WriteBarrierParams& params,
252  cppgc::HeapHandle& heap_handle,
253  const TracedReferenceBase& ref) {
254  cppgc::internal::WriteBarrier::CheckParams(WriteBarrierType::kMarking,
255  params);
256  DijkstraMarkingBarrierSlow(heap_handle, ref);
257  }
258 
259  /**
260  * Conservative Dijkstra-style write barrier that processes an object if it
261  * has not yet been processed.
262  *
263  * \param params The parameters retrieved from `GetWriteBarrierType()`.
264  * \param object The pointer to the object. May be an interior pointer to a
265  * an interface of the actual object.
266  */
267  static V8_INLINE void DijkstraMarkingBarrier(const WriteBarrierParams& params,
268  cppgc::HeapHandle& heap_handle,
269  const void* object) {
270  cppgc::internal::WriteBarrier::DijkstraMarkingBarrier(params, object);
271  }
272 
273  /**
274  * Generational barrier for maintaining consistency when running with multiple
275  * generations.
276  *
277  * \param params The parameters retrieved from `GetWriteBarrierType()`.
278  * \param ref The reference being written to.
279  */
280  static V8_INLINE void GenerationalBarrier(const WriteBarrierParams& params,
281  const TracedReferenceBase& ref) {}
282 
283  private:
284  JSHeapConsistency() = delete;
285 
286  static void CheckWrapper(v8::Local<v8::Object>&, int, const void*);
287 
288  static void DijkstraMarkingBarrierSlow(cppgc::HeapHandle&,
289  const TracedReferenceBase& ref);
290 };
291 
292 /**
293  * Provided as input to `CppHeap::CollectCustomSpaceStatisticsAtLastGC()`.
294  *
295  * Its method is invoked with the results of the statistic collection.
296  */
298  public:
299  virtual ~CustomSpaceStatisticsReceiver() = default;
300  /**
301  * Reports the size of a space at the last GC. It is called for each space
302  * that was requested in `CollectCustomSpaceStatisticsAtLastGC()`.
303  *
304  * \param space_index The index of the space.
305  * \param bytes The total size of live objects in the space at the last GC.
306  * It is zero if there was no GC yet.
307  */
308  virtual void AllocatedBytes(cppgc::CustomSpaceIndex space_index,
309  size_t bytes) = 0;
310 };
311 
312 } // namespace v8
313 
314 namespace cppgc {
315 
316 template <typename T>
318  static void Trace(Visitor* visitor, const v8::TracedReference<T>* self) {
319  static_cast<v8::JSVisitor*>(visitor)->Trace(*self);
320  }
321 };
322 
323 } // namespace cppgc
324 
325 #endif // INCLUDE_V8_CPPGC_H_