TracingAPI.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #ifndef js_TracingAPI_h
  6. #define js_TracingAPI_h
  7. #include "jsalloc.h"
  8. #include "js/HashTable.h"
  9. #include "js/HeapAPI.h"
  10. #include "js/TraceKind.h"
  11. class JS_PUBLIC_API(JSTracer);
  12. namespace JS {
  13. class JS_PUBLIC_API(CallbackTracer);
  14. template <typename T> class Heap;
  15. template <typename T> class TenuredHeap;
  16. /** Returns a static string equivalent of |kind|. */
  17. JS_FRIEND_API(const char*)
  18. GCTraceKindToAscii(JS::TraceKind kind);
  19. } // namespace JS
  20. enum WeakMapTraceKind {
  21. /**
  22. * Do not trace into weak map keys or values during traversal. Users must
  23. * handle weak maps manually.
  24. */
  25. DoNotTraceWeakMaps,
  26. /**
  27. * Do true ephemeron marking with a weak key lookup marking phase. This is
  28. * the default for GCMarker.
  29. */
  30. ExpandWeakMaps,
  31. /**
  32. * Trace through to all values, irrespective of whether the keys are live
  33. * or not. Used for non-marking tracers.
  34. */
  35. TraceWeakMapValues,
  36. /**
  37. * Trace through to all keys and values, irrespective of whether the keys
  38. * are live or not. Used for non-marking tracers.
  39. */
  40. TraceWeakMapKeysValues
  41. };
  42. class JS_PUBLIC_API(JSTracer)
  43. {
  44. public:
  45. // Return the runtime set on the tracer.
  46. JSRuntime* runtime() const { return runtime_; }
  47. // Return the weak map tracing behavior currently set on this tracer.
  48. WeakMapTraceKind weakMapAction() const { return weakMapAction_; }
  49. enum class TracerKindTag {
  50. // Marking path: a tracer used only for marking liveness of cells, not
  51. // for moving them. The kind will transition to WeakMarking after
  52. // everything reachable by regular edges has been marked.
  53. Marking,
  54. // Same as Marking, except we have now moved on to the "weak marking
  55. // phase", in which every marked obj/script is immediately looked up to
  56. // see if it is a weak map key (and therefore might require marking its
  57. // weak map value).
  58. WeakMarking,
  59. // A tracer that traverses the graph for the purposes of moving objects
  60. // from the nursery to the tenured area.
  61. Tenuring,
  62. // General-purpose traversal that invokes a callback on each cell.
  63. // Traversing children is the responsibility of the callback.
  64. Callback
  65. };
  66. bool isMarkingTracer() const { return tag_ == TracerKindTag::Marking || tag_ == TracerKindTag::WeakMarking; }
  67. bool isWeakMarkingTracer() const { return tag_ == TracerKindTag::WeakMarking; }
  68. bool isTenuringTracer() const { return tag_ == TracerKindTag::Tenuring; }
  69. bool isCallbackTracer() const { return tag_ == TracerKindTag::Callback; }
  70. inline JS::CallbackTracer* asCallbackTracer();
  71. #ifdef DEBUG
  72. bool checkEdges() { return checkEdges_; }
  73. #endif
  74. protected:
  75. JSTracer(JSRuntime* rt, TracerKindTag tag,
  76. WeakMapTraceKind weakTraceKind = TraceWeakMapValues)
  77. : runtime_(rt)
  78. , weakMapAction_(weakTraceKind)
  79. #ifdef DEBUG
  80. , checkEdges_(true)
  81. #endif
  82. , tag_(tag)
  83. {}
  84. #ifdef DEBUG
  85. // Set whether to check edges are valid in debug builds.
  86. void setCheckEdges(bool check) {
  87. checkEdges_ = check;
  88. }
  89. #endif
  90. private:
  91. JSRuntime* runtime_;
  92. WeakMapTraceKind weakMapAction_;
  93. #ifdef DEBUG
  94. bool checkEdges_;
  95. #endif
  96. protected:
  97. TracerKindTag tag_;
  98. };
  99. namespace JS {
  100. class AutoTracingName;
  101. class AutoTracingIndex;
  102. class AutoTracingCallback;
  103. class JS_PUBLIC_API(CallbackTracer) : public JSTracer
  104. {
  105. public:
  106. CallbackTracer(JSRuntime* rt, WeakMapTraceKind weakTraceKind = TraceWeakMapValues)
  107. : JSTracer(rt, JSTracer::TracerKindTag::Callback, weakTraceKind),
  108. contextName_(nullptr), contextIndex_(InvalidIndex), contextFunctor_(nullptr)
  109. {}
  110. CallbackTracer(JSContext* cx, WeakMapTraceKind weakTraceKind = TraceWeakMapValues);
  111. // Override these methods to receive notification when an edge is visited
  112. // with the type contained in the callback. The default implementation
  113. // dispatches to the fully-generic onChild implementation, so for cases that
  114. // do not care about boxing overhead and do not need the actual edges,
  115. // just override the generic onChild.
  116. virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); }
  117. virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); }
  118. virtual void onSymbolEdge(JS::Symbol** symp) { onChild(JS::GCCellPtr(*symp)); }
  119. virtual void onScriptEdge(JSScript** scriptp) { onChild(JS::GCCellPtr(*scriptp)); }
  120. virtual void onShapeEdge(js::Shape** shapep) {
  121. onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape));
  122. }
  123. virtual void onObjectGroupEdge(js::ObjectGroup** groupp) {
  124. onChild(JS::GCCellPtr(*groupp, JS::TraceKind::ObjectGroup));
  125. }
  126. virtual void onBaseShapeEdge(js::BaseShape** basep) {
  127. onChild(JS::GCCellPtr(*basep, JS::TraceKind::BaseShape));
  128. }
  129. virtual void onJitCodeEdge(js::jit::JitCode** codep) {
  130. onChild(JS::GCCellPtr(*codep, JS::TraceKind::JitCode));
  131. }
  132. virtual void onLazyScriptEdge(js::LazyScript** lazyp) {
  133. onChild(JS::GCCellPtr(*lazyp, JS::TraceKind::LazyScript));
  134. }
  135. virtual void onScopeEdge(js::Scope** scopep) {
  136. onChild(JS::GCCellPtr(*scopep, JS::TraceKind::Scope));
  137. }
  138. // Override this method to receive notification when a node in the GC
  139. // heap graph is visited.
  140. virtual void onChild(const JS::GCCellPtr& thing) = 0;
  141. // Access to the tracing context:
  142. // When tracing with a JS::CallbackTracer, we invoke the callback with the
  143. // edge location and the type of target. This is useful for operating on
  144. // the edge in the abstract or on the target thing, satisfying most common
  145. // use cases. However, some tracers need additional detail about the
  146. // specific edge that is being traced in order to be useful. Unfortunately,
  147. // the raw pointer to the edge that we provide is not enough information to
  148. // infer much of anything useful about that edge.
  149. //
  150. // In order to better support use cases that care in particular about edges
  151. // -- as opposed to the target thing -- tracing implementations are
  152. // responsible for providing extra context information about each edge they
  153. // trace, as it is traced. This contains, at a minimum, an edge name and,
  154. // when tracing an array, the index. Further specialization can be achived
  155. // (with some complexity), by associating a functor with the tracer so
  156. // that, when requested, the user can generate totally custom edge
  157. // descriptions.
  158. // Returns the current edge's name. It is only valid to call this when
  159. // inside the trace callback, however, the edge name will always be set.
  160. const char* contextName() const { MOZ_ASSERT(contextName_); return contextName_; }
  161. // Returns the current edge's index, if marked as part of an array of edges.
  162. // This must be called only inside the trace callback. When not tracing an
  163. // array, the value will be InvalidIndex.
  164. const static size_t InvalidIndex = size_t(-1);
  165. size_t contextIndex() const { return contextIndex_; }
  166. // Build a description of this edge in the heap graph. This call may invoke
  167. // the context functor, if set, which may inspect arbitrary areas of the
  168. // heap. On the other hand, the description provided by this method may be
  169. // substantially more accurate and useful than those provided by only the
  170. // contextName and contextIndex.
  171. void getTracingEdgeName(char* buffer, size_t bufferSize);
  172. // The trace implementation may associate a callback with one or more edges
  173. // using AutoTracingDetails. This functor is called by getTracingEdgeName
  174. // and is responsible for providing a textual representation of the
  175. // currently being traced edge. The callback has access to the full heap,
  176. // including the currently set tracing context.
  177. class ContextFunctor {
  178. public:
  179. virtual void operator()(CallbackTracer* trc, char* buf, size_t bufsize) = 0;
  180. };
  181. #ifdef DEBUG
  182. enum class TracerKind { DoNotCare, Moving, GrayBuffering, VerifyTraceProtoAndIface };
  183. virtual TracerKind getTracerKind() const { return TracerKind::DoNotCare; }
  184. #endif
  185. // In C++, overriding a method hides all methods in the base class with
  186. // that name, not just methods with that signature. Thus, the typed edge
  187. // methods have to have distinct names to allow us to override them
  188. // individually, which is freqently useful if, for example, we only want to
  189. // process only one type of edge.
  190. void dispatchToOnEdge(JSObject** objp) { onObjectEdge(objp); }
  191. void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); }
  192. void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); }
  193. void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); }
  194. void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); }
  195. void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); }
  196. void dispatchToOnEdge(js::BaseShape** basep) { onBaseShapeEdge(basep); }
  197. void dispatchToOnEdge(js::jit::JitCode** codep) { onJitCodeEdge(codep); }
  198. void dispatchToOnEdge(js::LazyScript** lazyp) { onLazyScriptEdge(lazyp); }
  199. void dispatchToOnEdge(js::Scope** scopep) { onScopeEdge(scopep); }
  200. private:
  201. friend class AutoTracingName;
  202. const char* contextName_;
  203. friend class AutoTracingIndex;
  204. size_t contextIndex_;
  205. friend class AutoTracingDetails;
  206. ContextFunctor* contextFunctor_;
  207. };
  208. // Set the name portion of the tracer's context for the current edge.
  209. class MOZ_RAII AutoTracingName
  210. {
  211. CallbackTracer* trc_;
  212. const char* prior_;
  213. public:
  214. AutoTracingName(CallbackTracer* trc, const char* name) : trc_(trc), prior_(trc->contextName_) {
  215. MOZ_ASSERT(name);
  216. trc->contextName_ = name;
  217. }
  218. ~AutoTracingName() {
  219. MOZ_ASSERT(trc_->contextName_);
  220. trc_->contextName_ = prior_;
  221. }
  222. };
  223. // Set the index portion of the tracer's context for the current range.
  224. class MOZ_RAII AutoTracingIndex
  225. {
  226. CallbackTracer* trc_;
  227. public:
  228. explicit AutoTracingIndex(JSTracer* trc, size_t initial = 0) : trc_(nullptr) {
  229. if (trc->isCallbackTracer()) {
  230. trc_ = trc->asCallbackTracer();
  231. MOZ_ASSERT(trc_->contextIndex_ == CallbackTracer::InvalidIndex);
  232. trc_->contextIndex_ = initial;
  233. }
  234. }
  235. ~AutoTracingIndex() {
  236. if (trc_) {
  237. MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex);
  238. trc_->contextIndex_ = CallbackTracer::InvalidIndex;
  239. }
  240. }
  241. void operator++() {
  242. if (trc_) {
  243. MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex);
  244. ++trc_->contextIndex_;
  245. }
  246. }
  247. };
  248. // Set a context callback for the trace callback to use, if it needs a detailed
  249. // edge description.
  250. class MOZ_RAII AutoTracingDetails
  251. {
  252. CallbackTracer* trc_;
  253. public:
  254. AutoTracingDetails(JSTracer* trc, CallbackTracer::ContextFunctor& func) : trc_(nullptr) {
  255. if (trc->isCallbackTracer()) {
  256. trc_ = trc->asCallbackTracer();
  257. MOZ_ASSERT(trc_->contextFunctor_ == nullptr);
  258. trc_->contextFunctor_ = &func;
  259. }
  260. }
  261. ~AutoTracingDetails() {
  262. if (trc_) {
  263. MOZ_ASSERT(trc_->contextFunctor_);
  264. trc_->contextFunctor_ = nullptr;
  265. }
  266. }
  267. };
  268. } // namespace JS
  269. JS::CallbackTracer*
  270. JSTracer::asCallbackTracer()
  271. {
  272. MOZ_ASSERT(isCallbackTracer());
  273. return static_cast<JS::CallbackTracer*>(this);
  274. }
  275. namespace JS {
  276. // The JS::TraceEdge family of functions traces the given GC thing reference.
  277. // This performs the tracing action configured on the given JSTracer: typically
  278. // calling the JSTracer::callback or marking the thing as live.
  279. //
  280. // The argument to JS::TraceEdge is an in-out param: when the function returns,
  281. // the garbage collector might have moved the GC thing. In this case, the
  282. // reference passed to JS::TraceEdge will be updated to the thing's new
  283. // location. Callers of this method are responsible for updating any state that
  284. // is dependent on the object's address. For example, if the object's address
  285. // is used as a key in a hashtable, then the object must be removed and
  286. // re-inserted with the correct hash.
  287. //
  288. // Note that while |edgep| must never be null, it is fine for |*edgep| to be
  289. // nullptr.
  290. template <typename T>
  291. extern JS_PUBLIC_API(void)
  292. TraceEdge(JSTracer* trc, JS::Heap<T>* edgep, const char* name);
  293. extern JS_PUBLIC_API(void)
  294. TraceEdge(JSTracer* trc, JS::TenuredHeap<JSObject*>* edgep, const char* name);
  295. // Edges that are always traced as part of root marking do not require
  296. // incremental barriers. This function allows for marking non-barriered
  297. // pointers, but asserts that this happens during root marking.
  298. //
  299. // Note that while |edgep| must never be null, it is fine for |*edgep| to be
  300. // nullptr.
  301. template <typename T>
  302. extern JS_PUBLIC_API(void)
  303. UnsafeTraceRoot(JSTracer* trc, T* edgep, const char* name);
  304. extern JS_PUBLIC_API(void)
  305. TraceChildren(JSTracer* trc, GCCellPtr thing);
  306. using ZoneSet = js::HashSet<Zone*, js::DefaultHasher<Zone*>, js::SystemAllocPolicy>;
  307. using CompartmentSet = js::HashSet<JSCompartment*, js::DefaultHasher<JSCompartment*>,
  308. js::SystemAllocPolicy>;
  309. /**
  310. * Trace every value within |compartments| that is wrapped by a
  311. * cross-compartment wrapper from a compartment that is not an element of
  312. * |compartments|.
  313. */
  314. extern JS_PUBLIC_API(void)
  315. TraceIncomingCCWs(JSTracer* trc, const JS::CompartmentSet& compartments);
  316. } // namespace JS
  317. extern JS_PUBLIC_API(void)
  318. JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc,
  319. void* thing, JS::TraceKind kind, bool includeDetails);
  320. namespace js {
  321. // Trace an edge that is not a GC root and is not wrapped in a barriered
  322. // wrapper for some reason.
  323. //
  324. // This method does not check if |*edgep| is non-null before tracing through
  325. // it, so callers must check any nullable pointer before calling this method.
  326. template <typename T>
  327. extern JS_PUBLIC_API(void)
  328. UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, T* edgep, const char* name);
  329. namespace gc {
  330. // Return true if the given edge is not live and is about to be swept.
  331. template <typename T>
  332. extern JS_PUBLIC_API(bool)
  333. EdgeNeedsSweep(JS::Heap<T>* edgep);
  334. // Not part of the public API, but declared here so we can use it in GCPolicy
  335. // which is.
  336. template <typename T>
  337. bool
  338. IsAboutToBeFinalizedUnbarriered(T* thingp);
  339. } // namespace gc
  340. } // namespace js
  341. #endif /* js_TracingAPI_h */