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
|