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