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