DeserializedNode.cpp (3911B)
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 referent = rhs.referent; 15 name = rhs.name; 16 } 17 18 DeserializedEdge& DeserializedEdge::operator=(DeserializedEdge&& rhs) { 19 MOZ_ASSERT(&rhs != this); 20 this->~DeserializedEdge(); 21 new (this) DeserializedEdge(std::move(rhs)); 22 return *this; 23 } 24 25 JS::ubi::Node DeserializedNode::getEdgeReferent(const DeserializedEdge& edge) { 26 auto ptr = owner->nodes.lookup(edge.referent); 27 MOZ_ASSERT(ptr); 28 29 // `HashSets` only provide const access to their values, because mutating a 30 // value might change its hash, rendering it unfindable in the set. 31 // Unfortunately, the `ubi::Node` constructor requires a non-const pointer to 32 // its referent. However, the only aspect of a `DeserializedNode` we hash on 33 // is its id, which can't be changed via `ubi::Node`, so this cast can't cause 34 // the trouble `HashSet` is concerned a non-const reference would cause. 35 return JS::ubi::Node(const_cast<DeserializedNode*>(&*ptr)); 36 } 37 38 JS::ubi::StackFrame DeserializedStackFrame::getParentStackFrame() const { 39 MOZ_ASSERT(parent.isSome()); 40 auto ptr = owner->frames.lookup(parent.ref()); 41 MOZ_ASSERT(ptr); 42 // See above comment in DeserializedNode::getEdgeReferent about why this 43 // const_cast is needed and safe. 44 return JS::ubi::StackFrame(const_cast<DeserializedStackFrame*>(&*ptr)); 45 } 46 47 } // namespace devtools 48 } // namespace mozilla 49 50 namespace JS { 51 namespace ubi { 52 53 const char16_t Concrete<DeserializedNode>::concreteTypeName[] = 54 u"mozilla::devtools::DeserializedNode"; 55 56 const char16_t* Concrete<DeserializedNode>::typeName() const { 57 return get().typeName; 58 } 59 60 Node::Size Concrete<DeserializedNode>::size( 61 mozilla::MallocSizeOf mallocSizeof) const { 62 return get().size; 63 } 64 65 class DeserializedEdgeRange : public EdgeRange { 66 DeserializedNode* node; 67 Edge currentEdge; 68 size_t i; 69 70 void settle() { 71 if (i >= node->edges.length()) { 72 front_ = nullptr; 73 return; 74 } 75 76 auto& edge = node->edges[i]; 77 auto referent = node->getEdgeReferent(edge); 78 currentEdge = Edge(edge.name ? NS_xstrdup(edge.name) : nullptr, referent); 79 front_ = ¤tEdge; 80 } 81 82 public: 83 explicit DeserializedEdgeRange(DeserializedNode& node) : node(&node), i(0) { 84 settle(); 85 } 86 87 void popFront() override { 88 i++; 89 settle(); 90 } 91 }; 92 93 StackFrame Concrete<DeserializedNode>::allocationStack() const { 94 MOZ_ASSERT(hasAllocationStack()); 95 auto id = get().allocationStack.ref(); 96 auto ptr = get().owner->frames.lookup(id); 97 MOZ_ASSERT(ptr); 98 // See above comment in DeserializedNode::getEdgeReferent about why this 99 // const_cast is needed and safe. 100 return JS::ubi::StackFrame(const_cast<DeserializedStackFrame*>(&*ptr)); 101 } 102 103 js::UniquePtr<EdgeRange> Concrete<DeserializedNode>::edges(JSContext* cx, 104 bool) const { 105 js::UniquePtr<DeserializedEdgeRange> range( 106 js_new<DeserializedEdgeRange>(get())); 107 108 if (!range) return nullptr; 109 110 return js::UniquePtr<EdgeRange>(range.release()); 111 } 112 113 StackFrame ConcreteStackFrame<DeserializedStackFrame>::parent() const { 114 return get().parent.isNothing() ? StackFrame() : get().getParentStackFrame(); 115 } 116 117 bool ConcreteStackFrame<DeserializedStackFrame>::constructSavedFrameStack( 118 JSContext* cx, JS::MutableHandle<JSObject*> outSavedFrameStack) const { 119 StackFrame f(&get()); 120 return ConstructSavedFrameStackSlow(cx, f, outSavedFrameStack); 121 } 122 123 } // namespace ubi 124 } // namespace JS