diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /js/public/UbiNodeCensus.h | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/public/UbiNodeCensus.h')
-rw-r--r-- | js/public/UbiNodeCensus.h | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/js/public/UbiNodeCensus.h b/js/public/UbiNodeCensus.h new file mode 100644 index 000000000..8c7990886 --- /dev/null +++ b/js/public/UbiNodeCensus.h @@ -0,0 +1,252 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef js_UbiNodeCensus_h +#define js_UbiNodeCensus_h + +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" + +#include <algorithm> + +#include "jsapi.h" + +#include "js/UbiNode.h" +#include "js/UbiNodeBreadthFirst.h" + +// A census is a ubi::Node traversal that assigns each node to one or more +// buckets, and returns a report with the size of each bucket. +// +// We summarize the results of a census with counts broken down according to +// criteria selected by the API consumer code that is requesting the census. For +// example, the following breakdown might give an interesting overview of the +// heap: +// +// - all nodes +// - objects +// - objects with a specific [[Class]] * +// - strings +// - scripts +// - all other Node types +// - nodes with a specific ubi::Node::typeName * +// +// Obviously, the parts of this tree marked with * represent many separate +// counts, depending on how many distinct [[Class]] values and ubi::Node type +// names we encounter. +// +// The supported types of breakdowns are documented in +// js/src/doc/Debugger/Debugger.Memory.md. +// +// When we parse the 'breakdown' argument to takeCensus, we build a tree of +// CountType nodes. For example, for the breakdown shown in the +// Debugger.Memory.prototype.takeCensus, documentation: +// +// { +// by: "coarseType", +// objects: { by: "objectClass" }, +// other: { by: "internalType" } +// } +// +// we would build the following tree of CountType subclasses: +// +// ByCoarseType +// objects: ByObjectClass +// each class: SimpleCount +// scripts: SimpleCount +// strings: SimpleCount +// other: ByUbinodeType +// each type: SimpleCount +// +// The interior nodes are all breakdown types that categorize nodes according to +// one characteristic or another; and the leaf nodes are all SimpleType. +// +// Each CountType has its own concrete C++ type that holds the counts it +// produces. SimpleCount::Count just holds totals. ByObjectClass::Count has a +// hash table whose keys are object class names and whose values are counts of +// some other type (in the example above, SimpleCount). +// +// To keep actual count nodes small, they have no vtable. Instead, each count +// points to its CountType, which knows how to carry out all the operations we +// need on a Count. A CountType can produce new count nodes; process nodes as we +// visit them; build a JS object reporting the results; and destruct count +// nodes. + + +namespace JS { +namespace ubi { + +struct Census; + +class CountBase; + +struct CountDeleter { + JS_PUBLIC_API(void) operator()(CountBase*); +}; + +using CountBasePtr = js::UniquePtr<CountBase, CountDeleter>; + +// Abstract base class for CountType nodes. +struct CountType { + explicit CountType() { } + virtual ~CountType() { } + + // Destruct a count tree node that this type instance constructed. + virtual void destructCount(CountBase& count) = 0; + + // Return a fresh node for the count tree that categorizes nodes according + // to this type. Return a nullptr on OOM. + virtual CountBasePtr makeCount() = 0; + + // Trace |count| and all its children, for garbage collection. + virtual void traceCount(CountBase& count, JSTracer* trc) = 0; + + // Implement the 'count' method for counts returned by this CountType + // instance's 'newCount' method. + virtual MOZ_MUST_USE bool count(CountBase& count, + mozilla::MallocSizeOf mallocSizeOf, + const Node& node) = 0; + + // Implement the 'report' method for counts returned by this CountType + // instance's 'newCount' method. + virtual MOZ_MUST_USE bool report(JSContext* cx, CountBase& count, + MutableHandleValue report) = 0; +}; + +using CountTypePtr = js::UniquePtr<CountType>; + +// An abstract base class for count tree nodes. +class CountBase { + // In lieu of a vtable, each CountBase points to its type, which + // carries not only the implementations of the CountBase methods, but also + // additional parameters for the type's behavior, as specified in the + // breakdown argument passed to takeCensus. + CountType& type; + + protected: + ~CountBase() { } + + public: + explicit CountBase(CountType& type) + : type(type) + , total_(0) + , smallestNodeIdCounted_(SIZE_MAX) + { } + + // Categorize and count |node| as appropriate for this count's type. + MOZ_MUST_USE bool count(mozilla::MallocSizeOf mallocSizeOf, const Node& node) { + total_++; + + auto id = node.identifier(); + if (id < smallestNodeIdCounted_) { + smallestNodeIdCounted_ = id; + } + +#ifdef DEBUG + size_t oldTotal = total_; +#endif + + bool ret = type.count(*this, mallocSizeOf, node); + + MOZ_ASSERT(total_ == oldTotal, + "CountType::count should not increment total_, CountBase::count handles that"); + + return ret; + } + + // Construct a JavaScript object reporting the counts recorded in this + // count, and store it in |report|. Return true on success, or false on + // failure. + MOZ_MUST_USE bool report(JSContext* cx, MutableHandleValue report) { + return type.report(cx, *this, report); + } + + // Down-cast this CountBase to its true type, based on its 'type' member, + // and run its destructor. + void destruct() { return type.destructCount(*this); } + + // Trace this count for garbage collection. + void trace(JSTracer* trc) { type.traceCount(*this, trc); } + + size_t total_; + + // The smallest JS::ubi::Node::identifier() passed to this instance's + // count() method. This provides a stable way to sort sets. + Node::Id smallestNodeIdCounted_; +}; + +class RootedCount : JS::CustomAutoRooter { + CountBasePtr count; + + void trace(JSTracer* trc) override { count->trace(trc); } + + public: + RootedCount(JSContext* cx, CountBasePtr&& count) + : CustomAutoRooter(cx), + count(Move(count)) + { } + CountBase* operator->() const { return count.get(); } + explicit operator bool() const { return count.get(); } + operator CountBasePtr&() { return count; } +}; + +// Common data for a census traversal, shared across all CountType nodes. +struct Census { + JSContext* const cx; + // If the targetZones set is non-empty, then only consider nodes whose zone + // is an element of the set. If the targetZones set is empty, then nodes in + // all zones are considered. + JS::ZoneSet targetZones; + Zone* atomsZone; + + explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) { } + + MOZ_MUST_USE JS_PUBLIC_API(bool) init(); +}; + +// A BreadthFirst handler type that conducts a census, using a CountBase to +// categorize and count each node. +class CensusHandler { + Census& census; + CountBasePtr& rootCount; + mozilla::MallocSizeOf mallocSizeOf; + + public: + CensusHandler(Census& census, CountBasePtr& rootCount, mozilla::MallocSizeOf mallocSizeOf) + : census(census), + rootCount(rootCount), + mallocSizeOf(mallocSizeOf) + { } + + MOZ_MUST_USE bool report(JSContext* cx, MutableHandleValue report) { + return rootCount->report(cx, report); + } + + // This class needs to retain no per-node data. + class NodeData { }; + + MOZ_MUST_USE JS_PUBLIC_API(bool) operator() (BreadthFirst<CensusHandler>& traversal, + Node origin, const Edge& edge, + NodeData* referentData, bool first); +}; + +using CensusTraversal = BreadthFirst<CensusHandler>; + +// Examine the census options supplied by the API consumer, and (among other +// things) use that to build a CountType tree. +MOZ_MUST_USE JS_PUBLIC_API(bool) ParseCensusOptions(JSContext* cx, + Census& census, HandleObject options, + CountTypePtr& outResult); + +// Parse the breakdown language (as described in +// js/src/doc/Debugger/Debugger.Memory.md) into a CountTypePtr. A null pointer +// is returned on error and is reported to the cx. +JS_PUBLIC_API(CountTypePtr) ParseBreakdown(JSContext* cx, HandleValue breakdownValue); + + +} // namespace ubi +} // namespace JS + +#endif // js_UbiNodeCensus_h |