Bug 1869092 - Fix timeouts in browser_PanelMultiView.js. r=twisniewski,test-only
[gecko.git] / js / public / UbiNodeCensus.h
blob4086300580c7924ee8a3dd0c65e2c369bf46cd67
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef js_UbiNodeCensus_h
8 #define js_UbiNodeCensus_h
10 #include "js/UbiNode.h"
11 #include "js/UbiNodeBreadthFirst.h"
13 // A census is a ubi::Node traversal that assigns each node to one or more
14 // buckets, and returns a report with the size of each bucket.
16 // We summarize the results of a census with counts broken down according to
17 // criteria selected by the API consumer code that is requesting the census. For
18 // example, the following breakdown might give an interesting overview of the
19 // heap:
21 // - all nodes
22 // - objects
23 // - objects with a specific [[Class]] *
24 // - strings
25 // - scripts
26 // - DOM nodes
27 // - nsINodes with a specific name (found in nsINode::NodeName()) *
28 // - all other Node types
29 // - nodes with a specific ubi::Node::typeName *
31 // Obviously, the parts of this tree marked with * represent many separate
32 // counts, depending on how many distinct [[Class]] values and ubi::Node type
33 // names we encounter.
35 // The supported types of breakdowns are documented in
36 // js/src/doc/Debugger/Debugger.Memory.md.
38 // When we parse the 'breakdown' argument to takeCensus, we build a tree of
39 // CountType nodes. For example, for the breakdown shown in the
40 // Debugger.Memory.prototype.takeCensus, documentation:
42 // {
43 // by: "coarseType",
44 // objects: { by: "objectClass" },
45 // other: { by: "internalType" },
46 // domNode: { by: "descriptiveType" }
47 // }
49 // we would build the following tree of CountType subclasses:
51 // ByCoarseType
52 // objects: ByObjectClass
53 // each class: SimpleCount
54 // scripts: SimpleCount
55 // strings: SimpleCount
56 // other: ByUbinodeType
57 // each type: SimpleCount
58 // domNode: ByDomObjectClass
59 // each type: SimpleCount
61 // The interior nodes are all breakdown types that categorize nodes according to
62 // one characteristic or another; and the leaf nodes are all SimpleType.
64 // Each CountType has its own concrete C++ type that holds the counts it
65 // produces. SimpleCount::Count just holds totals. ByObjectClass::Count has a
66 // hash table whose keys are object class names and whose values are counts of
67 // some other type (in the example above, SimpleCount).
69 // To keep actual count nodes small, they have no vtable. Instead, each count
70 // points to its CountType, which knows how to carry out all the operations we
71 // need on a Count. A CountType can produce new count nodes; process nodes as we
72 // visit them; build a JS object reporting the results; and destruct count
73 // nodes.
75 namespace JS {
76 namespace ubi {
78 struct Census;
80 class CountBase;
82 struct CountDeleter {
83 JS_PUBLIC_API void operator()(CountBase*);
86 using CountBasePtr = js::UniquePtr<CountBase, CountDeleter>;
88 // Abstract base class for CountType nodes.
89 struct CountType {
90 explicit CountType() = default;
91 virtual ~CountType() = default;
93 // Destruct a count tree node that this type instance constructed.
94 virtual void destructCount(CountBase& count) = 0;
96 // Return a fresh node for the count tree that categorizes nodes according
97 // to this type. Return a nullptr on OOM.
98 virtual CountBasePtr makeCount() = 0;
100 // Trace |count| and all its children, for garbage collection.
101 virtual void traceCount(CountBase& count, JSTracer* trc) = 0;
103 // Implement the 'count' method for counts returned by this CountType
104 // instance's 'newCount' method.
105 [[nodiscard]] virtual bool count(CountBase& count,
106 mozilla::MallocSizeOf mallocSizeOf,
107 const Node& node) = 0;
109 // Implement the 'report' method for counts returned by this CountType
110 // instance's 'newCount' method.
111 [[nodiscard]] virtual bool report(JSContext* cx, CountBase& count,
112 MutableHandleValue report) = 0;
115 using CountTypePtr = js::UniquePtr<CountType>;
117 // An abstract base class for count tree nodes.
118 class CountBase {
119 // In lieu of a vtable, each CountBase points to its type, which
120 // carries not only the implementations of the CountBase methods, but also
121 // additional parameters for the type's behavior, as specified in the
122 // breakdown argument passed to takeCensus.
123 CountType& type;
125 protected:
126 ~CountBase() = default;
128 public:
129 explicit CountBase(CountType& type)
130 : type(type), total_(0), smallestNodeIdCounted_(SIZE_MAX) {}
132 // Categorize and count |node| as appropriate for this count's type.
133 [[nodiscard]] bool count(mozilla::MallocSizeOf mallocSizeOf,
134 const Node& node) {
135 total_++;
137 auto id = node.identifier();
138 if (id < smallestNodeIdCounted_) {
139 smallestNodeIdCounted_ = id;
142 #ifdef DEBUG
143 size_t oldTotal = total_;
144 #endif
146 bool ret = type.count(*this, mallocSizeOf, node);
148 MOZ_ASSERT(total_ == oldTotal,
149 "CountType::count should not increment total_, CountBase::count "
150 "handles that");
152 return ret;
155 // Construct a JavaScript object reporting the counts recorded in this
156 // count, and store it in |report|. Return true on success, or false on
157 // failure.
158 [[nodiscard]] bool report(JSContext* cx, MutableHandleValue report) {
159 return type.report(cx, *this, report);
162 // Down-cast this CountBase to its true type, based on its 'type' member,
163 // and run its destructor.
164 void destruct() { return type.destructCount(*this); }
166 // Trace this count for garbage collection.
167 void trace(JSTracer* trc) { type.traceCount(*this, trc); }
169 size_t total_;
171 // The smallest JS::ubi::Node::identifier() passed to this instance's
172 // count() method. This provides a stable way to sort sets.
173 Node::Id smallestNodeIdCounted_;
176 using RootedCount = JS::Rooted<CountBasePtr>;
178 // Common data for a census traversal, shared across all CountType nodes.
179 struct Census {
180 JSContext* const cx;
181 // If the targetZones set is non-empty, then only consider nodes whose zone
182 // is an element of the set. If the targetZones set is empty, then nodes in
183 // all zones are considered.
184 JS::ZoneSet targetZones;
186 explicit Census(JSContext* cx) : cx(cx) {}
189 // A BreadthFirst handler type that conducts a census, using a CountBase to
190 // categorize and count each node.
191 class CensusHandler {
192 Census& census;
193 JS::Handle<CountBasePtr> rootCount;
194 mozilla::MallocSizeOf mallocSizeOf;
196 public:
197 CensusHandler(Census& census, JS::Handle<CountBasePtr> rootCount,
198 mozilla::MallocSizeOf mallocSizeOf)
199 : census(census), rootCount(rootCount), mallocSizeOf(mallocSizeOf) {}
201 [[nodiscard]] bool report(JSContext* cx, MutableHandleValue report) {
202 return rootCount->report(cx, report);
205 // This class needs to retain no per-node data.
206 class NodeData {};
208 [[nodiscard]] JS_PUBLIC_API bool operator()(
209 BreadthFirst<CensusHandler>& traversal, Node origin, const Edge& edge,
210 NodeData* referentData, bool first);
213 using CensusTraversal = BreadthFirst<CensusHandler>;
215 // Examine the census options supplied by the API consumer, and (among other
216 // things) use that to build a CountType tree.
217 [[nodiscard]] JS_PUBLIC_API bool ParseCensusOptions(JSContext* cx,
218 Census& census,
219 HandleObject options,
220 CountTypePtr& outResult);
222 // Parse the breakdown language (as described in
223 // js/src/doc/Debugger/Debugger.Memory.md) into a CountTypePtr. A null pointer
224 // is returned on error and is reported to the cx.
225 JS_PUBLIC_API CountTypePtr ParseBreakdown(JSContext* cx,
226 HandleValue breakdownValue);
228 } // namespace ubi
229 } // namespace JS
231 #endif // js_UbiNodeCensus_h