/src/mozilla-central/devtools/shared/heapsnapshot/DeserializedNode.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | #include "mozilla/devtools/DeserializedNode.h" |
7 | | #include "mozilla/devtools/HeapSnapshot.h" |
8 | | #include "nsCRTGlue.h" |
9 | | |
10 | | namespace mozilla { |
11 | | namespace devtools { |
12 | | |
13 | | DeserializedEdge::DeserializedEdge(DeserializedEdge&& rhs) |
14 | 0 | { |
15 | 0 | referent = rhs.referent; |
16 | 0 | name = rhs.name; |
17 | 0 | } |
18 | | |
19 | | DeserializedEdge& DeserializedEdge::operator=(DeserializedEdge&& rhs) |
20 | 0 | { |
21 | 0 | MOZ_ASSERT(&rhs != this); |
22 | 0 | this->~DeserializedEdge(); |
23 | 0 | new(this) DeserializedEdge(std::move(rhs)); |
24 | 0 | return *this; |
25 | 0 | } |
26 | | |
27 | | JS::ubi::Node |
28 | | DeserializedNode::getEdgeReferent(const DeserializedEdge& edge) |
29 | 0 | { |
30 | 0 | auto ptr = owner->nodes.lookup(edge.referent); |
31 | 0 | MOZ_ASSERT(ptr); |
32 | 0 |
|
33 | 0 | // `HashSets` only provide const access to their values, because mutating a |
34 | 0 | // value might change its hash, rendering it unfindable in the set. |
35 | 0 | // Unfortunately, the `ubi::Node` constructor requires a non-const pointer to |
36 | 0 | // its referent. However, the only aspect of a `DeserializedNode` we hash on |
37 | 0 | // is its id, which can't be changed via `ubi::Node`, so this cast can't cause |
38 | 0 | // the trouble `HashSet` is concerned a non-const reference would cause. |
39 | 0 | return JS::ubi::Node(const_cast<DeserializedNode*>(&*ptr)); |
40 | 0 | } |
41 | | |
42 | | JS::ubi::StackFrame |
43 | | DeserializedStackFrame::getParentStackFrame() const |
44 | 0 | { |
45 | 0 | MOZ_ASSERT(parent.isSome()); |
46 | 0 | auto ptr = owner->frames.lookup(parent.ref()); |
47 | 0 | MOZ_ASSERT(ptr); |
48 | 0 | // See above comment in DeserializedNode::getEdgeReferent about why this |
49 | 0 | // const_cast is needed and safe. |
50 | 0 | return JS::ubi::StackFrame(const_cast<DeserializedStackFrame*>(&*ptr)); |
51 | 0 | } |
52 | | |
53 | | } // namespace devtools |
54 | | } // namespace mozilla |
55 | | |
56 | | namespace JS { |
57 | | namespace ubi { |
58 | | |
59 | | using mozilla::devtools::DeserializedEdge; |
60 | | |
61 | | const char16_t Concrete<DeserializedNode>::concreteTypeName[] = |
62 | | u"mozilla::devtools::DeserializedNode"; |
63 | | |
64 | | const char16_t* |
65 | | Concrete<DeserializedNode>::typeName() const |
66 | 0 | { |
67 | 0 | return get().typeName; |
68 | 0 | } |
69 | | |
70 | | Node::Size |
71 | | Concrete<DeserializedNode>::size(mozilla::MallocSizeOf mallocSizeof) const |
72 | 0 | { |
73 | 0 | return get().size; |
74 | 0 | } |
75 | | |
76 | | class DeserializedEdgeRange : public EdgeRange |
77 | | { |
78 | | DeserializedNode* node; |
79 | | Edge currentEdge; |
80 | | size_t i; |
81 | | |
82 | 0 | void settle() { |
83 | 0 | if (i >= node->edges.length()) { |
84 | 0 | front_ = nullptr; |
85 | 0 | return; |
86 | 0 | } |
87 | 0 | |
88 | 0 | auto& edge = node->edges[i]; |
89 | 0 | auto referent = node->getEdgeReferent(edge); |
90 | 0 | currentEdge = Edge(edge.name ? NS_xstrdup(edge.name) : nullptr, referent); |
91 | 0 | front_ = ¤tEdge; |
92 | 0 | } |
93 | | |
94 | | public: |
95 | | explicit DeserializedEdgeRange(DeserializedNode& node) |
96 | | : node(&node) |
97 | | , i(0) |
98 | 0 | { |
99 | 0 | settle(); |
100 | 0 | } |
101 | | |
102 | | void popFront() override |
103 | 0 | { |
104 | 0 | i++; |
105 | 0 | settle(); |
106 | 0 | } |
107 | | }; |
108 | | |
109 | | StackFrame |
110 | | Concrete<DeserializedNode>::allocationStack() const |
111 | 0 | { |
112 | 0 | MOZ_ASSERT(hasAllocationStack()); |
113 | 0 | auto id = get().allocationStack.ref(); |
114 | 0 | auto ptr = get().owner->frames.lookup(id); |
115 | 0 | MOZ_ASSERT(ptr); |
116 | 0 | // See above comment in DeserializedNode::getEdgeReferent about why this |
117 | 0 | // const_cast is needed and safe. |
118 | 0 | return JS::ubi::StackFrame(const_cast<DeserializedStackFrame*>(&*ptr)); |
119 | 0 | } |
120 | | |
121 | | |
122 | | js::UniquePtr<EdgeRange> |
123 | | Concrete<DeserializedNode>::edges(JSContext* cx, bool) const |
124 | 0 | { |
125 | 0 | js::UniquePtr<DeserializedEdgeRange> range(js_new<DeserializedEdgeRange>(get())); |
126 | 0 |
|
127 | 0 | if (!range) |
128 | 0 | return nullptr; |
129 | 0 | |
130 | 0 | return js::UniquePtr<EdgeRange>(range.release()); |
131 | 0 | } |
132 | | |
133 | | StackFrame |
134 | | ConcreteStackFrame<DeserializedStackFrame>::parent() const |
135 | 0 | { |
136 | 0 | return get().parent.isNothing() ? StackFrame() : get().getParentStackFrame(); |
137 | 0 | } |
138 | | |
139 | | bool |
140 | | ConcreteStackFrame<DeserializedStackFrame>::constructSavedFrameStack( |
141 | | JSContext* cx, |
142 | | MutableHandleObject outSavedFrameStack) const |
143 | 0 | { |
144 | 0 | StackFrame f(&get()); |
145 | 0 | return ConstructSavedFrameStackSlow(cx, f, outSavedFrameStack); |
146 | 0 | } |
147 | | |
148 | | } // namespace ubi |
149 | | } // namespace JS |