Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / js / public / TracingAPI.h
blob4db1b0a30ca570403e417eb38e937c0220ecb6c5
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef js_TracingAPI_h
8 #define js_TracingAPI_h
10 #include "js/GCTypeMacros.h"
11 #include "js/HeapAPI.h"
12 #include "js/TraceKind.h"
14 class JS_PUBLIC_API JSTracer;
16 namespace JS {
17 class JS_PUBLIC_API CallbackTracer;
18 template <typename T>
19 class Heap;
20 template <typename T>
21 class TenuredHeap;
23 /** Returns a static string equivalent of |kind|. */
24 JS_PUBLIC_API const char* GCTraceKindToAscii(JS::TraceKind kind);
26 /** Returns the base size in bytes of the GC thing of kind |kind|. */
27 JS_PUBLIC_API size_t GCTraceKindSize(JS::TraceKind kind);
29 // Kinds of JSTracer.
30 enum class TracerKind {
31 // Generic tracers: Internal tracers that have a different virtual method
32 // called for each edge kind.
33 Marking,
34 Tenuring,
35 Moving,
36 ClearEdges,
37 Sweeping,
38 MinorSweeping,
39 Barrier,
41 // Callback tracers: General-purpose tracers that have a single virtual
42 // method called on every edge.
44 // Order is important. All callback kinds must follow this one.
45 Callback,
47 // Specific kinds of callback tracer.
48 UnmarkGray,
49 VerifyTraceProtoAndIface,
50 CompartmentCheck,
53 enum class WeakMapTraceAction {
54 /**
55 * Do not trace into weak map keys or values during traversal. Users must
56 * handle weak maps manually.
58 Skip,
60 /**
61 * Do true ephemeron marking with a weak key lookup marking phase. This is
62 * the default for GCMarker.
64 Expand,
66 /**
67 * Trace through to all values, irrespective of whether the keys are live
68 * or not. Used for non-marking tracers.
70 TraceValues,
72 /**
73 * Trace through to all keys and values, irrespective of whether the keys
74 * are live or not. Used for non-marking tracers.
76 TraceKeysAndValues
79 // Whether a tracer should trace weak edges. GCMarker sets this to Skip.
80 enum class WeakEdgeTraceAction { Skip, Trace };
82 struct TraceOptions {
83 JS::WeakMapTraceAction weakMapAction = WeakMapTraceAction::TraceValues;
84 JS::WeakEdgeTraceAction weakEdgeAction = WeakEdgeTraceAction::Trace;
86 TraceOptions() = default;
87 TraceOptions(JS::WeakMapTraceAction weakMapActionArg,
88 JS::WeakEdgeTraceAction weakEdgeActionArg)
89 : weakMapAction(weakMapActionArg), weakEdgeAction(weakEdgeActionArg) {}
90 MOZ_IMPLICIT TraceOptions(JS::WeakMapTraceAction weakMapActionArg)
91 : weakMapAction(weakMapActionArg) {}
92 MOZ_IMPLICIT TraceOptions(JS::WeakEdgeTraceAction weakEdgeActionArg)
93 : weakEdgeAction(weakEdgeActionArg) {}
96 class AutoTracingIndex;
98 // Optional context information that can be used to construct human readable
99 // descriptions of what is being traced.
100 class TracingContext {
101 public:
102 // Access to the tracing context: When tracing with a JS::CallbackTracer, we
103 // invoke the callback with the edge location and the type of target. This is
104 // useful for operating on the edge in the abstract or on the target thing,
105 // satisfying most common use cases. However, some tracers need additional
106 // detail about the specific edge that is being traced in order to be
107 // useful. Unfortunately, the raw pointer to the edge that we provide is not
108 // enough information to infer much of anything useful about that edge.
110 // In order to better support use cases that care in particular about edges --
111 // as opposed to the target thing -- tracing implementations are responsible
112 // for providing extra context information about each edge they trace, as it
113 // is traced. This contains, at a minimum, an edge name and, when tracing an
114 // array, the index. Further specialization can be achieved (with some
115 // complexity), by associating a functor with the tracer so that, when
116 // requested, the user can generate totally custom edge descriptions.
118 // Returns the current edge's index, if marked as part of an array of edges.
119 // This must be called only inside the trace callback. When not tracing an
120 // array, the value will be InvalidIndex.
121 constexpr static size_t InvalidIndex = size_t(-1);
122 size_t index() const { return index_; }
124 // Build a description of this edge in the heap graph. This call may invoke
125 // the context functor, if set, which may inspect arbitrary areas of the
126 // heap. On the other hand, the description provided by this method may be
127 // substantially more accurate and useful than those provided by only the
128 // name and index.
129 void getEdgeName(const char* name, char* buffer, size_t bufferSize);
131 // The trace implementation may associate a callback with one or more edges
132 // using AutoTracingDetails. This functor is called by getEdgeName and
133 // is responsible for providing a textual representation of the edge currently
134 // being traced. The callback has access to the full heap, including the
135 // currently set tracing context.
136 class Functor {
137 public:
138 virtual void operator()(TracingContext* tcx, char* buf, size_t bufsize) = 0;
141 private:
142 friend class AutoTracingIndex;
143 size_t index_ = InvalidIndex;
145 friend class AutoTracingDetails;
146 Functor* functor_ = nullptr;
149 } // namespace JS
151 class JS_PUBLIC_API JSTracer {
152 public:
153 // Return the runtime set on the tracer.
154 JSRuntime* runtime() const { return runtime_; }
156 JS::TracerKind kind() const { return kind_; }
157 bool isGenericTracer() const { return kind_ < JS::TracerKind::Callback; }
158 bool isCallbackTracer() const { return kind_ >= JS::TracerKind::Callback; }
159 bool isMarkingTracer() const { return kind_ == JS::TracerKind::Marking; }
160 bool isTenuringTracer() const { return kind_ == JS::TracerKind::Tenuring; }
162 inline JS::CallbackTracer* asCallbackTracer();
164 JS::WeakMapTraceAction weakMapAction() const {
165 return options_.weakMapAction;
167 bool traceWeakEdges() const {
168 return options_.weakEdgeAction == JS::WeakEdgeTraceAction::Trace;
171 JS::TracingContext& context() { return context_; }
173 // These methods are called when the tracer encounters an edge. Clients should
174 // override them to receive notifications when an edge of each type is
175 // visited.
177 // The caller updates the edge with the return value (if different).
179 // In C++, overriding a method hides all methods in the base class with that
180 // name, not just methods with that signature. Thus, the typed edge methods
181 // have to have distinct names to allow us to override them individually,
182 // which is freqently useful if, for example, we only want to process one type
183 // of edge.
184 #define DEFINE_ON_EDGE_METHOD(name, type, _1, _2) \
185 virtual void on##name##Edge(type** thingp, const char* name) = 0;
186 JS_FOR_EACH_TRACEKIND(DEFINE_ON_EDGE_METHOD)
187 #undef DEFINE_ON_EDGE_METHOD
189 protected:
190 JSTracer(JSRuntime* rt, JS::TracerKind kind,
191 JS::TraceOptions options = JS::TraceOptions())
192 : runtime_(rt), kind_(kind), options_(options) {}
194 private:
195 JSRuntime* const runtime_;
196 const JS::TracerKind kind_;
197 const JS::TraceOptions options_;
198 JS::TracingContext context_;
201 namespace js {
203 // A CRTP helper class that implements a JSTracer by calling a template method
204 // on the derived tracer type for each edge kind.
205 template <typename T>
206 class GenericTracerImpl : public JSTracer {
207 public:
208 GenericTracerImpl(JSRuntime* rt, JS::TracerKind kind,
209 JS::TraceOptions options)
210 : JSTracer(rt, kind, options) {}
212 private:
213 T* derived() { return static_cast<T*>(this); }
215 #define DEFINE_ON_EDGE_METHOD(name, type, _1, _2) \
216 void on##name##Edge(type** thingp, const char* name) final { \
217 derived()->onEdge(thingp, name); \
219 JS_FOR_EACH_TRACEKIND(DEFINE_ON_EDGE_METHOD)
220 #undef DEFINE_ON_EDGE_METHOD
223 } // namespace js
225 namespace JS {
227 class JS_PUBLIC_API CallbackTracer
228 : public js::GenericTracerImpl<CallbackTracer> {
229 public:
230 CallbackTracer(JSRuntime* rt, JS::TracerKind kind = JS::TracerKind::Callback,
231 JS::TraceOptions options = JS::TraceOptions())
232 : GenericTracerImpl(rt, kind, options) {
233 MOZ_ASSERT(isCallbackTracer());
235 CallbackTracer(JSContext* cx, JS::TracerKind kind = JS::TracerKind::Callback,
236 JS::TraceOptions options = JS::TraceOptions());
238 // Override this method to receive notification when a node in the GC
239 // heap graph is visited.
240 virtual void onChild(JS::GCCellPtr thing, const char* name) = 0;
242 private:
243 template <typename T>
244 void onEdge(T** thingp, const char* name) {
245 onChild(JS::GCCellPtr(*thingp), name);
247 friend class js::GenericTracerImpl<CallbackTracer>;
250 // Set the index portion of the tracer's context for the current range.
251 class MOZ_RAII AutoTracingIndex {
252 JSTracer* trc_;
254 public:
255 explicit AutoTracingIndex(JSTracer* trc, size_t initial = 0) : trc_(trc) {
256 MOZ_ASSERT(trc_->context().index_ == TracingContext::InvalidIndex);
257 trc_->context().index_ = initial;
259 ~AutoTracingIndex() {
260 MOZ_ASSERT(trc_->context().index_ != TracingContext::InvalidIndex);
261 trc_->context().index_ = TracingContext::InvalidIndex;
264 void operator++() {
265 MOZ_ASSERT(trc_->context().index_ != TracingContext::InvalidIndex);
266 ++trc_->context().index_;
270 // Set a context callback for the trace callback to use, if it needs a detailed
271 // edge description.
272 class MOZ_RAII AutoTracingDetails {
273 JSTracer* trc_;
275 public:
276 AutoTracingDetails(JSTracer* trc, TracingContext::Functor& func) : trc_(trc) {
277 MOZ_ASSERT(trc_->context().functor_ == nullptr);
278 trc_->context().functor_ = &func;
280 ~AutoTracingDetails() {
281 MOZ_ASSERT(trc_->context().functor_);
282 trc_->context().functor_ = nullptr;
286 // Save and clear tracing context when performing nested tracing.
287 class MOZ_RAII AutoClearTracingContext {
288 JSTracer* trc_;
289 TracingContext prev_;
291 public:
292 explicit AutoClearTracingContext(JSTracer* trc)
293 : trc_(trc), prev_(trc->context()) {
294 trc_->context() = TracingContext();
297 ~AutoClearTracingContext() { trc_->context() = prev_; }
300 } // namespace JS
302 JS::CallbackTracer* JSTracer::asCallbackTracer() {
303 MOZ_ASSERT(isCallbackTracer());
304 return static_cast<JS::CallbackTracer*>(this);
307 namespace js {
309 class AbstractGeneratorObject;
310 class SavedFrame;
311 namespace wasm {
312 class AnyRef;
313 } // namespace wasm
315 namespace gc {
317 #define JS_DECLARE_TRACE_EXTERNAL_EDGE(type) \
318 extern JS_PUBLIC_API void TraceExternalEdge(JSTracer* trc, type* thingp, \
319 const char* name);
321 // Declare edge-tracing function overloads for public GC pointer types.
322 JS_FOR_EACH_PUBLIC_GC_POINTER_TYPE(JS_DECLARE_TRACE_EXTERNAL_EDGE)
323 JS_FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(JS_DECLARE_TRACE_EXTERNAL_EDGE)
325 #undef JS_DECLARE_TRACE_EXTERNAL_EDGE
327 } // namespace gc
328 } // namespace js
330 namespace JS {
332 // The JS::TraceEdge family of functions traces the given GC thing reference.
333 // This performs the tracing action configured on the given JSTracer: typically
334 // calling the JSTracer::callback or marking the thing as live.
336 // The argument to JS::TraceEdge is an in-out param: when the function returns,
337 // the garbage collector might have moved the GC thing. In this case, the
338 // reference passed to JS::TraceEdge will be updated to the thing's new
339 // location. Callers of this method are responsible for updating any state that
340 // is dependent on the object's address. For example, if the object's address
341 // is used as a key in a hashtable, then the object must be removed and
342 // re-inserted with the correct hash.
344 // Note that while |edgep| must never be null, it is fine for |*edgep| to be
345 // nullptr.
347 template <typename T>
348 inline void TraceEdge(JSTracer* trc, JS::Heap<T>* thingp, const char* name) {
349 MOZ_ASSERT(thingp);
350 if (*thingp) {
351 js::gc::TraceExternalEdge(trc, thingp->unsafeGet(), name);
355 template <typename T>
356 inline void TraceEdge(JSTracer* trc, JS::TenuredHeap<T>* thingp,
357 const char* name) {
358 MOZ_ASSERT(thingp);
359 if (T ptr = thingp->unbarrieredGetPtr()) {
360 js::gc::TraceExternalEdge(trc, &ptr, name);
361 thingp->setPtr(ptr);
365 // Edges that are always traced as part of root marking do not require
366 // incremental barriers. |JS::TraceRoot| overloads allow for marking
367 // non-barriered pointers but assert that this happens during root marking.
369 // Note that while |edgep| must never be null, it is fine for |*edgep| to be
370 // nullptr.
371 #define JS_DECLARE_TRACE_ROOT(type) \
372 extern JS_PUBLIC_API void TraceRoot(JSTracer* trc, type* edgep, \
373 const char* name);
375 // Declare edge-tracing function overloads for public GC pointer types.
376 JS_FOR_EACH_PUBLIC_GC_POINTER_TYPE(JS_DECLARE_TRACE_ROOT)
377 JS_FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(JS_DECLARE_TRACE_ROOT)
379 // We also require overloads for these purely-internal types. These overloads
380 // ought not be in public headers, and they should use a different name in order
381 // to not be *actual* overloads, but for the moment we still declare them here.
382 JS_DECLARE_TRACE_ROOT(js::AbstractGeneratorObject*)
383 JS_DECLARE_TRACE_ROOT(js::SavedFrame*)
384 JS_DECLARE_TRACE_ROOT(js::wasm::AnyRef)
386 #undef JS_DECLARE_TRACE_ROOT
388 extern JS_PUBLIC_API void TraceChildren(JSTracer* trc, GCCellPtr thing);
390 } // namespace JS
392 namespace js {
394 inline bool IsTracerKind(JSTracer* trc, JS::TracerKind kind) {
395 return trc->kind() == kind;
398 // Trace an edge that is not a GC root and is not wrapped in a barriered
399 // wrapper for some reason.
401 // This method does not check if |*edgep| is non-null before tracing through
402 // it, so callers must check any nullable pointer before calling this method.
403 extern JS_PUBLIC_API void UnsafeTraceManuallyBarrieredEdge(JSTracer* trc,
404 JSObject** thingp,
405 const char* name);
407 namespace gc {
409 // Return true if the given edge is not live and is about to be swept.
410 template <typename T>
411 extern JS_PUBLIC_API bool TraceWeakEdge(JSTracer* trc, JS::Heap<T>* thingp);
413 } // namespace gc
415 #ifdef DEBUG
417 * Return whether the runtime is currently being destroyed, for use in
418 * assertions.
420 extern JS_PUBLIC_API bool RuntimeIsBeingDestroyed();
421 #endif
423 } // namespace js
425 #endif /* js_TracingAPI_h */