UbiNode.h 44 KB

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