LCOV - code coverage report
Current view: top level - js/public - TracingAPI.h (source / functions) Hit Total Coverage
Test: output.info Lines: 81 111 73.0 %
Date: 2017-07-14 16:53:18 Functions: 32 53 60.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13