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/visitor.h"
16 #include "v8-internal.h"       // NOLINT(build/include_directory)
17 #include "v8-platform.h"       // NOLINT(build/include_directory)
18 #include "v8-traced-handle.h"  // NOLINT(build/include_directory)
19 
20 namespace cppgc {
21 class AllocationHandle;
22 class HeapHandle;
23 }  // namespace cppgc
24 
25 namespace v8 {
26 
27 class Object;
28 
29 namespace internal {
30 class CppHeap;
31 }  // namespace internal
32 
33 class CustomSpaceStatisticsReceiver;
34 
35 /**
36  * Describes how V8 wrapper objects maintain references to garbage-collected C++
37  * objects.
38  */
39 struct WrapperDescriptor final {
40   /**
41    * The index used on `v8::Ojbect::SetAlignedPointerFromInternalField()` and
42    * related APIs to add additional data to an object which is used to identify
43    * JS->C++ references.
44    */
45   using InternalFieldIndex = int;
46 
47   /**
48    * Unknown embedder id. The value is reserved for internal usages and must not
49    * be used with `CppHeap`.
50    */
51   static constexpr uint16_t kUnknownEmbedderId = UINT16_MAX;
52 
WrapperDescriptorv8::final53   constexpr WrapperDescriptor(InternalFieldIndex wrappable_type_index,
54                               InternalFieldIndex wrappable_instance_index,
55                               uint16_t embedder_id_for_garbage_collected)
56       : wrappable_type_index(wrappable_type_index),
57         wrappable_instance_index(wrappable_instance_index),
58         embedder_id_for_garbage_collected(embedder_id_for_garbage_collected) {}
59 
60   /**
61    * Index of the wrappable type.
62    */
63   InternalFieldIndex wrappable_type_index;
64 
65   /**
66    * Index of the wrappable instance.
67    */
68   InternalFieldIndex wrappable_instance_index;
69 
70   /**
71    * Embedder id identifying instances of garbage-collected objects. It is
72    * expected that the first field of the wrappable type is a uint16_t holding
73    * the id. Only references to instances of wrappables types with an id of
74    * `embedder_id_for_garbage_collected` will be considered by CppHeap.
75    */
76   uint16_t embedder_id_for_garbage_collected;
77 };
78 
79 struct V8_EXPORT CppHeapCreateParams {
CppHeapCreateParamsv8::CppHeapCreateParams80   CppHeapCreateParams(
81       std::vector<std::unique_ptr<cppgc::CustomSpaceBase>> custom_spaces,
82       WrapperDescriptor wrapper_descriptor)
83       : custom_spaces(std::move(custom_spaces)),
84         wrapper_descriptor(wrapper_descriptor) {}
85 
86   CppHeapCreateParams(const CppHeapCreateParams&) = delete;
87   CppHeapCreateParams& operator=(const CppHeapCreateParams&) = delete;
88 
89   std::vector<std::unique_ptr<cppgc::CustomSpaceBase>> custom_spaces;
90   WrapperDescriptor wrapper_descriptor;
91   /**
92    * Specifies which kind of marking are supported by the heap. The type may be
93    * further reduced via runtime flags when attaching the heap to an Isolate.
94    */
95   cppgc::Heap::MarkingType marking_support =
96       cppgc::Heap::MarkingType::kIncrementalAndConcurrent;
97   /**
98    * Specifies which kind of sweeping is supported by the heap. The type may be
99    * further reduced via runtime flags when attaching the heap to an Isolate.
100    */
101   cppgc::Heap::SweepingType sweeping_support =
102       cppgc::Heap::SweepingType::kIncrementalAndConcurrent;
103 };
104 
105 /**
106  * A heap for allocating managed C++ objects.
107  *
108  * Similar to v8::Isolate, the heap may only be accessed from one thread at a
109  * time. The heap may be used from different threads using the
110  * v8::Locker/v8::Unlocker APIs which is different from generic Oilpan.
111  */
112 class V8_EXPORT CppHeap {
113  public:
114   static std::unique_ptr<CppHeap> Create(v8::Platform* platform,
115                                          const CppHeapCreateParams& params);
116 
117   virtual ~CppHeap() = default;
118 
119   /**
120    * \returns the opaque handle for allocating objects using
121    * `MakeGarbageCollected()`.
122    */
123   cppgc::AllocationHandle& GetAllocationHandle();
124 
125   /**
126    * \returns the opaque heap handle which may be used to refer to this heap in
127    *   other APIs. Valid as long as the underlying `CppHeap` is alive.
128    */
129   cppgc::HeapHandle& GetHeapHandle();
130 
131   /**
132    * Terminate clears all roots and performs multiple garbage collections to
133    * reclaim potentially newly created objects in destructors.
134    *
135    * After this call, object allocation is prohibited.
136    */
137   void Terminate();
138 
139   /**
140    * \param detail_level specifies whether should return detailed
141    *   statistics or only brief summary statistics.
142    * \returns current CppHeap statistics regarding memory consumption
143    *   and utilization.
144    */
145   cppgc::HeapStatistics CollectStatistics(
146       cppgc::HeapStatistics::DetailLevel detail_level);
147 
148   /**
149    * Collects statistics for the given spaces and reports them to the receiver.
150    *
151    * \param custom_spaces a collection of custom space indicies.
152    * \param receiver an object that gets the results.
153    */
154   void CollectCustomSpaceStatisticsAtLastGC(
155       std::vector<cppgc::CustomSpaceIndex> custom_spaces,
156       std::unique_ptr<CustomSpaceStatisticsReceiver> receiver);
157 
158   /**
159    * Enables a detached mode that allows testing garbage collection using
160    * `cppgc::testing` APIs. Once used, the heap cannot be attached to an
161    * `Isolate` anymore.
162    */
163   void EnableDetachedGarbageCollectionsForTesting();
164 
165   /**
166    * Performs a stop-the-world garbage collection for testing purposes.
167    *
168    * \param stack_state The stack state to assume for the garbage collection.
169    */
170   void CollectGarbageForTesting(cppgc::EmbedderStackState stack_state);
171 
172   /**
173    * Performs a stop-the-world minor garbage collection for testing purposes.
174    *
175    * \param stack_state The stack state to assume for the garbage collection.
176    */
177   void CollectGarbageInYoungGenerationForTesting(
178       cppgc::EmbedderStackState stack_state);
179 
180  private:
181   CppHeap() = default;
182 
183   friend class internal::CppHeap;
184 };
185 
186 class JSVisitor : public cppgc::Visitor {
187  public:
JSVisitor(cppgc::Visitor::Key key)188   explicit JSVisitor(cppgc::Visitor::Key key) : cppgc::Visitor(key) {}
189   ~JSVisitor() override = default;
190 
Trace(const TracedReferenceBase& ref)191   void Trace(const TracedReferenceBase& ref) {
192     if (ref.IsEmptyThreadSafe()) return;
193     Visit(ref);
194   }
195 
196  protected:
197   using cppgc::Visitor::Visit;
198 
Visit(const TracedReferenceBase& ref)199   virtual void Visit(const TracedReferenceBase& ref) {}
200 };
201 
202 /**
203  * Provided as input to `CppHeap::CollectCustomSpaceStatisticsAtLastGC()`.
204  *
205  * Its method is invoked with the results of the statistic collection.
206  */
207 class CustomSpaceStatisticsReceiver {
208  public:
209   virtual ~CustomSpaceStatisticsReceiver() = default;
210   /**
211    * Reports the size of a space at the last GC. It is called for each space
212    * that was requested in `CollectCustomSpaceStatisticsAtLastGC()`.
213    *
214    * \param space_index The index of the space.
215    * \param bytes The total size of live objects in the space at the last GC.
216    *    It is zero if there was no GC yet.
217    */
218   virtual void AllocatedBytes(cppgc::CustomSpaceIndex space_index,
219                               size_t bytes) = 0;
220 };
221 
222 }  // namespace v8
223 
224 namespace cppgc {
225 
226 template <typename T>
227 struct TraceTrait<v8::TracedReference<T>> {
GetTraceDescriptorcppgc::TraceTrait228   static cppgc::TraceDescriptor GetTraceDescriptor(const void* self) {
229     return {nullptr, Trace};
230   }
231 
Tracecppgc::TraceTrait232   static void Trace(Visitor* visitor, const void* self) {
233     static_cast<v8::JSVisitor*>(visitor)->Trace(
234         *static_cast<const v8::TracedReference<T>*>(self));
235   }
236 };
237 
238 }  // namespace cppgc
239 
240 #endif  // INCLUDE_V8_CPPGC_H_
241