Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/devtools/shared/heapsnapshot/DominatorTree.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/DominatorTree.h"
7
#include "mozilla/dom/DominatorTreeBinding.h"
8
9
namespace mozilla {
10
namespace devtools {
11
12
dom::Nullable<uint64_t>
13
DominatorTree::GetRetainedSize(uint64_t aNodeId, ErrorResult& aRv)
14
0
{
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
0
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
0
  }
26
0
27
0
  MOZ_ASSERT(size != 0,
28
0
             "The node should not have been unknown since we got it from the heap snapshot.");
29
0
  return dom::Nullable<uint64_t>(size);
30
0
}
31
32
struct NodeAndRetainedSize
33
{
34
  JS::ubi::Node mNode;
35
  JS::ubi::Node::Size mSize;
36
37
  NodeAndRetainedSize(const JS::ubi::Node& aNode, JS::ubi::Node::Size aSize)
38
    : mNode(aNode)
39
    , mSize(aSize)
40
0
  { }
41
42
  struct Comparator
43
  {
44
    static bool
45
    Equals(const NodeAndRetainedSize& aLhs, const NodeAndRetainedSize& aRhs)
46
0
    {
47
0
      return aLhs.mSize == aRhs.mSize;
48
0
    }
49
50
    static bool
51
    LessThan(const NodeAndRetainedSize& aLhs, const NodeAndRetainedSize& aRhs)
52
0
    {
53
0
      // Use > because we want to sort from greatest to least retained size.
54
0
      return aLhs.mSize > aRhs.mSize;
55
0
    }
56
  };
57
};
58
59
void
60
DominatorTree::GetImmediatelyDominated(uint64_t aNodeId,
61
                                       dom::Nullable<nsTArray<uint64_t>>& aOutResult,
62
                                       ErrorResult& aRv)
63
0
{
64
0
  MOZ_ASSERT(aOutResult.IsNull());
65
0
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
0
71
0
  // 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
0
    }
83
0
    MOZ_ASSERT(retainedSize != 0,
84
0
               "retainedSize should not be zero since we know the node is in the dominator tree.");
85
0
86
0
    dominatedNodes.AppendElement(NodeAndRetainedSize(dominatedNode, retainedSize));
87
0
  }
88
0
89
0
  // Sort them by retained size.
90
0
  NodeAndRetainedSize::Comparator comparator;
91
0
  dominatedNodes.Sort(comparator);
92
0
93
0
  // 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
0
    // The root dominates itself, but we don't want to expose that to JS.
98
0
    if (entry.mNode == root)
99
0
      continue;
100
0
101
0
    aOutResult.Value().AppendElement(entry.mNode.identifier());
102
0
  }
103
0
}
104
105
dom::Nullable<uint64_t>
106
DominatorTree::GetImmediateDominator(uint64_t aNodeId) const
107
0
{
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
0
113
0
  JS::ubi::Node dominator = mDominatorTree.getImmediateDominator(*node);
114
0
  if (!dominator || dominator == *node)
115
0
    return dom::Nullable<uint64_t>();
116
0
117
0
  return dom::Nullable<uint64_t>(dominator.identifier());
118
0
}
119
120
121
/*** Cycle Collection Boilerplate *****************************************************************/
122
123
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DominatorTree, mParent, mHeapSnapshot)
124
125
NS_IMPL_CYCLE_COLLECTING_ADDREF(DominatorTree)
126
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
DominatorTree::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto)
135
0
{
136
0
  return dom::DominatorTree_Binding::Wrap(aCx, this, aGivenProto);
137
0
}
138
139
} // namespace devtools
140
} // namespace mozilla