Coverage Report

Created: 2018-09-25 14:53

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