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