LCOV - code coverage report
Current view: top level - js/public - UbiNode.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 196 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 169 0.0 %
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_UbiNode_h
       8             : #define js_UbiNode_h
       9             : 
      10             : #include "mozilla/Alignment.h"
      11             : #include "mozilla/Assertions.h"
      12             : #include "mozilla/Attributes.h"
      13             : #include "mozilla/Maybe.h"
      14             : #include "mozilla/MemoryReporting.h"
      15             : #include "mozilla/Move.h"
      16             : #include "mozilla/RangedPtr.h"
      17             : #include "mozilla/TypeTraits.h"
      18             : #include "mozilla/Variant.h"
      19             : 
      20             : #include "jspubtd.h"
      21             : 
      22             : #include "js/GCAPI.h"
      23             : #include "js/HashTable.h"
      24             : #include "js/RootingAPI.h"
      25             : #include "js/TracingAPI.h"
      26             : #include "js/TypeDecls.h"
      27             : #include "js/UniquePtr.h"
      28             : #include "js/Value.h"
      29             : #include "js/Vector.h"
      30             : 
      31             : // JS::ubi::Node
      32             : //
      33             : // JS::ubi::Node is a pointer-like type designed for internal use by heap
      34             : // analysis tools. A ubi::Node can refer to:
      35             : //
      36             : // - a JS value, like a string, object, or symbol;
      37             : // - an internal SpiderMonkey structure, like a shape or a scope chain object
      38             : // - an instance of some embedding-provided type: in Firefox, an XPCOM
      39             : //   object, or an internal DOM node class instance
      40             : //
      41             : // A ubi::Node instance provides metadata about its referent, and can
      42             : // enumerate its referent's outgoing edges, so you can implement heap analysis
      43             : // algorithms that walk the graph - finding paths between objects, or
      44             : // computing heap dominator trees, say - using ubi::Node, while remaining
      45             : // ignorant of the details of the types you're operating on.
      46             : //
      47             : // Of course, when it comes to presenting the results in a developer-facing
      48             : // tool, you'll need to stop being ignorant of those details, because you have
      49             : // to discuss the ubi::Nodes' referents with the developer. Here, ubi::Node
      50             : // can hand you dynamically checked, properly typed pointers to the original
      51             : // objects via the as<T> method, or generate descriptions of the referent
      52             : // itself.
      53             : //
      54             : // ubi::Node instances are lightweight (two-word) value types. Instances:
      55             : // - compare equal if and only if they refer to the same object;
      56             : // - have hash values that respect their equality relation; and
      57             : // - have serializations that are only equal if the ubi::Nodes are equal.
      58             : //
      59             : // A ubi::Node is only valid for as long as its referent is alive; if its
      60             : // referent goes away, the ubi::Node becomes a dangling pointer. A ubi::Node
      61             : // that refers to a GC-managed object is not automatically a GC root; if the
      62             : // GC frees or relocates its referent, the ubi::Node becomes invalid. A
      63             : // ubi::Node that refers to a reference-counted object does not bump the
      64             : // reference count.
      65             : //
      66             : // ubi::Node values require no supporting data structures, making them
      67             : // feasible for use in memory-constrained devices --- ideally, the memory
      68             : // requirements of the algorithm which uses them will be the limiting factor,
      69             : // not the demands of ubi::Node itself.
      70             : //
      71             : // One can construct a ubi::Node value given a pointer to a type that ubi::Node
      72             : // supports. In the other direction, one can convert a ubi::Node back to a
      73             : // pointer; these downcasts are checked dynamically. In particular, one can
      74             : // convert a 'JSContext*' to a ubi::Node, yielding a node with an outgoing edge
      75             : // for every root registered with the runtime; starting from this, one can walk
      76             : // the entire heap. (Of course, one could also start traversal at any other kind
      77             : // of type to which one has a pointer.)
      78             : //
      79             : //
      80             : // Extending ubi::Node To Handle Your Embedding's Types
      81             : //
      82             : // To add support for a new ubi::Node referent type R, you must define a
      83             : // specialization of the ubi::Concrete template, ubi::Concrete<R>, which
      84             : // inherits from ubi::Base. ubi::Node itself uses the specialization for
      85             : // compile-time information (i.e. the checked conversions between R * and
      86             : // ubi::Node), and the inheritance for run-time dispatching.
      87             : //
      88             : //
      89             : // ubi::Node Exposes Implementation Details
      90             : //
      91             : // In many cases, a JavaScript developer's view of their data differs
      92             : // substantially from its actual implementation. For example, while the
      93             : // ECMAScript specification describes objects as maps from property names to
      94             : // sets of attributes (like ECMAScript's [[Value]]), in practice many objects
      95             : // have only a pointer to a shape, shared with other similar objects, and
      96             : // indexed slots that contain the [[Value]] attributes. As another example, a
      97             : // string produced by concatenating two other strings may sometimes be
      98             : // represented by a "rope", a structure that points to the two original
      99             : // strings.
     100             : //
     101             : // We intend to use ubi::Node to write tools that report memory usage, so it's
     102             : // important that ubi::Node accurately portray how much memory nodes consume.
     103             : // Thus, for example, when data that apparently belongs to multiple nodes is
     104             : // in fact shared in a common structure, ubi::Node's graph uses a separate
     105             : // node for that shared structure, and presents edges to it from the data's
     106             : // apparent owners. For example, ubi::Node exposes SpiderMonkey objects'
     107             : // shapes and base shapes, and exposes rope string and substring structure,
     108             : // because these optimizations become visible when a tool reports how much
     109             : // memory a structure consumes.
     110             : //
     111             : // However, fine granularity is not a goal. When a particular object is the
     112             : // exclusive owner of a separate block of memory, ubi::Node may present the
     113             : // object and its block as a single node, and add their sizes together when
     114             : // reporting the node's size, as there is no meaningful loss of data in this
     115             : // case. Thus, for example, a ubi::Node referring to a JavaScript object, when
     116             : // asked for the object's size in bytes, includes the object's slot and
     117             : // element arrays' sizes in the total. There is no separate ubi::Node value
     118             : // representing the slot and element arrays, since they are owned exclusively
     119             : // by the object.
     120             : //
     121             : //
     122             : // Presenting Analysis Results To JavaScript Developers
     123             : //
     124             : // If an analysis provides its results in terms of ubi::Node values, a user
     125             : // interface presenting those results will generally need to clean them up
     126             : // before they can be understood by JavaScript developers. For example,
     127             : // JavaScript developers should not need to understand shapes, only JavaScript
     128             : // objects. Similarly, they should not need to understand the distinction
     129             : // between DOM nodes and the JavaScript shadow objects that represent them.
     130             : //
     131             : //
     132             : // Rooting Restrictions
     133             : //
     134             : // At present there is no way to root ubi::Node instances, so instances can't be
     135             : // live across any operation that might GC. Analyses using ubi::Node must either
     136             : // run to completion and convert their results to some other rootable type, or
     137             : // save their intermediate state in some rooted structure if they must GC before
     138             : // they complete. (For algorithms like path-finding and dominator tree
     139             : // computation, we implement the algorithm avoiding any operation that could
     140             : // cause a GC --- and use AutoCheckCannotGC to verify this.)
     141             : //
     142             : // If this restriction prevents us from implementing interesting tools, we may
     143             : // teach the GC how to root ubi::Nodes, fix up hash tables that use them as
     144             : // keys, etc.
     145             : //
     146             : //
     147             : // Hostile Graph Structure
     148             : //
     149             : // Analyses consuming ubi::Node graphs must be robust when presented with graphs
     150             : // that are deliberately constructed to exploit their weaknesses. When operating
     151             : // on live graphs, web content has control over the object graph, and less
     152             : // direct control over shape and string structure, and analyses should be
     153             : // prepared to handle extreme cases gracefully. For example, if an analysis were
     154             : // to use the C++ stack in a depth-first traversal, carefully constructed
     155             : // content could cause the analysis to overflow the stack.
     156             : //
     157             : // When ubi::Nodes refer to nodes deserialized from a heap snapshot, analyses
     158             : // must be even more careful: since snapshots often come from potentially
     159             : // compromised e10s content processes, even properties normally guaranteed by
     160             : // the platform (the proper linking of DOM nodes, for example) might be
     161             : // corrupted. While it is the deserializer's responsibility to check the basic
     162             : // structure of the snapshot file, the analyses should be prepared for ubi::Node
     163             : // graphs constructed from snapshots to be even more bizarre.
     164             : 
     165             : class JSAtom;
     166             : 
     167             : namespace JS {
     168             : namespace ubi {
     169             : 
     170             : class Edge;
     171             : class EdgeRange;
     172             : class StackFrame;
     173             : 
     174             : } // namespace ubi
     175             : } // namespace JS
     176             : 
     177             : namespace JS {
     178             : namespace ubi {
     179             : 
     180             : using mozilla::Forward;
     181             : using mozilla::Maybe;
     182             : using mozilla::Move;
     183             : using mozilla::RangedPtr;
     184             : using mozilla::Variant;
     185             : 
     186             : template <typename T>
     187             : using Vector = mozilla::Vector<T, 0, js::SystemAllocPolicy>;
     188             : 
     189             : /*** ubi::StackFrame ******************************************************************************/
     190             : 
     191             : // Concrete JS::ubi::StackFrame instances backed by a live SavedFrame object
     192             : // store their strings as JSAtom*, while deserialized stack frames from offline
     193             : // heap snapshots store their strings as const char16_t*. In order to provide
     194             : // zero-cost accessors to these strings in a single interface that works with
     195             : // both cases, we use this variant type.
     196           0 : class JS_PUBLIC_API(AtomOrTwoByteChars) : public Variant<JSAtom*, const char16_t*> {
     197             :     using Base = Variant<JSAtom*, const char16_t*>;
     198             : 
     199             :   public:
     200             :     template<typename T>
     201           0 :     MOZ_IMPLICIT AtomOrTwoByteChars(T&& rhs) : Base(Forward<T>(rhs)) { }
     202             : 
     203             :     template<typename T>
     204             :     AtomOrTwoByteChars& operator=(T&& rhs) {
     205             :         MOZ_ASSERT(this != &rhs, "self-move disallowed");
     206             :         this->~AtomOrTwoByteChars();
     207             :         new (this) AtomOrTwoByteChars(Forward<T>(rhs));
     208             :         return *this;
     209             :     }
     210             : 
     211             :     // Return the length of the given AtomOrTwoByteChars string.
     212             :     size_t length();
     213             : 
     214             :     // Copy the given AtomOrTwoByteChars string into the destination buffer,
     215             :     // inflating if necessary. Does NOT null terminate. Returns the number of
     216             :     // characters written to destination.
     217             :     size_t copyToBuffer(RangedPtr<char16_t> destination, size_t length);
     218             : };
     219             : 
     220             : // The base class implemented by each ConcreteStackFrame<T> type. Subclasses
     221             : // must not add data members to this class.
     222             : class BaseStackFrame {
     223             :     friend class StackFrame;
     224             : 
     225             :     BaseStackFrame(const StackFrame&) = delete;
     226             :     BaseStackFrame& operator=(const StackFrame&) = delete;
     227             : 
     228             :   protected:
     229             :     void* ptr;
     230           0 :     explicit BaseStackFrame(void* ptr) : ptr(ptr) { }
     231             : 
     232             :   public:
     233             :     // This is a value type that should not have a virtual destructor. Don't add
     234             :     // destructors in subclasses!
     235             : 
     236             :     // Get a unique identifier for this StackFrame. The identifier is not valid
     237             :     // across garbage collections.
     238           0 :     virtual uint64_t identifier() const { return uint64_t(uintptr_t(ptr)); }
     239             : 
     240             :     // Get this frame's parent frame.
     241             :     virtual StackFrame parent() const = 0;
     242             : 
     243             :     // Get this frame's line number.
     244             :     virtual uint32_t line() const = 0;
     245             : 
     246             :     // Get this frame's column number.
     247             :     virtual uint32_t column() const = 0;
     248             : 
     249             :     // Get this frame's source name. Never null.
     250             :     virtual AtomOrTwoByteChars source() const = 0;
     251             : 
     252             :     // Return this frame's function name if named, otherwise the inferred
     253             :     // display name. Can be null.
     254             :     virtual AtomOrTwoByteChars functionDisplayName() const = 0;
     255             : 
     256             :     // Returns true if this frame's function is system JavaScript running with
     257             :     // trusted principals, false otherwise.
     258             :     virtual bool isSystem() const = 0;
     259             : 
     260             :     // Return true if this frame's function is a self-hosted JavaScript builtin,
     261             :     // false otherwise.
     262             :     virtual bool isSelfHosted(JSContext* cx) const = 0;
     263             : 
     264             :     // Construct a SavedFrame stack for the stack starting with this frame and
     265             :     // containing all of its parents. The SavedFrame objects will be placed into
     266             :     // cx's current compartment.
     267             :     //
     268             :     // Note that the process of
     269             :     //
     270             :     //     SavedFrame
     271             :     //         |
     272             :     //         V
     273             :     //     JS::ubi::StackFrame
     274             :     //         |
     275             :     //         V
     276             :     //     offline heap snapshot
     277             :     //         |
     278             :     //         V
     279             :     //     JS::ubi::StackFrame
     280             :     //         |
     281             :     //         V
     282             :     //     SavedFrame
     283             :     //
     284             :     // is lossy because we cannot serialize and deserialize the SavedFrame's
     285             :     // principals in the offline heap snapshot, so JS::ubi::StackFrame
     286             :     // simplifies the principals check into the boolean isSystem() state. This
     287             :     // is fine because we only expose JS::ubi::Stack to devtools and chrome
     288             :     // code, and not to the web platform.
     289             :     virtual MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx,
     290             :                                                        MutableHandleObject outSavedFrameStack)
     291             :         const = 0;
     292             : 
     293             :     // Trace the concrete implementation of JS::ubi::StackFrame.
     294             :     virtual void trace(JSTracer* trc) = 0;
     295             : };
     296             : 
     297             : // A traits template with a specialization for each backing type that implements
     298             : // the ubi::BaseStackFrame interface. Each specialization must be the a subclass
     299             : // of ubi::BaseStackFrame.
     300             : template<typename T> class ConcreteStackFrame;
     301             : 
     302             : // A JS::ubi::StackFrame represents a frame in a recorded stack. It can be
     303             : // backed either by a live SavedFrame object or by a structure deserialized from
     304             : // an offline heap snapshot.
     305             : //
     306             : // It is a value type that may be memcpy'd hither and thither without worrying
     307             : // about constructors or destructors, similar to POD types.
     308             : //
     309             : // Its lifetime is the same as the lifetime of the graph that is being analyzed
     310             : // by the JS::ubi::Node that the JS::ubi::StackFrame came from. That is, if the
     311             : // graph being analyzed is the live heap graph, the JS::ubi::StackFrame is only
     312             : // valid within the scope of an AutoCheckCannotGC; if the graph being analyzed
     313             : // is an offline heap snapshot, the JS::ubi::StackFrame is valid as long as the
     314             : // offline heap snapshot is alive.
     315             : class StackFrame {
     316             :     // Storage in which we allocate BaseStackFrame subclasses.
     317             :     mozilla::AlignedStorage2<BaseStackFrame> storage;
     318             : 
     319           0 :     BaseStackFrame* base() { return storage.addr(); }
     320           0 :     const BaseStackFrame* base() const { return storage.addr(); }
     321             : 
     322             :     template<typename T>
     323           0 :     void construct(T* ptr) {
     324             :         static_assert(mozilla::IsBaseOf<BaseStackFrame, ConcreteStackFrame<T>>::value,
     325             :                       "ConcreteStackFrame<T> must inherit from BaseStackFrame");
     326             :         static_assert(sizeof(ConcreteStackFrame<T>) == sizeof(*base()),
     327             :                       "ubi::ConcreteStackFrame<T> specializations must be the same size as "
     328             :                       "ubi::BaseStackFrame");
     329           0 :         ConcreteStackFrame<T>::construct(base(), ptr);
     330           0 :     }
     331             :     struct ConstructFunctor;
     332             : 
     333             :   public:
     334           0 :     StackFrame() { construct<void>(nullptr); }
     335             : 
     336             :     template<typename T>
     337           0 :     MOZ_IMPLICIT StackFrame(T* ptr) {
     338           0 :         construct(ptr);
     339           0 :     }
     340             : 
     341             :     template<typename T>
     342             :     StackFrame& operator=(T* ptr) {
     343             :         construct(ptr);
     344             :         return *this;
     345             :     }
     346             : 
     347             :     // Constructors accepting SpiderMonkey's generic-pointer-ish types.
     348             : 
     349             :     template<typename T>
     350             :     explicit StackFrame(const JS::Handle<T*>& handle) {
     351             :         construct(handle.get());
     352             :     }
     353             : 
     354             :     template<typename T>
     355             :     StackFrame& operator=(const JS::Handle<T*>& handle) {
     356             :         construct(handle.get());
     357             :         return *this;
     358             :     }
     359             : 
     360             :     template<typename T>
     361             :     explicit StackFrame(const JS::Rooted<T*>& root) {
     362             :         construct(root.get());
     363             :     }
     364             : 
     365             :     template<typename T>
     366             :     StackFrame& operator=(const JS::Rooted<T*>& root) {
     367             :         construct(root.get());
     368             :         return *this;
     369             :     }
     370             : 
     371             :     // Because StackFrame is just a vtable pointer and an instance pointer, we
     372             :     // can memcpy everything around instead of making concrete classes define
     373             :     // virtual constructors. See the comment above Node's copy constructor for
     374             :     // more details; that comment applies here as well.
     375           0 :     StackFrame(const StackFrame& rhs) {
     376           0 :         memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u));
     377           0 :     }
     378             : 
     379           0 :     StackFrame& operator=(const StackFrame& rhs) {
     380           0 :         memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u));
     381           0 :         return *this;
     382             :     }
     383             : 
     384           0 :     bool operator==(const StackFrame& rhs) const { return base()->ptr == rhs.base()->ptr; }
     385             :     bool operator!=(const StackFrame& rhs) const { return !(*this == rhs); }
     386             : 
     387           0 :     explicit operator bool() const {
     388           0 :         return base()->ptr != nullptr;
     389             :     }
     390             : 
     391             :     // Copy this StackFrame's source name into the given |destination|
     392             :     // buffer. Copy no more than |length| characters. The result is *not* null
     393             :     // terminated. Returns how many characters were written into the buffer.
     394             :     size_t source(RangedPtr<char16_t> destination, size_t length) const;
     395             : 
     396             :     // Copy this StackFrame's function display name into the given |destination|
     397             :     // buffer. Copy no more than |length| characters. The result is *not* null
     398             :     // terminated. Returns how many characters were written into the buffer.
     399             :     size_t functionDisplayName(RangedPtr<char16_t> destination, size_t length) const;
     400             : 
     401             :     // Get the size of the respective strings. 0 is returned for null strings.
     402             :     size_t sourceLength();
     403             :     size_t functionDisplayNameLength();
     404             : 
     405             :     // Methods that forward to virtual calls through BaseStackFrame.
     406             : 
     407           0 :     void trace(JSTracer* trc) { base()->trace(trc); }
     408           0 :     uint64_t identifier() const {
     409           0 :         auto id = base()->identifier();
     410           0 :         MOZ_ASSERT(JS::Value::isNumberRepresentable(id));
     411           0 :         return id;
     412             :     }
     413           0 :     uint32_t line() const { return base()->line(); }
     414           0 :     uint32_t column() const { return base()->column(); }
     415           0 :     AtomOrTwoByteChars source() const { return base()->source(); }
     416           0 :     AtomOrTwoByteChars functionDisplayName() const { return base()->functionDisplayName(); }
     417           0 :     StackFrame parent() const { return base()->parent(); }
     418           0 :     bool isSystem() const { return base()->isSystem(); }
     419           0 :     bool isSelfHosted(JSContext* cx) const { return base()->isSelfHosted(cx); }
     420           0 :     MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx,
     421             :                                                MutableHandleObject outSavedFrameStack) const {
     422           0 :         return base()->constructSavedFrameStack(cx, outSavedFrameStack);
     423             :     }
     424             : 
     425             :     struct HashPolicy {
     426             :         using Lookup = JS::ubi::StackFrame;
     427             : 
     428           0 :         static js::HashNumber hash(const Lookup& lookup) {
     429           0 :             return lookup.identifier();
     430             :         }
     431             : 
     432           0 :         static bool match(const StackFrame& key, const Lookup& lookup) {
     433           0 :             return key == lookup;
     434             :         }
     435             : 
     436             :         static void rekey(StackFrame& k, const StackFrame& newKey) {
     437             :             k = newKey;
     438             :         }
     439             :     };
     440             : };
     441             : 
     442             : // The ubi::StackFrame null pointer. Any attempt to operate on a null
     443             : // ubi::StackFrame crashes.
     444             : template<>
     445             : class ConcreteStackFrame<void> : public BaseStackFrame {
     446           0 :     explicit ConcreteStackFrame(void* ptr) : BaseStackFrame(ptr) { }
     447             : 
     448             :   public:
     449           0 :     static void construct(void* storage, void*) { new (storage) ConcreteStackFrame(nullptr); }
     450             : 
     451           0 :     uint64_t identifier() const override { return 0; }
     452           0 :     void trace(JSTracer* trc) override { }
     453           0 :     MOZ_MUST_USE bool constructSavedFrameStack(JSContext* cx, MutableHandleObject out)
     454             :         const override
     455             :     {
     456           0 :         out.set(nullptr);
     457           0 :         return true;
     458             :     }
     459             : 
     460           0 :     uint32_t line() const override { MOZ_CRASH("null JS::ubi::StackFrame"); }
     461           0 :     uint32_t column() const override { MOZ_CRASH("null JS::ubi::StackFrame"); }
     462           0 :     AtomOrTwoByteChars source() const override { MOZ_CRASH("null JS::ubi::StackFrame"); }
     463           0 :     AtomOrTwoByteChars functionDisplayName() const override { MOZ_CRASH("null JS::ubi::StackFrame"); }
     464           0 :     StackFrame parent() const override { MOZ_CRASH("null JS::ubi::StackFrame"); }
     465           0 :     bool isSystem() const override { MOZ_CRASH("null JS::ubi::StackFrame"); }
     466           0 :     bool isSelfHosted(JSContext* cx) const override { MOZ_CRASH("null JS::ubi::StackFrame"); }
     467             : };
     468             : 
     469             : MOZ_MUST_USE JS_PUBLIC_API(bool)
     470             : ConstructSavedFrameStackSlow(JSContext* cx,
     471             :                              JS::ubi::StackFrame& frame,
     472             :                              MutableHandleObject outSavedFrameStack);
     473             : 
     474             : 
     475             : /*** ubi::Node ************************************************************************************/
     476             : 
     477             : // A concrete node specialization can claim its referent is a member of a
     478             : // particular "coarse type" which is less specific than the actual
     479             : // implementation type but generally more palatable for web developers. For
     480             : // example, JitCode can be considered to have a coarse type of "Script". This is
     481             : // used by some analyses for putting nodes into different buckets. The default,
     482             : // if a concrete specialization does not provide its own mapping to a CoarseType
     483             : // variant, is "Other".
     484             : //
     485             : // NB: the values associated with a particular enum variant must not change or
     486             : // be reused for new variants. Doing so will cause inspecting ubi::Nodes backed
     487             : // by an offline heap snapshot from an older SpiderMonkey/Firefox version to
     488             : // break. Consider this enum append only.
     489             : enum class CoarseType: uint32_t {
     490             :     Other  = 0,
     491             :     Object = 1,
     492             :     Script = 2,
     493             :     String = 3,
     494             : 
     495             :     FIRST  = Other,
     496             :     LAST   = String
     497             : };
     498             : 
     499             : inline uint32_t
     500           0 : CoarseTypeToUint32(CoarseType type)
     501             : {
     502           0 :     return static_cast<uint32_t>(type);
     503             : }
     504             : 
     505             : inline bool
     506           0 : Uint32IsValidCoarseType(uint32_t n)
     507             : {
     508           0 :     auto first = static_cast<uint32_t>(CoarseType::FIRST);
     509           0 :     auto last = static_cast<uint32_t>(CoarseType::LAST);
     510           0 :     MOZ_ASSERT(first < last);
     511           0 :     return first <= n && n <= last;
     512             : }
     513             : 
     514             : inline CoarseType
     515           0 : Uint32ToCoarseType(uint32_t n)
     516             : {
     517           0 :     MOZ_ASSERT(Uint32IsValidCoarseType(n));
     518           0 :     return static_cast<CoarseType>(n);
     519             : }
     520             : 
     521             : // The base class implemented by each ubi::Node referent type. Subclasses must
     522             : // not add data members to this class.
     523             : class JS_PUBLIC_API(Base) {
     524             :     friend class Node;
     525             : 
     526             :     // For performance's sake, we'd prefer to avoid a virtual destructor; and
     527             :     // an empty constructor seems consistent with the 'lightweight value type'
     528             :     // visible behavior we're trying to achieve. But if the destructor isn't
     529             :     // virtual, and a subclass overrides it, the subclass's destructor will be
     530             :     // ignored. Is there a way to make the compiler catch that error?
     531             : 
     532             :   protected:
     533             :     // Space for the actual pointer. Concrete subclasses should define a
     534             :     // properly typed 'get' member function to access this.
     535             :     void* ptr;
     536             : 
     537           0 :     explicit Base(void* ptr) : ptr(ptr) { }
     538             : 
     539             :   public:
     540           0 :     bool operator==(const Base& rhs) const {
     541             :         // Some compilers will indeed place objects of different types at
     542             :         // the same address, so technically, we should include the vtable
     543             :         // in this comparison. But it seems unlikely to cause problems in
     544             :         // practice.
     545           0 :         return ptr == rhs.ptr;
     546             :     }
     547           0 :     bool operator!=(const Base& rhs) const { return !(*this == rhs); }
     548             : 
     549             :     // An identifier for this node, guaranteed to be stable and unique for as
     550             :     // long as this ubi::Node's referent is alive and at the same address.
     551             :     //
     552             :     // This is probably suitable for use in serializations, as it is an integral
     553             :     // type. It may also help save memory when constructing HashSets of
     554             :     // ubi::Nodes: since a uint64_t will always be smaller-or-equal-to the size
     555             :     // of a ubi::Node, a HashSet<ubi::Node::Id> may use less space per element
     556             :     // than a HashSet<ubi::Node>.
     557             :     //
     558             :     // (Note that 'unique' only means 'up to equality on ubi::Node'; see the
     559             :     // caveats about multiple objects allocated at the same address for
     560             :     // 'ubi::Node::operator=='.)
     561             :     using Id = uint64_t;
     562           0 :     virtual Id identifier() const { return Id(uintptr_t(ptr)); }
     563             : 
     564             :     // Returns true if this node is pointing to something on the live heap, as
     565             :     // opposed to something from a deserialized core dump. Returns false,
     566             :     // otherwise.
     567           0 :     virtual bool isLive() const { return true; };
     568             : 
     569             :     // Return the coarse-grained type-of-thing that this node represents.
     570           0 :     virtual CoarseType coarseType() const { return CoarseType::Other; }
     571             : 
     572             :     // Return a human-readable name for the referent's type. The result should
     573             :     // be statically allocated. (You can use u"strings" for this.)
     574             :     //
     575             :     // This must always return Concrete<T>::concreteTypeName; we use that
     576             :     // pointer as a tag for this particular referent type.
     577             :     virtual const char16_t* typeName() const = 0;
     578             : 
     579             :     // Return the size of this node, in bytes. Include any structures that this
     580             :     // node owns exclusively that are not exposed as their own ubi::Nodes.
     581             :     // |mallocSizeOf| should be a malloc block sizing function; see
     582             :     // |mfbt/MemoryReporting.h|.
     583             :     //
     584             :     // Because we can use |JS::ubi::Node|s backed by a snapshot that was taken
     585             :     // on a 64-bit platform when we are currently on a 32-bit platform, we
     586             :     // cannot rely on |size_t| for node sizes. Instead, |Size| is uint64_t on
     587             :     // all platforms.
     588             :     using Size = uint64_t;
     589           0 :     virtual Size size(mozilla::MallocSizeOf mallocSizeof) const { return 1; }
     590             : 
     591             :     // Return an EdgeRange that initially contains all the referent's outgoing
     592             :     // edges. The caller takes ownership of the EdgeRange.
     593             :     //
     594             :     // If wantNames is true, compute names for edges. Doing so can be expensive
     595             :     // in time and memory.
     596             :     virtual js::UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames) const = 0;
     597             : 
     598             :     // Return the Zone to which this node's referent belongs, or nullptr if the
     599             :     // referent is not of a type allocated in SpiderMonkey Zones.
     600           0 :     virtual JS::Zone* zone() const { return nullptr; }
     601             : 
     602             :     // Return the compartment for this node. Some ubi::Node referents are not
     603             :     // associated with JSCompartments, such as JSStrings (which are associated
     604             :     // with Zones). When the referent is not associated with a compartment,
     605             :     // nullptr is returned.
     606           0 :     virtual JSCompartment* compartment() const { return nullptr; }
     607             : 
     608             :     // Return whether this node's referent's allocation stack was captured.
     609           0 :     virtual bool hasAllocationStack() const { return false; }
     610             : 
     611             :     // Get the stack recorded at the time this node's referent was
     612             :     // allocated. This must only be called when hasAllocationStack() is true.
     613           0 :     virtual StackFrame allocationStack() const {
     614           0 :         MOZ_CRASH("Concrete classes that have an allocation stack must override both "
     615             :                   "hasAllocationStack and allocationStack.");
     616             :     }
     617             : 
     618             :     // Methods for JSObject Referents
     619             :     //
     620             :     // These methods are only semantically valid if the referent is either a
     621             :     // JSObject in the live heap, or represents a previously existing JSObject
     622             :     // from some deserialized heap snapshot.
     623             : 
     624             :     // Return the object's [[Class]]'s name.
     625           0 :     virtual const char* jsObjectClassName() const { return nullptr; }
     626             : 
     627             :     // If this object was constructed with `new` and we have the data available,
     628             :     // place the contructor function's display name in the out parameter.
     629             :     // Otherwise, place nullptr in the out parameter. Caller maintains ownership
     630             :     // of the out parameter. True is returned on success, false is returned on
     631             :     // OOM.
     632           0 :     virtual MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName)
     633             :         const
     634             :     {
     635           0 :         outName.reset(nullptr);
     636           0 :         return true;
     637             :     }
     638             : 
     639             :     // Methods for CoarseType::Script referents
     640             : 
     641             :     // Return the script's source's filename if available. If unavailable,
     642             :     // return nullptr.
     643           0 :     virtual const char* scriptFilename() const { return nullptr; }
     644             : 
     645             :   private:
     646             :     Base(const Base& rhs) = delete;
     647             :     Base& operator=(const Base& rhs) = delete;
     648             : };
     649             : 
     650             : // A traits template with a specialization for each referent type that
     651             : // ubi::Node supports. The specialization must be the concrete subclass of Base
     652             : // that represents a pointer to the referent type. It must include these
     653             : // members:
     654             : //
     655             : //    // The specific char16_t array returned by Concrete<T>::typeName().
     656             : //    static const char16_t concreteTypeName[];
     657             : //
     658             : //    // Construct an instance of this concrete class in |storage| referring
     659             : //    // to |referent|. Implementations typically use a placement 'new'.
     660             : //    //
     661             : //    // In some cases, |referent| will contain dynamic type information that
     662             : //    // identifies it a some more specific subclass of |Referent|. For
     663             : //    // example, when |Referent| is |JSObject|, then |referent->getClass()|
     664             : //    // could tell us that it's actually a JSFunction. Similarly, if
     665             : //    // |Referent| is |nsISupports|, we would like a ubi::Node that knows its
     666             : //    // final implementation type.
     667             : //    //
     668             : //    // So we delegate the actual construction to this specialization, which
     669             : //    // knows Referent's details.
     670             : //    static void construct(void* storage, Referent* referent);
     671             : template<typename Referent>
     672             : class Concrete;
     673             : 
     674             : // A container for a Base instance; all members simply forward to the contained
     675             : // instance.  This container allows us to pass ubi::Node instances by value.
     676             : class Node {
     677             :     // Storage in which we allocate Base subclasses.
     678             :     mozilla::AlignedStorage2<Base> storage;
     679           0 :     Base* base() { return storage.addr(); }
     680           0 :     const Base* base() const { return storage.addr(); }
     681             : 
     682             :     template<typename T>
     683           0 :     void construct(T* ptr) {
     684             :         static_assert(sizeof(Concrete<T>) == sizeof(*base()),
     685             :                       "ubi::Base specializations must be the same size as ubi::Base");
     686             :         static_assert(mozilla::IsBaseOf<Base, Concrete<T>>::value,
     687             :                       "ubi::Concrete<T> must inherit from ubi::Base");
     688           0 :         Concrete<T>::construct(base(), ptr);
     689           0 :     }
     690             :     struct ConstructFunctor;
     691             : 
     692             :   public:
     693           0 :     Node() { construct<void>(nullptr); }
     694             : 
     695             :     template<typename T>
     696           0 :     MOZ_IMPLICIT Node(T* ptr) {
     697           0 :         construct(ptr);
     698           0 :     }
     699             :     template<typename T>
     700             :     Node& operator=(T* ptr) {
     701             :         construct(ptr);
     702             :         return *this;
     703             :     }
     704             : 
     705             :     // We can construct and assign from rooted forms of pointers.
     706             :     template<typename T>
     707           0 :     MOZ_IMPLICIT Node(const Rooted<T*>& root) {
     708           0 :         construct(root.get());
     709           0 :     }
     710             :     template<typename T>
     711             :     Node& operator=(const Rooted<T*>& root) {
     712             :         construct(root.get());
     713             :         return *this;
     714             :     }
     715             : 
     716             :     // Constructors accepting SpiderMonkey's other generic-pointer-ish types.
     717             :     // Note that we *do* want an implicit constructor here: JS::Value and
     718             :     // JS::ubi::Node are both essentially tagged references to other sorts of
     719             :     // objects, so letting conversions happen automatically is appropriate.
     720             :     MOZ_IMPLICIT Node(JS::HandleValue value);
     721             :     explicit Node(const JS::GCCellPtr& thing);
     722             : 
     723             :     // copy construction and copy assignment just use memcpy, since we know
     724             :     // instances contain nothing but a vtable pointer and a data pointer.
     725             :     //
     726             :     // To be completely correct, concrete classes could provide a virtual
     727             :     // 'construct' member function, which we could invoke on rhs to construct an
     728             :     // instance in our storage. But this is good enough; there's no need to jump
     729             :     // through vtables for copying and assignment that are just going to move
     730             :     // two words around. The compiler knows how to optimize memcpy.
     731           0 :     Node(const Node& rhs) {
     732           0 :         memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u));
     733           0 :     }
     734             : 
     735           0 :     Node& operator=(const Node& rhs) {
     736           0 :         memcpy(storage.u.mBytes, rhs.storage.u.mBytes, sizeof(storage.u));
     737           0 :         return *this;
     738             :     }
     739             : 
     740           0 :     bool operator==(const Node& rhs) const { return *base() == *rhs.base(); }
     741           0 :     bool operator!=(const Node& rhs) const { return *base() != *rhs.base(); }
     742             : 
     743           0 :     explicit operator bool() const {
     744           0 :         return base()->ptr != nullptr;
     745             :     }
     746             : 
     747           0 :     bool isLive() const { return base()->isLive(); }
     748             : 
     749             :     // Get the canonical type name for the given type T.
     750             :     template<typename T>
     751           0 :     static const char16_t* canonicalTypeName() { return Concrete<T>::concreteTypeName; }
     752             : 
     753             :     template<typename T>
     754           0 :     bool is() const {
     755           0 :         return base()->typeName() == canonicalTypeName<T>();
     756             :     }
     757             : 
     758             :     template<typename T>
     759           0 :     T* as() const {
     760           0 :         MOZ_ASSERT(isLive());
     761           0 :         MOZ_ASSERT(is<T>());
     762           0 :         return static_cast<T*>(base()->ptr);
     763             :     }
     764             : 
     765             :     template<typename T>
     766             :     T* asOrNull() const {
     767             :         MOZ_ASSERT(isLive());
     768             :         return is<T>() ? static_cast<T*>(base()->ptr) : nullptr;
     769             :     }
     770             : 
     771             :     // If this node refers to something that can be represented as a JavaScript
     772             :     // value that is safe to expose to JavaScript code, return that value.
     773             :     // Otherwise return UndefinedValue(). JSStrings, JS::Symbols, and some (but
     774             :     // not all!) JSObjects can be exposed.
     775             :     JS::Value exposeToJS() const;
     776             : 
     777           0 :     CoarseType coarseType()         const { return base()->coarseType(); }
     778           0 :     const char16_t* typeName()      const { return base()->typeName(); }
     779           0 :     JS::Zone* zone()                const { return base()->zone(); }
     780           0 :     JSCompartment* compartment()    const { return base()->compartment(); }
     781           0 :     const char* jsObjectClassName() const { return base()->jsObjectClassName(); }
     782             :     MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) const {
     783             :         return base()->jsObjectConstructorName(cx, outName);
     784             :     }
     785             : 
     786           0 :     const char* scriptFilename() const { return base()->scriptFilename(); }
     787             : 
     788             :     using Size = Base::Size;
     789           0 :     Size size(mozilla::MallocSizeOf mallocSizeof) const {
     790           0 :         auto size =  base()->size(mallocSizeof);
     791           0 :         MOZ_ASSERT(size > 0,
     792             :                    "C++ does not have zero-sized types! Choose 1 if you just need a "
     793             :                    "conservative default.");
     794           0 :         return size;
     795             :     }
     796             : 
     797           0 :     js::UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames = true) const {
     798           0 :         return base()->edges(cx, wantNames);
     799             :     }
     800             : 
     801           0 :     bool hasAllocationStack() const { return base()->hasAllocationStack(); }
     802           0 :     StackFrame allocationStack() const {
     803           0 :         return base()->allocationStack();
     804             :     }
     805             : 
     806             :     using Id = Base::Id;
     807           0 :     Id identifier() const {
     808           0 :         auto id = base()->identifier();
     809           0 :         MOZ_ASSERT(JS::Value::isNumberRepresentable(id));
     810           0 :         return id;
     811             :     }
     812             : 
     813             :     // A hash policy for ubi::Nodes.
     814             :     // This simply uses the stock PointerHasher on the ubi::Node's pointer.
     815             :     // We specialize DefaultHasher below to make this the default.
     816             :     class HashPolicy {
     817             :         typedef js::PointerHasher<void*, mozilla::tl::FloorLog2<sizeof(void*)>::value> PtrHash;
     818             : 
     819             :       public:
     820             :         typedef Node Lookup;
     821             : 
     822           0 :         static js::HashNumber hash(const Lookup& l) { return PtrHash::hash(l.base()->ptr); }
     823           0 :         static bool match(const Node& k, const Lookup& l) { return k == l; }
     824             :         static void rekey(Node& k, const Node& newKey) { k = newKey; }
     825             :     };
     826             : };
     827             : 
     828             : using NodeSet = js::HashSet<Node, js::DefaultHasher<Node>, js::SystemAllocPolicy>;
     829             : using NodeSetPtr = mozilla::UniquePtr<NodeSet, JS::DeletePolicy<NodeSet>>;
     830             : 
     831             : /*** Edge and EdgeRange ***************************************************************************/
     832             : 
     833             : using EdgeName = UniqueTwoByteChars;
     834             : 
     835             : // An outgoing edge to a referent node.
     836           0 : class Edge {
     837             :   public:
     838           0 :     Edge() : name(nullptr), referent() { }
     839             : 
     840             :     // Construct an initialized Edge, taking ownership of |name|.
     841           0 :     Edge(char16_t* name, const Node& referent)
     842           0 :         : name(name)
     843           0 :         , referent(referent)
     844           0 :     { }
     845             : 
     846             :     // Move construction and assignment.
     847           0 :     Edge(Edge&& rhs)
     848           0 :         : name(mozilla::Move(rhs.name))
     849           0 :         , referent(rhs.referent)
     850           0 :     { }
     851             : 
     852           0 :     Edge& operator=(Edge&& rhs) {
     853           0 :         MOZ_ASSERT(&rhs != this);
     854           0 :         this->~Edge();
     855           0 :         new (this) Edge(mozilla::Move(rhs));
     856           0 :         return *this;
     857             :     }
     858             : 
     859             :     Edge(const Edge&) = delete;
     860             :     Edge& operator=(const Edge&) = delete;
     861             : 
     862             :     // This edge's name. This may be nullptr, if Node::edges was called with
     863             :     // false as the wantNames parameter.
     864             :     //
     865             :     // The storage is owned by this Edge, and will be freed when this Edge is
     866             :     // destructed. You may take ownership of the name by `mozilla::Move`ing it
     867             :     // out of the edge; it is just a UniquePtr.
     868             :     //
     869             :     // (In real life we'll want a better representation for names, to avoid
     870             :     // creating tons of strings when the names follow a pattern; and we'll need
     871             :     // to think about lifetimes carefully to ensure traversal stays cheap.)
     872             :     EdgeName name;
     873             : 
     874             :     // This edge's referent.
     875             :     Node referent;
     876             : };
     877             : 
     878             : // EdgeRange is an abstract base class for iterating over a node's outgoing
     879             : // edges. (This is modeled after js::HashTable<K,V>::Range.)
     880             : //
     881             : // Concrete instances of this class need not be as lightweight as Node itself,
     882             : // since they're usually only instantiated while iterating over a particular
     883             : // object's edges. For example, a dumb implementation for JS Cells might use
     884             : // JS::TraceChildren to to get the outgoing edges, and then store them in an
     885             : // array internal to the EdgeRange.
     886             : class EdgeRange {
     887             :   protected:
     888             :     // The current front edge of this range, or nullptr if this range is empty.
     889             :     Edge* front_;
     890             : 
     891           0 :     EdgeRange() : front_(nullptr) { }
     892             : 
     893             :   public:
     894           0 :     virtual ~EdgeRange() { }
     895             : 
     896             :     // True if there are no more edges in this range.
     897           0 :     bool empty() const { return !front_; }
     898             : 
     899             :     // The front edge of this range. This is owned by the EdgeRange, and is
     900             :     // only guaranteed to live until the next call to popFront, or until
     901             :     // the EdgeRange is destructed.
     902             :     const Edge& front() const { return *front_; }
     903           0 :     Edge& front() { return *front_; }
     904             : 
     905             :     // Remove the front edge from this range. This should only be called if
     906             :     // !empty().
     907             :     virtual void popFront() = 0;
     908             : 
     909             :   private:
     910             :     EdgeRange(const EdgeRange&) = delete;
     911             :     EdgeRange& operator=(const EdgeRange&) = delete;
     912             : };
     913             : 
     914             : 
     915             : typedef mozilla::Vector<Edge, 8, js::SystemAllocPolicy> EdgeVector;
     916             : 
     917             : // An EdgeRange concrete class that holds a pre-existing vector of
     918             : // Edges. A PreComputedEdgeRange does not take ownership of its
     919             : // EdgeVector; it is up to the PreComputedEdgeRange's consumer to manage
     920             : // that lifetime.
     921           0 : class PreComputedEdgeRange : public EdgeRange {
     922             :     EdgeVector& edges;
     923             :     size_t      i;
     924             : 
     925           0 :     void settle() {
     926           0 :         front_ = i < edges.length() ? &edges[i] : nullptr;
     927           0 :     }
     928             : 
     929             :   public:
     930           0 :     explicit PreComputedEdgeRange(EdgeVector& edges)
     931           0 :       : edges(edges),
     932           0 :         i(0)
     933             :     {
     934           0 :         settle();
     935           0 :     }
     936             : 
     937           0 :     void popFront() override {
     938           0 :         MOZ_ASSERT(!empty());
     939           0 :         i++;
     940           0 :         settle();
     941           0 :     }
     942             : };
     943             : 
     944             : /*** RootList *************************************************************************************/
     945             : 
     946             : // RootList is a class that can be pointed to by a |ubi::Node|, creating a
     947             : // fictional root-of-roots which has edges to every GC root in the JS
     948             : // runtime. Having a single root |ubi::Node| is useful for algorithms written
     949             : // with the assumption that there aren't multiple roots (such as computing
     950             : // dominator trees) and you want a single point of entry. It also ensures that
     951             : // the roots themselves get visited by |ubi::BreadthFirst| (they would otherwise
     952             : // only be used as starting points).
     953             : //
     954             : // RootList::init itself causes a minor collection, but once the list of roots
     955             : // has been created, GC must not occur, as the referent ubi::Nodes are not
     956             : // stable across GC. The init calls emplace on |noGC|'s AutoCheckCannotGC, whose
     957             : // lifetime must extend at least as long as the RootList itself.
     958             : //
     959             : // Example usage:
     960             : //
     961             : //    {
     962             : //        mozilla::Maybe<JS::AutoCheckCannotGC> maybeNoGC;
     963             : //        JS::ubi::RootList rootList(cx, maybeNoGC);
     964             : //        if (!rootList.init())
     965             : //            return false;
     966             : //
     967             : //        // The AutoCheckCannotGC is guaranteed to exist if init returned true.
     968             : //        MOZ_ASSERT(maybeNoGC.isSome());
     969             : //
     970             : //        JS::ubi::Node root(&rootList);
     971             : //
     972             : //        ...
     973             : //    }
     974           0 : class MOZ_STACK_CLASS JS_PUBLIC_API(RootList) {
     975             :     Maybe<AutoCheckCannotGC>& noGC;
     976             : 
     977             :   public:
     978             :     JSContext* cx;
     979             :     EdgeVector edges;
     980             :     bool       wantNames;
     981             : 
     982             :     RootList(JSContext* cx, Maybe<AutoCheckCannotGC>& noGC, bool wantNames = false);
     983             : 
     984             :     // Find all GC roots.
     985             :     MOZ_MUST_USE bool init();
     986             :     // Find only GC roots in the provided set of |JSCompartment|s.
     987             :     MOZ_MUST_USE bool init(CompartmentSet& debuggees);
     988             :     // Find only GC roots in the given Debugger object's set of debuggee
     989             :     // compartments.
     990             :     MOZ_MUST_USE bool init(HandleObject debuggees);
     991             : 
     992             :     // Returns true if the RootList has been initialized successfully, false
     993             :     // otherwise.
     994           0 :     bool initialized() { return noGC.isSome(); }
     995             : 
     996             :     // Explicitly add the given Node as a root in this RootList. If wantNames is
     997             :     // true, you must pass an edgeName. The RootList does not take ownership of
     998             :     // edgeName.
     999             :     MOZ_MUST_USE bool addRoot(Node node, const char16_t* edgeName = nullptr);
    1000             : };
    1001             : 
    1002             : 
    1003             : /*** Concrete classes for ubi::Node referent types ************************************************/
    1004             : 
    1005             : template<>
    1006             : class JS_PUBLIC_API(Concrete<RootList>) : public Base {
    1007             :   protected:
    1008           0 :     explicit Concrete(RootList* ptr) : Base(ptr) { }
    1009           0 :     RootList& get() const { return *static_cast<RootList*>(ptr); }
    1010             : 
    1011             :   public:
    1012           0 :     static void construct(void* storage, RootList* ptr) { new (storage) Concrete(ptr); }
    1013             : 
    1014             :     js::UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames) const override;
    1015             : 
    1016           0 :     const char16_t* typeName() const override { return concreteTypeName; }
    1017             :     static const char16_t concreteTypeName[];
    1018             : };
    1019             : 
    1020             : // A reusable ubi::Concrete specialization base class for types supported by
    1021             : // JS::TraceChildren.
    1022             : template<typename Referent>
    1023             : class JS_PUBLIC_API(TracerConcrete) : public Base {
    1024             :     js::UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames) const override;
    1025             :     JS::Zone* zone() const override;
    1026             : 
    1027             :   protected:
    1028           0 :     explicit TracerConcrete(Referent* ptr) : Base(ptr) { }
    1029           0 :     Referent& get() const { return *static_cast<Referent*>(ptr); }
    1030             : };
    1031             : 
    1032             : // For JS::TraceChildren-based types that have a 'compartment' method.
    1033             : template<typename Referent>
    1034             : class JS_PUBLIC_API(TracerConcreteWithCompartment) : public TracerConcrete<Referent> {
    1035             :     typedef TracerConcrete<Referent> TracerBase;
    1036             :     JSCompartment* compartment() const override;
    1037             : 
    1038             :   protected:
    1039           0 :     explicit TracerConcreteWithCompartment(Referent* ptr) : TracerBase(ptr) { }
    1040             : };
    1041             : 
    1042             : // Define specializations for some commonly-used public JSAPI types.
    1043             : // These can use the generic templates above.
    1044             : template<>
    1045             : class JS_PUBLIC_API(Concrete<JS::Symbol>) : TracerConcrete<JS::Symbol> {
    1046             :   protected:
    1047           0 :     explicit Concrete(JS::Symbol* ptr) : TracerConcrete(ptr) { }
    1048             : 
    1049             :   public:
    1050           0 :     static void construct(void* storage, JS::Symbol* ptr) {
    1051           0 :         new (storage) Concrete(ptr);
    1052           0 :     }
    1053             : 
    1054             :     Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
    1055             : 
    1056           0 :     const char16_t* typeName() const override { return concreteTypeName; }
    1057             :     static const char16_t concreteTypeName[];
    1058             : };
    1059             : 
    1060             : template<>
    1061             : class JS_PUBLIC_API(Concrete<JSScript>) : TracerConcreteWithCompartment<JSScript> {
    1062             :   protected:
    1063           0 :     explicit Concrete(JSScript *ptr) : TracerConcreteWithCompartment<JSScript>(ptr) { }
    1064             : 
    1065             :   public:
    1066           0 :     static void construct(void *storage, JSScript *ptr) { new (storage) Concrete(ptr); }
    1067             : 
    1068           0 :     CoarseType coarseType() const final { return CoarseType::Script; }
    1069             :     Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
    1070             :     const char* scriptFilename() const final;
    1071             : 
    1072           0 :     const char16_t* typeName() const override { return concreteTypeName; }
    1073             :     static const char16_t concreteTypeName[];
    1074             : };
    1075             : 
    1076             : // The JSObject specialization.
    1077             : template<>
    1078             : class JS_PUBLIC_API(Concrete<JSObject>) : public TracerConcreteWithCompartment<JSObject> {
    1079             :   protected:
    1080           0 :     explicit Concrete(JSObject* ptr) : TracerConcreteWithCompartment(ptr) { }
    1081             : 
    1082             :   public:
    1083           0 :     static void construct(void* storage, JSObject* ptr) {
    1084           0 :         new (storage) Concrete(ptr);
    1085           0 :     }
    1086             : 
    1087             :     const char* jsObjectClassName() const override;
    1088             :     MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName)
    1089             :         const override;
    1090             :     Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
    1091             : 
    1092             :     bool hasAllocationStack() const override;
    1093             :     StackFrame allocationStack() const override;
    1094             : 
    1095           0 :     CoarseType coarseType() const final { return CoarseType::Object; }
    1096             : 
    1097           0 :     const char16_t* typeName() const override { return concreteTypeName; }
    1098             :     static const char16_t concreteTypeName[];
    1099             : };
    1100             : 
    1101             : // For JSString, we extend the generic template with a 'size' implementation.
    1102             : template<>
    1103             : class JS_PUBLIC_API(Concrete<JSString>) : TracerConcrete<JSString> {
    1104             :   protected:
    1105           0 :     explicit Concrete(JSString *ptr) : TracerConcrete<JSString>(ptr) { }
    1106             : 
    1107             :   public:
    1108           0 :     static void construct(void *storage, JSString *ptr) { new (storage) Concrete(ptr); }
    1109             : 
    1110             :     Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
    1111             : 
    1112           0 :     CoarseType coarseType() const final { return CoarseType::String; }
    1113             : 
    1114           0 :     const char16_t* typeName() const override { return concreteTypeName; }
    1115             :     static const char16_t concreteTypeName[];
    1116             : };
    1117             : 
    1118             : // The ubi::Node null pointer. Any attempt to operate on a null ubi::Node asserts.
    1119             : template<>
    1120             : class JS_PUBLIC_API(Concrete<void>) : public Base {
    1121             :     const char16_t* typeName() const override;
    1122             :     Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
    1123             :     js::UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames) const override;
    1124             :     JS::Zone* zone() const override;
    1125             :     JSCompartment* compartment() const override;
    1126             :     CoarseType coarseType() const final;
    1127             : 
    1128           0 :     explicit Concrete(void* ptr) : Base(ptr) { }
    1129             : 
    1130             :   public:
    1131           0 :     static void construct(void* storage, void* ptr) { new (storage) Concrete(ptr); }
    1132             : };
    1133             : 
    1134             : 
    1135             : } // namespace ubi
    1136             : } // namespace JS
    1137             : 
    1138             : namespace js {
    1139             : 
    1140             : // Make ubi::Node::HashPolicy the default hash policy for ubi::Node.
    1141             : template<> struct DefaultHasher<JS::ubi::Node> : JS::ubi::Node::HashPolicy { };
    1142             : template<> struct DefaultHasher<JS::ubi::StackFrame> : JS::ubi::StackFrame::HashPolicy { };
    1143             : 
    1144             : } // namespace js
    1145             : 
    1146             : #endif // js_UbiNode_h

Generated by: LCOV version 1.13