TracingAPI.h 15 KB

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