DominatorTree.cpp (4736B)
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/DominatorTree.h" 7 #include "mozilla/dom/DominatorTreeBinding.h" 8 #include "mozilla/ErrorResult.h" 9 10 namespace mozilla { 11 namespace devtools { 12 13 dom::Nullable<uint64_t> DominatorTree::GetRetainedSize(uint64_t aNodeId, 14 ErrorResult& aRv) { 15 JS::ubi::Node::Id id(aNodeId); 16 auto node = mHeapSnapshot->getNodeById(id); 17 if (node.isNothing()) return dom::Nullable<uint64_t>(); 18 19 auto mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf(); 20 JS::ubi::Node::Size size = 0; 21 if (!mDominatorTree.getRetainedSize(*node, mallocSizeOf, size)) { 22 aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 23 return dom::Nullable<uint64_t>(); 24 } 25 26 MOZ_ASSERT(size != 0, 27 "The node should not have been unknown since we got it from the " 28 "heap snapshot."); 29 return dom::Nullable<uint64_t>(size); 30 } 31 32 struct NodeAndRetainedSize { 33 JS::ubi::Node mNode; 34 JS::ubi::Node::Size mSize; 35 36 NodeAndRetainedSize(const JS::ubi::Node& aNode, JS::ubi::Node::Size aSize) 37 : mNode(aNode), mSize(aSize) {} 38 39 struct Comparator { 40 static bool Equals(const NodeAndRetainedSize& aLhs, 41 const NodeAndRetainedSize& aRhs) { 42 return aLhs.mSize == aRhs.mSize; 43 } 44 45 static bool LessThan(const NodeAndRetainedSize& aLhs, 46 const NodeAndRetainedSize& aRhs) { 47 // Use > because we want to sort from greatest to least retained size. 48 return aLhs.mSize > aRhs.mSize; 49 } 50 }; 51 }; 52 53 void DominatorTree::GetImmediatelyDominated( 54 uint64_t aNodeId, dom::Nullable<nsTArray<uint64_t>>& aOutResult, 55 ErrorResult& aRv) { 56 MOZ_ASSERT(aOutResult.IsNull()); 57 58 JS::ubi::Node::Id id(aNodeId); 59 Maybe<JS::ubi::Node> node = mHeapSnapshot->getNodeById(id); 60 if (node.isNothing()) return; 61 62 // Get all immediately dominated nodes and their retained sizes. 63 MallocSizeOf mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf(); 64 Maybe<JS::ubi::DominatorTree::DominatedSetRange> range = 65 mDominatorTree.getDominatedSet(*node); 66 MOZ_ASSERT( 67 range.isSome(), 68 "The node should be known, since we got it from the heap snapshot."); 69 size_t length = range->length(); 70 nsTArray<NodeAndRetainedSize> dominatedNodes(length); 71 for (const JS::ubi::Node& dominatedNode : *range) { 72 JS::ubi::Node::Size retainedSize = 0; 73 if (NS_WARN_IF(!mDominatorTree.getRetainedSize(dominatedNode, mallocSizeOf, 74 retainedSize))) { 75 aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 76 return; 77 } 78 MOZ_ASSERT(retainedSize != 0, 79 "retainedSize should not be zero since we know the node is in " 80 "the dominator tree."); 81 82 dominatedNodes.AppendElement( 83 NodeAndRetainedSize(dominatedNode, retainedSize)); 84 } 85 86 // Sort them by retained size. 87 NodeAndRetainedSize::Comparator comparator; 88 dominatedNodes.Sort(comparator); 89 90 // Fill the result with the nodes' ids. 91 JS::ubi::Node root = mDominatorTree.root(); 92 aOutResult.SetValue(nsTArray<uint64_t>(length)); 93 for (const NodeAndRetainedSize& entry : dominatedNodes) { 94 // The root dominates itself, but we don't want to expose that to JS. 95 if (entry.mNode == root) continue; 96 97 aOutResult.Value().AppendElement(entry.mNode.identifier()); 98 } 99 } 100 101 dom::Nullable<uint64_t> DominatorTree::GetImmediateDominator( 102 uint64_t aNodeId) const { 103 JS::ubi::Node::Id id(aNodeId); 104 Maybe<JS::ubi::Node> node = mHeapSnapshot->getNodeById(id); 105 if (node.isNothing()) return dom::Nullable<uint64_t>(); 106 107 JS::ubi::Node dominator = mDominatorTree.getImmediateDominator(*node); 108 if (!dominator || dominator == *node) return dom::Nullable<uint64_t>(); 109 110 return dom::Nullable<uint64_t>(dominator.identifier()); 111 } 112 113 /*** Cycle Collection Boilerplate 114 * *****************************************************************/ 115 116 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DominatorTree, mParent, mHeapSnapshot) 117 118 NS_IMPL_CYCLE_COLLECTING_ADDREF(DominatorTree) 119 NS_IMPL_CYCLE_COLLECTING_RELEASE(DominatorTree) 120 121 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DominatorTree) 122 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 123 NS_INTERFACE_MAP_ENTRY(nsISupports) 124 NS_INTERFACE_MAP_END 125 126 /* virtual */ 127 JSObject* DominatorTree::WrapObject(JSContext* aCx, 128 JS::Handle<JSObject*> aGivenProto) { 129 return dom::DominatorTree_Binding::Wrap(aCx, this, aGivenProto); 130 } 131 132 } // namespace devtools 133 } // namespace mozilla