Bug 1874684 - Part 21: Rename SecondsAndNanoseconds::toTotalNanoseconds. r=dminor
[gecko.git] / js / public / UbiNodeCensus.h
blob9ac470725cc38dc740b43fd8657f3e4d192d2bec
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/GCVector.h"
11 #include "js/UbiNode.h"
12 #include "js/UbiNodeBreadthFirst.h"
14 // A census is a ubi::Node traversal that assigns each node to one or more
15 // buckets, and returns a report with the size of each bucket.
17 // We summarize the results of a census with counts broken down according to
18 // criteria selected by the API consumer code that is requesting the census. For
19 // example, the following breakdown might give an interesting overview of the
20 // heap:
22 // - all nodes
23 // - objects
24 // - objects with a specific [[Class]] *
25 // - strings
26 // - scripts
27 // - DOM nodes
28 // - nsINodes with a specific name (found in nsINode::NodeName()) *
29 // - all other Node types
30 // - nodes with a specific ubi::Node::typeName *
32 // Obviously, the parts of this tree marked with * represent many separate
33 // counts, depending on how many distinct [[Class]] values and ubi::Node type
34 // names we encounter.
36 // The supported types of breakdowns are documented in
37 // js/src/doc/Debugger/Debugger.Memory.md.
39 // When we parse the 'breakdown' argument to takeCensus, we build a tree of
40 // CountType nodes. For example, for the breakdown shown in the
41 // Debugger.Memory.prototype.takeCensus, documentation:
43 // {
44 // by: "coarseType",
45 // objects: { by: "objectClass" },
46 // other: { by: "internalType" },
47 // domNode: { by: "descriptiveType" }
48 // }
50 // we would build the following tree of CountType subclasses:
52 // ByCoarseType
53 // objects: ByObjectClass
54 // each class: SimpleCount
55 // scripts: SimpleCount
56 // strings: SimpleCount
57 // other: ByUbinodeType
58 // each type: SimpleCount
59 // domNode: ByDomObjectClass
60 // each type: SimpleCount
62 // The interior nodes are all breakdown types that categorize nodes according to
63 // one characteristic or another; and the leaf nodes are all SimpleType.
65 // Each CountType has its own concrete C++ type that holds the counts it
66 // produces. SimpleCount::Count just holds totals. ByObjectClass::Count has a
67 // hash table whose keys are object class names and whose values are counts of
68 // some other type (in the example above, SimpleCount).
70 // To keep actual count nodes small, they have no vtable. Instead, each count
71 // points to its CountType, which knows how to carry out all the operations we
72 // need on a Count. A CountType can produce new count nodes; process nodes as we
73 // visit them; build a JS object reporting the results; and destruct count
74 // nodes.
76 namespace JS {
77 namespace ubi {
79 struct Census;
81 class CountBase;
83 struct CountDeleter {
84 JS_PUBLIC_API void operator()(CountBase*);
87 using CountBasePtr = js::UniquePtr<CountBase, CountDeleter>;
89 // Abstract base class for CountType nodes.
90 struct CountType {
91 explicit CountType() = default;
92 virtual ~CountType() = default;
94 // Destruct a count tree node that this type instance constructed.
95 virtual void destructCount(CountBase& count) = 0;
97 // Return a fresh node for the count tree that categorizes nodes according
98 // to this type. Return a nullptr on OOM.
99 virtual CountBasePtr makeCount() = 0;
101 // Trace |count| and all its children, for garbage collection.
102 virtual void traceCount(CountBase& count, JSTracer* trc) = 0;
104 // Implement the 'count' method for counts returned by this CountType
105 // instance's 'newCount' method.
106 [[nodiscard]] virtual bool count(CountBase& count,
107 mozilla::MallocSizeOf mallocSizeOf,
108 const Node& node) = 0;
110 // Implement the 'report' method for counts returned by this CountType
111 // instance's 'newCount' method.
112 [[nodiscard]] virtual bool report(JSContext* cx, CountBase& count,
113 MutableHandleValue report) = 0;
116 using CountTypePtr = js::UniquePtr<CountType>;
118 // An abstract base class for count tree nodes.
119 class CountBase {
120 // In lieu of a vtable, each CountBase points to its type, which
121 // carries not only the implementations of the CountBase methods, but also
122 // additional parameters for the type's behavior, as specified in the
123 // breakdown argument passed to takeCensus.
124 CountType& type;
126 protected:
127 ~CountBase() = default;
129 public:
130 explicit CountBase(CountType& type)
131 : type(type), total_(0), smallestNodeIdCounted_(SIZE_MAX) {}
133 // Categorize and count |node| as appropriate for this count's type.
134 [[nodiscard]] bool count(mozilla::MallocSizeOf mallocSizeOf,
135 const Node& node) {
136 total_++;
138 auto id = node.identifier();
139 if (id < smallestNodeIdCounted_) {
140 smallestNodeIdCounted_ = id;
143 #ifdef DEBUG
144 size_t oldTotal = total_;
145 #endif
147 bool ret = type.count(*this, mallocSizeOf, node);
149 MOZ_ASSERT(total_ == oldTotal,
150 "CountType::count should not increment total_, CountBase::count "
151 "handles that");
153 return ret;
156 // Construct a JavaScript object reporting the counts recorded in this
157 // count, and store it in |report|. Return true on success, or false on
158 // failure.
159 [[nodiscard]] bool report(JSContext* cx, MutableHandleValue report) {
160 return type.report(cx, *this, report);
163 // Down-cast this CountBase to its true type, based on its 'type' member,
164 // and run its destructor.
165 void destruct() { return type.destructCount(*this); }
167 // Trace this count for garbage collection.
168 void trace(JSTracer* trc) { type.traceCount(*this, trc); }
170 size_t total_;
172 // The smallest JS::ubi::Node::identifier() passed to this instance's
173 // count() method. This provides a stable way to sort sets.
174 Node::Id smallestNodeIdCounted_;
177 using RootedCount = JS::Rooted<CountBasePtr>;
179 // Common data for a census traversal, shared across all CountType nodes.
180 struct Census {
181 JSContext* const cx;
182 // If the targetZones set is non-empty, then only consider nodes whose zone
183 // is an element of the set. If the targetZones set is empty, then nodes in
184 // all zones are considered.
185 JS::ZoneSet targetZones;
187 explicit Census(JSContext* cx) : cx(cx) {}
190 // A BreadthFirst handler type that conducts a census, using a CountBase to
191 // categorize and count each node.
192 class CensusHandler {
193 Census& census;
194 JS::Handle<CountBasePtr> rootCount;
195 mozilla::MallocSizeOf mallocSizeOf;
197 public:
198 CensusHandler(Census& census, JS::Handle<CountBasePtr> rootCount,
199 mozilla::MallocSizeOf mallocSizeOf)
200 : census(census), rootCount(rootCount), mallocSizeOf(mallocSizeOf) {}
202 [[nodiscard]] bool report(JSContext* cx, MutableHandleValue report) {
203 return rootCount->report(cx, report);
206 // This class needs to retain no per-node data.
207 class NodeData {};
209 [[nodiscard]] JS_PUBLIC_API bool operator()(
210 BreadthFirst<CensusHandler>& traversal, Node origin, const Edge& edge,
211 NodeData* referentData, bool first);
214 using CensusTraversal = BreadthFirst<CensusHandler>;
216 // Examine the census options supplied by the API consumer, and (among other
217 // things) use that to build a CountType tree.
218 [[nodiscard]] JS_PUBLIC_API bool ParseCensusOptions(JSContext* cx,
219 Census& census,
220 HandleObject options,
221 CountTypePtr& outResult);
223 // Parse the breakdown language (as described in
224 // js/src/doc/Debugger/Debugger.Memory.md) into a CountTypePtr. A null pointer
225 // is returned on error and is reported to the cx.
226 JS_PUBLIC_API CountTypePtr
227 ParseBreakdown(JSContext* cx, HandleValue breakdownValue,
228 MutableHandle<JS::GCVector<JSLinearString*>> seen);
230 } // namespace ubi
231 } // namespace JS
233 #endif // js_UbiNodeCensus_h