Changeset View
Changeset View
Standalone View
Standalone View
libraries/source/spidermonkey/include-win32-debug/js/UbiNodeCensus.h
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- | ||||
* vim: set ts=8 sts=4 et sw=4 tw=99: | * vim: set ts=8 sts=4 et sw=4 tw=99: | ||||
* This Source Code Form is subject to the terms of the Mozilla Public | * 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 | * 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/. */ | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
#ifndef js_UbiNodeCensus_h | #ifndef js_UbiNodeCensus_h | ||||
#define js_UbiNodeCensus_h | #define js_UbiNodeCensus_h | ||||
#include "mozilla/Attributes.h" | |||||
#include "mozilla/Move.h" | #include "mozilla/Move.h" | ||||
#include <algorithm> | |||||
#include "jsapi.h" | #include "jsapi.h" | ||||
#include "js/UbiNode.h" | #include "js/UbiNode.h" | ||||
#include "js/UbiNodeBreadthFirst.h" | #include "js/UbiNodeBreadthFirst.h" | ||||
// A census is a ubi::Node traversal that assigns each node to one or more | // 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. | // buckets, and returns a report with the size of each bucket. | ||||
// | // | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
namespace JS { | namespace JS { | ||||
namespace ubi { | namespace ubi { | ||||
struct Census; | struct Census; | ||||
class CountBase; | class CountBase; | ||||
struct CountDeleter { | struct CountDeleter { | ||||
void operator()(CountBase*); | JS_PUBLIC_API(void) operator()(CountBase*); | ||||
}; | }; | ||||
using CountBasePtr = UniquePtr<CountBase, CountDeleter>; | using CountBasePtr = js::UniquePtr<CountBase, CountDeleter>; | ||||
// Abstract base class for CountType nodes. | // Abstract base class for CountType nodes. | ||||
struct CountType { | struct CountType { | ||||
explicit CountType(Census& census) : census(census) { } | explicit CountType() { } | ||||
virtual ~CountType() { } | virtual ~CountType() { } | ||||
// Destruct a count tree node that this type instance constructed. | // Destruct a count tree node that this type instance constructed. | ||||
virtual void destructCount(CountBase& count) = 0; | virtual void destructCount(CountBase& count) = 0; | ||||
// Return a fresh node for the count tree that categorizes nodes according | // Return a fresh node for the count tree that categorizes nodes according | ||||
// to this type. Return a nullptr on OOM. | // to this type. Return a nullptr on OOM. | ||||
virtual CountBasePtr makeCount() = 0; | virtual CountBasePtr makeCount() = 0; | ||||
// Trace |count| and all its children, for garbage collection. | // Trace |count| and all its children, for garbage collection. | ||||
virtual void traceCount(CountBase& count, JSTracer* trc) = 0; | virtual void traceCount(CountBase& count, JSTracer* trc) = 0; | ||||
// Implement the 'count' method for counts returned by this CountType | // Implement the 'count' method for counts returned by this CountType | ||||
// instance's 'newCount' method. | // instance's 'newCount' method. | ||||
virtual bool count(CountBase& count, const Node& node) = 0; | 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 | // Implement the 'report' method for counts returned by this CountType | ||||
// instance's 'newCount' method. | // instance's 'newCount' method. | ||||
virtual bool report(CountBase& count, MutableHandleValue report) = 0; | virtual MOZ_MUST_USE bool report(JSContext* cx, CountBase& count, | ||||
MutableHandleValue report) = 0; | |||||
protected: | |||||
Census& census; | |||||
}; | }; | ||||
using CountTypePtr = UniquePtr<CountType, JS::DeletePolicy<CountType>>; | using CountTypePtr = js::UniquePtr<CountType>; | ||||
// An abstract base class for count tree nodes. | // An abstract base class for count tree nodes. | ||||
class CountBase { | class CountBase { | ||||
// In lieu of a vtable, each CountBase points to its type, which | // In lieu of a vtable, each CountBase points to its type, which | ||||
// carries not only the implementations of the CountBase methods, but also | // carries not only the implementations of the CountBase methods, but also | ||||
// additional parameters for the type's behavior, as specified in the | // additional parameters for the type's behavior, as specified in the | ||||
// breakdown argument passed to takeCensus. | // breakdown argument passed to takeCensus. | ||||
CountType& type; | CountType& type; | ||||
protected: | protected: | ||||
~CountBase() { } | ~CountBase() { } | ||||
public: | public: | ||||
explicit CountBase(CountType& type) : type(type), total_(0) { } | explicit CountBase(CountType& type) | ||||
: type(type) | |||||
, total_(0) | |||||
, smallestNodeIdCounted_(SIZE_MAX) | |||||
{ } | |||||
// Categorize and count |node| as appropriate for this count's type. | // Categorize and count |node| as appropriate for this count's type. | ||||
bool count(const Node& node) { return type.count(*this, node); } | 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 | // Construct a JavaScript object reporting the counts recorded in this | ||||
// count, and store it in |report|. Return true on success, or false on | // count, and store it in |report|. Return true on success, or false on | ||||
// failure. | // failure. | ||||
bool report(MutableHandleValue report) { return type.report(*this, report); } | 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, | // Down-cast this CountBase to its true type, based on its 'type' member, | ||||
// and run its destructor. | // and run its destructor. | ||||
void destruct() { return type.destructCount(*this); } | void destruct() { return type.destructCount(*this); } | ||||
// Trace this count for garbage collection. | // Trace this count for garbage collection. | ||||
void trace(JSTracer* trc) { type.traceCount(*this, trc); } | void trace(JSTracer* trc) { type.traceCount(*this, trc); } | ||||
size_t total_; | 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 { | class RootedCount : JS::CustomAutoRooter { | ||||
CountBasePtr count; | CountBasePtr count; | ||||
void trace(JSTracer* trc) override { count->trace(trc); } | void trace(JSTracer* trc) override { count->trace(trc); } | ||||
public: | public: | ||||
Show All 12 Lines | struct Census { | ||||
// If the targetZones set is non-empty, then only consider nodes whose zone | // 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 | // is an element of the set. If the targetZones set is empty, then nodes in | ||||
// all zones are considered. | // all zones are considered. | ||||
JS::ZoneSet targetZones; | JS::ZoneSet targetZones; | ||||
Zone* atomsZone; | Zone* atomsZone; | ||||
explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) { } | explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) { } | ||||
bool init(); | MOZ_MUST_USE JS_PUBLIC_API(bool) init(); | ||||
// A 'new' work-alike that behaves like TempAllocPolicy: report OOM on this | |||||
// census's context, but don't charge the memory allocated to our context's | |||||
// GC pressure counters. | |||||
template<typename T, typename... Args> | |||||
T* new_(Args&&... args) MOZ_HEAP_ALLOCATOR { | |||||
void* memory = js_malloc(sizeof(T)); | |||||
if (MOZ_UNLIKELY(!memory)) { | |||||
return nullptr; | |||||
} | |||||
return new(memory) T(mozilla::Forward<Args>(args)...); | |||||
} | |||||
}; | }; | ||||
// A BreadthFirst handler type that conducts a census, using a CountBase to | // A BreadthFirst handler type that conducts a census, using a CountBase to | ||||
// categorize and count each node. | // categorize and count each node. | ||||
class CensusHandler { | class CensusHandler { | ||||
Census& census; | Census& census; | ||||
CountBasePtr& rootCount; | CountBasePtr& rootCount; | ||||
mozilla::MallocSizeOf mallocSizeOf; | |||||
public: | public: | ||||
CensusHandler(Census& census, CountBasePtr& rootCount) | CensusHandler(Census& census, CountBasePtr& rootCount, mozilla::MallocSizeOf mallocSizeOf) | ||||
: census(census), | : census(census), | ||||
rootCount(rootCount) | rootCount(rootCount), | ||||
mallocSizeOf(mallocSizeOf) | |||||
{ } | { } | ||||
bool report(MutableHandleValue report) { | MOZ_MUST_USE bool report(JSContext* cx, MutableHandleValue report) { | ||||
return rootCount->report(report); | return rootCount->report(cx, report); | ||||
} | } | ||||
// This class needs to retain no per-node data. | // This class needs to retain no per-node data. | ||||
class NodeData { }; | class NodeData { }; | ||||
bool operator() (BreadthFirst<CensusHandler>& traversal, | MOZ_MUST_USE JS_PUBLIC_API(bool) operator() (BreadthFirst<CensusHandler>& traversal, | ||||
Node origin, const Edge& edge, | Node origin, const Edge& edge, | ||||
NodeData* referentData, bool first); | NodeData* referentData, bool first); | ||||
}; | }; | ||||
using CensusTraversal = BreadthFirst<CensusHandler>; | using CensusTraversal = BreadthFirst<CensusHandler>; | ||||
// Examine the census options supplied by the API consumer, and use that to | // Examine the census options supplied by the API consumer, and (among other | ||||
// build a CountType tree. | // things) use that to build a CountType tree. | ||||
bool ParseCensusOptions(JSContext* cx, Census& census, HandleObject options, | MOZ_MUST_USE JS_PUBLIC_API(bool) ParseCensusOptions(JSContext* cx, | ||||
Census& census, HandleObject options, | |||||
CountTypePtr& outResult); | 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 ubi | ||||
} // namespace JS | } // namespace JS | ||||
#endif // js_UbiNodeCensus_h | #endif // js_UbiNodeCensus_h |
Wildfire Games · Phabricator