1 // Copyright 2021 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_EMBEDDER_HEAP_H_
6 #define INCLUDE_V8_EMBEDDER_HEAP_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <utility>
12 #include <vector>
13 
14 #include "cppgc/common.h"
15 #include "v8-local-handle.h"   // NOLINT(build/include_directory)
16 #include "v8-traced-handle.h"  // NOLINT(build/include_directory)
17 #include "v8config.h"          // NOLINT(build/include_directory)
18 
19 namespace v8 {
20 
21 class Data;
22 class Isolate;
23 class Value;
24 
25 namespace internal {
26 class LocalEmbedderHeapTracer;
27 }  // namespace internal
28 
29 /**
30  * Handler for embedder roots on non-unified heap garbage collections.
31  */
32 class V8_EXPORT EmbedderRootsHandler {
33  public:
34   virtual ~EmbedderRootsHandler() = default;
35 
36   /**
37    * Returns true if the TracedGlobal handle should be considered as root for
38    * the currently running non-tracing garbage collection and false otherwise.
39    * The default implementation will keep all TracedGlobal references as roots.
40    *
41    * If this returns false, then V8 may decide that the object referred to by
42    * such a handle is reclaimed. In that case:
43    * - No action is required if handles are used with destructors, i.e., by just
44    *   using |TracedGlobal|.
45    * - When run without destructors, i.e., by using |TracedReference|, V8 calls
46    *  |ResetRoot|.
47    *
48    * Note that the |handle| is different from the handle that the embedder holds
49    * for retaining the object. The embedder may use |WrapperClassId()| to
50    * distinguish cases where it wants handles to be treated as roots from not
51    * being treated as roots.
52    */
53   virtual bool IsRoot(const v8::TracedReference<v8::Value>& handle) = 0;
54   virtual bool IsRoot(const v8::TracedGlobal<v8::Value>& handle) = 0;
55 
56   /**
57    * Used in combination with |IsRoot|. Called by V8 when an
58    * object that is backed by a handle is reclaimed by a non-tracing garbage
59    * collection. It is up to the embedder to reset the original handle.
60    *
61    * Note that the |handle| is different from the handle that the embedder holds
62    * for retaining the object. It is up to the embedder to find the original
63    * handle via the object or class id.
64    */
65   virtual void ResetRoot(const v8::TracedReference<v8::Value>& handle) = 0;
66 };
67 
68 /**
69  * Interface for tracing through the embedder heap. During a V8 garbage
70  * collection, V8 collects hidden fields of all potential wrappers, and at the
71  * end of its marking phase iterates the collection and asks the embedder to
72  * trace through its heap and use reporter to report each JavaScript object
73  * reachable from any of the given wrappers.
74  */
75 class V8_EXPORT EmbedderHeapTracer {
76  public:
77   using EmbedderStackState = cppgc::EmbedderStackState;
78 
79   enum TraceFlags : uint64_t {
80     kNoFlags = 0,
81     kReduceMemory = 1 << 0,
82     kForced = 1 << 2,
83   };
84 
85   /**
86    * Interface for iterating through TracedGlobal handles.
87    */
88   class V8_EXPORT TracedGlobalHandleVisitor {
89    public:
90     virtual ~TracedGlobalHandleVisitor() = default;
VisitTracedGlobalHandle(const TracedGlobal<Value> & handle)91     virtual void VisitTracedGlobalHandle(const TracedGlobal<Value>& handle) {}
VisitTracedReference(const TracedReference<Value> & handle)92     virtual void VisitTracedReference(const TracedReference<Value>& handle) {}
93   };
94 
95   /**
96    * Summary of a garbage collection cycle. See |TraceEpilogue| on how the
97    * summary is reported.
98    */
99   struct TraceSummary {
100     /**
101      * Time spent managing the retained memory in milliseconds. This can e.g.
102      * include the time tracing through objects in the embedder.
103      */
104     double time = 0.0;
105 
106     /**
107      * Memory retained by the embedder through the |EmbedderHeapTracer|
108      * mechanism in bytes.
109      */
110     size_t allocated_size = 0;
111   };
112 
113   virtual ~EmbedderHeapTracer() = default;
114 
115   /**
116    * Iterates all TracedGlobal handles created for the v8::Isolate the tracer is
117    * attached to.
118    */
119   void IterateTracedGlobalHandles(TracedGlobalHandleVisitor* visitor);
120 
121   /**
122    * Called by the embedder to set the start of the stack which is e.g. used by
123    * V8 to determine whether handles are used from stack or heap.
124    */
125   void SetStackStart(void* stack_start);
126 
127   /**
128    * Called by the embedder to notify V8 of an empty execution stack.
129    */
130   V8_DEPRECATE_SOON(
131       "This call only optimized internal caches which V8 is able to figure out "
132       "on its own now.")
133   void NotifyEmptyEmbedderStack();
134 
135   /**
136    * Called by v8 to register internal fields of found wrappers.
137    *
138    * The embedder is expected to store them somewhere and trace reachable
139    * wrappers from them when called through |AdvanceTracing|.
140    */
141   virtual void RegisterV8References(
142       const std::vector<std::pair<void*, void*>>& embedder_fields) = 0;
143 
144   void RegisterEmbedderReference(const BasicTracedReference<v8::Data>& ref);
145 
146   /**
147    * Called at the beginning of a GC cycle.
148    */
TracePrologue(TraceFlags flags)149   virtual void TracePrologue(TraceFlags flags) {}
150 
151   /**
152    * Called to advance tracing in the embedder.
153    *
154    * The embedder is expected to trace its heap starting from wrappers reported
155    * by RegisterV8References method, and report back all reachable wrappers.
156    * Furthermore, the embedder is expected to stop tracing by the given
157    * deadline. A deadline of infinity means that tracing should be finished.
158    *
159    * Returns |true| if tracing is done, and false otherwise.
160    */
161   virtual bool AdvanceTracing(double deadline_in_ms) = 0;
162 
163   /*
164    * Returns true if there no more tracing work to be done (see AdvanceTracing)
165    * and false otherwise.
166    */
167   virtual bool IsTracingDone() = 0;
168 
169   /**
170    * Called at the end of a GC cycle.
171    *
172    * Note that allocation is *not* allowed within |TraceEpilogue|. Can be
173    * overriden to fill a |TraceSummary| that is used by V8 to schedule future
174    * garbage collections.
175    */
TraceEpilogue(TraceSummary * trace_summary)176   virtual void TraceEpilogue(TraceSummary* trace_summary) {}
177 
178   /**
179    * Called upon entering the final marking pause. No more incremental marking
180    * steps will follow this call.
181    */
182   virtual void EnterFinalPause(EmbedderStackState stack_state) = 0;
183 
184   /*
185    * Called by the embedder to request immediate finalization of the currently
186    * running tracing phase that has been started with TracePrologue and not
187    * yet finished with TraceEpilogue.
188    *
189    * Will be a noop when currently not in tracing.
190    *
191    * This is an experimental feature.
192    */
193   void FinalizeTracing();
194 
195   /**
196    * See documentation on EmbedderRootsHandler.
197    */
198   virtual bool IsRootForNonTracingGC(
199       const v8::TracedReference<v8::Value>& handle);
200   virtual bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>& handle);
201 
202   /**
203    * See documentation on EmbedderRootsHandler.
204    */
205   virtual void ResetHandleInNonTracingGC(
206       const v8::TracedReference<v8::Value>& handle);
207 
208   /*
209    * Called by the embedder to immediately perform a full garbage collection.
210    *
211    * Should only be used in testing code.
212    */
213   void GarbageCollectionForTesting(EmbedderStackState stack_state);
214 
215   /*
216    * Called by the embedder to signal newly allocated or freed memory. Not bound
217    * to tracing phases. Embedders should trade off when increments are reported
218    * as V8 may consult global heuristics on whether to trigger garbage
219    * collection on this change.
220    */
221   void IncreaseAllocatedSize(size_t bytes);
222   void DecreaseAllocatedSize(size_t bytes);
223 
224   /*
225    * Returns the v8::Isolate this tracer is attached too and |nullptr| if it
226    * is not attached to any v8::Isolate.
227    */
isolate()228   v8::Isolate* isolate() const { return isolate_; }
229 
230  protected:
231   v8::Isolate* isolate_ = nullptr;
232 
233   friend class internal::LocalEmbedderHeapTracer;
234 };
235 
236 }  // namespace v8
237 
238 #endif  // INCLUDE_V8_EMBEDDER_HEAP_H_
239