Bug 1231763 - Extract breakdown parsing from JS::ubi::Census. r=jimb

This commit is contained in:
Nick Fitzgerald 2015-12-16 09:19:00 +01:00
Родитель 514b142f92
Коммит ffd963dd3f
6 изменённых файлов: 169 добавлений и 190 удалений

Просмотреть файл

@ -4,25 +4,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/devtools/DominatorTree.h"
#include "js/Debug.h"
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/dom/DominatorTreeBinding.h"
namespace mozilla {
namespace devtools {
static MallocSizeOf
getCurrentThreadDebuggerMallocSizeOf()
{
auto ccrt = CycleCollectedJSRuntime::Get();
MOZ_ASSERT(ccrt);
auto rt = ccrt->Runtime();
MOZ_ASSERT(rt);
auto mallocSizeOf = JS::dbg::GetDebuggerMallocSizeOf(rt);
MOZ_ASSERT(mallocSizeOf);
return mallocSizeOf;
}
dom::Nullable<uint64_t>
DominatorTree::GetRetainedSize(uint64_t aNodeId, ErrorResult& aRv)
{
@ -31,7 +17,7 @@ DominatorTree::GetRetainedSize(uint64_t aNodeId, ErrorResult& aRv)
if (node.isNothing())
return dom::Nullable<uint64_t>();
auto mallocSizeOf = getCurrentThreadDebuggerMallocSizeOf();
auto mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf();
JS::ubi::Node::Size size = 0;
if (!mDominatorTree.getRetainedSize(*node, mallocSizeOf, size)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
@ -83,7 +69,7 @@ DominatorTree::GetImmediatelyDominated(uint64_t aNodeId,
return;
// Get all immediately dominated nodes and their retained sizes.
MallocSizeOf mallocSizeOf = getCurrentThreadDebuggerMallocSizeOf();
MallocSizeOf mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf();
Maybe<JS::ubi::DominatorTree::DominatedSetRange> range = mDominatorTree.getDominatedSet(*node);
MOZ_ASSERT(range.isSome(), "The node should be known, since we got it from the heap snapshot.");
size_t length = range->length();

Просмотреть файл

@ -55,6 +55,18 @@ using ::google::protobuf::io::ZeroCopyInputStream;
using JS::ubi::AtomOrTwoByteChars;
MallocSizeOf
GetCurrentThreadDebuggerMallocSizeOf()
{
auto ccrt = CycleCollectedJSRuntime::Get();
MOZ_ASSERT(ccrt);
auto rt = ccrt->Runtime();
MOZ_ASSERT(rt);
auto mallocSizeOf = JS::dbg::GetDebuggerMallocSizeOf(rt);
MOZ_ASSERT(mallocSizeOf);
return mallocSizeOf;
}
/*** Cycle Collection Boilerplate *****************************************************************/
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HeapSnapshot, mParent)
@ -482,7 +494,7 @@ HeapSnapshot::TakeCensus(JSContext* cx, JS::HandleObject options,
return;
}
JS::ubi::CensusHandler handler(census, rootCount);
JS::ubi::CensusHandler handler(census, rootCount, GetCurrentThreadDebuggerMallocSizeOf());
{
JS::AutoCheckCannotGC nogc;
@ -504,7 +516,7 @@ HeapSnapshot::TakeCensus(JSContext* cx, JS::HandleObject options,
}
}
if (NS_WARN_IF(!handler.report(rval))) {
if (NS_WARN_IF(!handler.report(cx, rval))) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}

Просмотреть файл

@ -221,6 +221,9 @@ WriteHeapGraph(JSContext* cx,
ignoreNodeCount, ignoreEdgeCount);
}
// Get the mozilla::MallocSizeOf for the current thread's JSRuntime.
MallocSizeOf GetCurrentThreadDebuggerMallocSizeOf();
} // namespace devtools
} // namespace mozilla

Просмотреть файл

@ -87,7 +87,7 @@ using CountBasePtr = UniquePtr<CountBase, CountDeleter>;
// Abstract base class for CountType nodes.
struct CountType {
explicit CountType(Census& census) : census(census) { }
explicit CountType() { }
virtual ~CountType() { }
// Destruct a count tree node that this type instance constructed.
@ -102,14 +102,13 @@ struct CountType {
// Implement the 'count' method for counts returned by this CountType
// instance's 'newCount' method.
virtual bool count(CountBase& count, const Node& node) = 0;
virtual 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 bool report(CountBase& count, MutableHandleValue report) = 0;
protected:
Census& census;
virtual bool report(JSContext* cx, CountBase& count, MutableHandleValue report) = 0;
};
using CountTypePtr = UniquePtr<CountType, JS::DeletePolicy<CountType>>;
@ -129,12 +128,16 @@ class CountBase {
explicit CountBase(CountType& type) : type(type), total_(0) { }
// Categorize and count |node| as appropriate for this count's type.
bool count(const Node& node) { return type.count(*this, node); }
bool count(mozilla::MallocSizeOf mallocSizeOf, const Node& node) {
return type.count(*this, mallocSizeOf, node);
}
// Construct a JavaScript object reporting the counts recorded in this
// count, and store it in |report|. Return true on success, or false on
// failure.
bool report(MutableHandleValue report) { return type.report(*this, report); }
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.
@ -173,18 +176,6 @@ struct Census {
explicit Census(JSContext* cx) : cx(cx), atomsZone(nullptr) { }
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
@ -192,15 +183,17 @@ struct Census {
class CensusHandler {
Census& census;
CountBasePtr& rootCount;
mozilla::MallocSizeOf mallocSizeOf;
public:
CensusHandler(Census& census, CountBasePtr& rootCount)
CensusHandler(Census& census, CountBasePtr& rootCount, mozilla::MallocSizeOf mallocSizeOf)
: census(census),
rootCount(rootCount)
rootCount(rootCount),
mallocSizeOf(mallocSizeOf)
{ }
bool report(MutableHandleValue report) {
return rootCount->report(report);
bool report(JSContext* cx, MutableHandleValue report) {
return rootCount->report(cx, report);
}
// This class needs to retain no per-node data.
@ -213,11 +206,17 @@ class CensusHandler {
using CensusTraversal = BreadthFirst<CensusHandler>;
// Examine the census options supplied by the API consumer, and use that to
// build a CountType tree.
// Examine the census options supplied by the API consumer, and (among other
// things) use that to build a CountType tree.
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.
CountTypePtr ParseBreakdown(JSContext* cx, HandleValue breakdownValue);
} // namespace ubi
} // namespace JS

Просмотреть файл

@ -539,7 +539,7 @@ DebuggerMemory::takeCensus(JSContext* cx, unsigned argc, Value* vp)
JS::ubi::RootedCount rootCount(cx, rootType->makeCount());
if (!rootCount)
return false;
JS::ubi::CensusHandler handler(census, rootCount);
JS::ubi::CensusHandler handler(census, rootCount, cx->runtime()->debuggerMallocSizeOf);
Debugger* dbg = memory->getDebugger();
RootedObject dbgObj(cx, dbg->object);
@ -573,7 +573,7 @@ DebuggerMemory::takeCensus(JSContext* cx, unsigned argc, Value* vp)
}
}
return handler.report(args.rval());
return handler.report(cx, args.rval());
}

Просмотреть файл

@ -54,18 +54,17 @@ class SimpleCount : public CountType {
bool reportBytes : 1;
public:
SimpleCount(Census& census,
UniquePtr<char16_t[], JS::FreePolicy>& label,
bool reportCount=true,
bool reportBytes=true)
: CountType(census),
explicit SimpleCount(UniquePtr<char16_t[], JS::FreePolicy>& label,
bool reportCount=true,
bool reportBytes=true)
: CountType(),
label(Move(label)),
reportCount(reportCount),
reportBytes(reportBytes)
{ }
explicit SimpleCount(Census& census)
: CountType(census),
explicit SimpleCount()
: CountType(),
label(nullptr),
reportCount(true),
reportBytes(true)
@ -76,45 +75,45 @@ class SimpleCount : public CountType {
count.~Count();
}
CountBasePtr makeCount() override { return CountBasePtr(census.new_<Count>(*this)); }
CountBasePtr makeCount() override { return CountBasePtr(js_new<Count>(*this)); }
void traceCount(CountBase& countBase, JSTracer* trc) override { }
bool count(CountBase& countBase, const Node& node) override;
bool report(CountBase& countBase, MutableHandleValue report) override;
bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override;
bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override;
};
bool
SimpleCount::count(CountBase& countBase, const Node& node)
SimpleCount::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node)
{
Count& count = static_cast<Count&>(countBase);
count.total_++;
if (reportBytes)
count.totalBytes_ += node.size(census.cx->runtime()->debuggerMallocSizeOf);
count.totalBytes_ += node.size(mallocSizeOf);
return true;
}
bool
SimpleCount::report(CountBase& countBase, MutableHandleValue report)
SimpleCount::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
{
Count& count = static_cast<Count&>(countBase);
RootedPlainObject obj(census.cx, NewBuiltinClassInstance<PlainObject>(census.cx));
RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
if (!obj)
return false;
RootedValue countValue(census.cx, NumberValue(count.total_));
if (reportCount && !DefineProperty(census.cx, obj, census.cx->names().count, countValue))
RootedValue countValue(cx, NumberValue(count.total_));
if (reportCount && !DefineProperty(cx, obj, cx->names().count, countValue))
return false;
RootedValue bytesValue(census.cx, NumberValue(count.totalBytes_));
if (reportBytes && !DefineProperty(census.cx, obj, census.cx->names().bytes, bytesValue))
RootedValue bytesValue(cx, NumberValue(count.totalBytes_));
if (reportBytes && !DefineProperty(cx, obj, cx->names().bytes, bytesValue))
return false;
if (label) {
JSString* labelString = JS_NewUCStringCopyZ(census.cx, label.get());
JSString* labelString = JS_NewUCStringCopyZ(cx, label.get());
if (!labelString)
return false;
RootedValue labelValue(census.cx, StringValue(labelString));
if (!DefineProperty(census.cx, obj, census.cx->names().label, labelValue))
RootedValue labelValue(cx, StringValue(labelString));
if (!DefineProperty(cx, obj, cx->names().label, labelValue))
return false;
}
@ -155,12 +154,11 @@ class ByCoarseType : public CountType {
};
public:
ByCoarseType(Census& census,
CountTypePtr& objects,
ByCoarseType(CountTypePtr& objects,
CountTypePtr& scripts,
CountTypePtr& strings,
CountTypePtr& other)
: CountType(census),
: CountType(),
objects(Move(objects)),
scripts(Move(scripts)),
strings(Move(strings)),
@ -174,8 +172,8 @@ class ByCoarseType : public CountType {
CountBasePtr makeCount() override;
void traceCount(CountBase& countBase, JSTracer* trc) override;
bool count(CountBase& countBase, const Node& node) override;
bool report(CountBase& countBase, MutableHandleValue report) override;
bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override;
bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override;
};
CountBasePtr
@ -189,11 +187,11 @@ ByCoarseType::makeCount()
if (!objectsCount || !scriptsCount || !stringsCount || !otherCount)
return CountBasePtr(nullptr);
return CountBasePtr(census.new_<Count>(*this,
objectsCount,
scriptsCount,
stringsCount,
otherCount));
return CountBasePtr(js_new<Count>(*this,
objectsCount,
scriptsCount,
stringsCount,
otherCount));
}
void
@ -207,20 +205,20 @@ ByCoarseType::traceCount(CountBase& countBase, JSTracer* trc)
}
bool
ByCoarseType::count(CountBase& countBase, const Node& node)
ByCoarseType::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node)
{
Count& count = static_cast<Count&>(countBase);
count.total_++;
switch (node.coarseType()) {
case JS::ubi::CoarseType::Object:
return count.objects->count(node);
return count.objects->count(mallocSizeOf, node);
case JS::ubi::CoarseType::Script:
return count.scripts->count(node);
return count.scripts->count(mallocSizeOf, node);
case JS::ubi::CoarseType::String:
return count.strings->count(node);
return count.strings->count(mallocSizeOf, node);
case JS::ubi::CoarseType::Other:
return count.other->count(node);
return count.other->count(mallocSizeOf, node);
default:
MOZ_CRASH("bad JS::ubi::CoarseType in JS::ubi::ByCoarseType::count");
return false;
@ -228,32 +226,31 @@ ByCoarseType::count(CountBase& countBase, const Node& node)
}
bool
ByCoarseType::report(CountBase& countBase, MutableHandleValue report)
ByCoarseType::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
{
Count& count = static_cast<Count&>(countBase);
JSContext* cx = census.cx;
RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
if (!obj)
return false;
RootedValue objectsReport(cx);
if (!count.objects->report(&objectsReport) ||
if (!count.objects->report(cx, &objectsReport) ||
!DefineProperty(cx, obj, cx->names().objects, objectsReport))
return false;
RootedValue scriptsReport(cx);
if (!count.scripts->report(&scriptsReport) ||
if (!count.scripts->report(cx, &scriptsReport) ||
!DefineProperty(cx, obj, cx->names().scripts, scriptsReport))
return false;
RootedValue stringsReport(cx);
if (!count.strings->report(&stringsReport) ||
if (!count.strings->report(cx, &stringsReport) ||
!DefineProperty(cx, obj, cx->names().strings, stringsReport))
return false;
RootedValue otherReport(cx);
if (!count.other->report(&otherReport) ||
if (!count.other->report(cx, &otherReport) ||
!DefineProperty(cx, obj, cx->names().other, otherReport))
return false;
@ -320,7 +317,7 @@ cStringCountMapToObject(JSContext* cx, CStringCountMap& map) {
for (auto& entry : entries) {
CountBasePtr& thenCount = entry->value();
RootedValue thenReport(cx);
if (!thenCount->report(&thenReport))
if (!thenCount->report(cx, &thenReport))
return nullptr;
const char* name = entry->key();
@ -365,10 +362,8 @@ class ByObjectClass : public CountType {
CountTypePtr otherType;
public:
ByObjectClass(Census& census,
CountTypePtr& classesType,
CountTypePtr& otherType)
: CountType(census),
ByObjectClass(CountTypePtr& classesType, CountTypePtr& otherType)
: CountType(),
classesType(Move(classesType)),
otherType(Move(otherType))
{ }
@ -380,8 +375,8 @@ class ByObjectClass : public CountType {
CountBasePtr makeCount() override;
void traceCount(CountBase& countBase, JSTracer* trc) override;
bool count(CountBase& countBase, const Node& node) override;
bool report(CountBase& countBase, MutableHandleValue report) override;
bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override;
bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override;
};
CountBasePtr
@ -391,7 +386,7 @@ ByObjectClass::makeCount()
if (!otherCount)
return nullptr;
UniquePtr<Count> count(census.new_<Count>(*this, otherCount));
UniquePtr<Count> count(js_new<Count>(*this, otherCount));
if (!count || !count->init())
return nullptr;
@ -408,14 +403,14 @@ ByObjectClass::traceCount(CountBase& countBase, JSTracer* trc)
}
bool
ByObjectClass::count(CountBase& countBase, const Node& node)
ByObjectClass::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node)
{
Count& count = static_cast<Count&>(countBase);
count.total_++;
const char* className = node.jsObjectClassName();
if (!className)
return count.other->count(node);
return count.other->count(mallocSizeOf, node);
Table::AddPtr p = count.table.lookupForAdd(className);
if (!p) {
@ -423,21 +418,20 @@ ByObjectClass::count(CountBase& countBase, const Node& node)
if (!classCount || !count.table.add(p, className, Move(classCount)))
return false;
}
return p->value()->count(node);
return p->value()->count(mallocSizeOf, node);
}
bool
ByObjectClass::report(CountBase& countBase, MutableHandleValue report)
ByObjectClass::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
{
Count& count = static_cast<Count&>(countBase);
JSContext* cx = census.cx;
RootedPlainObject obj(cx, cStringCountMapToObject(cx, count.table));
if (!obj)
return false;
RootedValue otherReport(cx);
if (!count.other->report(&otherReport) ||
if (!count.other->report(cx, &otherReport) ||
!DefineProperty(cx, obj, cx->names().other, otherReport))
return false;
@ -466,8 +460,8 @@ class ByUbinodeType : public CountType {
CountTypePtr entryType;
public:
ByUbinodeType(Census& census, CountTypePtr& entryType)
: CountType(census),
explicit ByUbinodeType(CountTypePtr& entryType)
: CountType(),
entryType(Move(entryType))
{ }
@ -478,14 +472,14 @@ class ByUbinodeType : public CountType {
CountBasePtr makeCount() override;
void traceCount(CountBase& countBase, JSTracer* trc) override;
bool count(CountBase& countBase, const Node& node) override;
bool report(CountBase& countBase, MutableHandleValue report) override;
bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override;
bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override;
};
CountBasePtr
ByUbinodeType::makeCount()
{
UniquePtr<Count> count(census.new_<Count>(*this));
UniquePtr<Count> count(js_new<Count>(*this));
if (!count || !count->init())
return nullptr;
@ -501,7 +495,7 @@ ByUbinodeType::traceCount(CountBase& countBase, JSTracer* trc)
}
bool
ByUbinodeType::count(CountBase& countBase, const Node& node)
ByUbinodeType::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node)
{
Count& count = static_cast<Count&>(countBase);
count.total_++;
@ -514,14 +508,13 @@ ByUbinodeType::count(CountBase& countBase, const Node& node)
if (!typesCount || !count.table.add(p, key, Move(typesCount)))
return false;
}
return p->value()->count(node);
return p->value()->count(mallocSizeOf, node);
}
bool
ByUbinodeType::report(CountBase& countBase, MutableHandleValue report)
ByUbinodeType::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
{
Count& count = static_cast<Count&>(countBase);
JSContext* cx = census.cx;
// Build a vector of pointers to entries; sort by total; and then use
// that to build the result object. This makes the ordering of entries
@ -541,7 +534,7 @@ ByUbinodeType::report(CountBase& countBase, MutableHandleValue report)
Entry& entry = **entryPtr;
CountBasePtr& typeCount = entry.value();
RootedValue typeReport(cx);
if (!typeCount->report(&typeReport))
if (!typeCount->report(cx, &typeReport))
return false;
const char16_t* name = entry.key();
@ -609,8 +602,8 @@ class ByAllocationStack : public CountType {
CountTypePtr noStackType;
public:
ByAllocationStack(Census& census, CountTypePtr& entryType, CountTypePtr& noStackType)
: CountType(census),
ByAllocationStack(CountTypePtr& entryType, CountTypePtr& noStackType)
: CountType(),
entryType(Move(entryType)),
noStackType(Move(noStackType))
{ }
@ -622,8 +615,8 @@ class ByAllocationStack : public CountType {
CountBasePtr makeCount() override;
void traceCount(CountBase& countBase, JSTracer* trc) override;
bool count(CountBase& countBase, const Node& node) override;
bool report(CountBase& countBase, MutableHandleValue report) override;
bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override;
bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override;
};
CountBasePtr
@ -633,7 +626,7 @@ ByAllocationStack::makeCount()
if (!noStackCount)
return nullptr;
UniquePtr<Count> count(census.new_<Count>(*this, noStackCount));
UniquePtr<Count> count(js_new<Count>(*this, noStackCount));
if (!count || !count->init())
return nullptr;
return CountBasePtr(count.release());
@ -657,7 +650,7 @@ ByAllocationStack::traceCount(CountBase& countBase, JSTracer* trc)
}
bool
ByAllocationStack::count(CountBase& countBase, const Node& node)
ByAllocationStack::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node)
{
Count& count = static_cast<Count&>(countBase);
count.total_++;
@ -673,18 +666,17 @@ ByAllocationStack::count(CountBase& countBase, const Node& node)
return false;
}
MOZ_ASSERT(p);
return p->value()->count(node);
return p->value()->count(mallocSizeOf, node);
}
// Otherwise, count it in the "no stack" category.
return count.noStack->count(node);
return count.noStack->count(mallocSizeOf, node);
}
bool
ByAllocationStack::report(CountBase& countBase, MutableHandleValue report)
ByAllocationStack::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
{
Count& count = static_cast<Count&>(countBase);
JSContext* cx = census.cx;
#ifdef DEBUG
// Check that nothing rehashes our table while we hold pointers into it.
@ -719,7 +711,7 @@ ByAllocationStack::report(CountBase& countBase, MutableHandleValue report)
CountBasePtr& stackCount = entry.value();
RootedValue stackReport(cx);
if (!stackCount->report(&stackReport))
if (!stackCount->report(cx, &stackReport))
return false;
if (!MapObject::set(cx, map, stackVal, stackReport))
@ -728,7 +720,7 @@ ByAllocationStack::report(CountBase& countBase, MutableHandleValue report)
if (count.noStack->total_ > 0) {
RootedValue noStackReport(cx);
if (!count.noStack->report(&noStackReport))
if (!count.noStack->report(cx, &noStackReport))
return false;
RootedValue noStack(cx, StringValue(cx->names().noStack));
if (!MapObject::set(cx, map, noStack, noStackReport))
@ -767,10 +759,8 @@ class ByFilename : public CountType {
CountTypePtr noFilenameType;
public:
ByFilename(Census& census,
CountTypePtr& thenType,
CountTypePtr& noFilenameType)
: CountType(census),
ByFilename(CountTypePtr& thenType, CountTypePtr& noFilenameType)
: CountType(),
thenType(Move(thenType)),
noFilenameType(Move(noFilenameType))
{ }
@ -782,8 +772,8 @@ class ByFilename : public CountType {
CountBasePtr makeCount() override;
void traceCount(CountBase& countBase, JSTracer* trc) override;
bool count(CountBase& countBase, const Node& node) override;
bool report(CountBase& countBase, MutableHandleValue report) override;
bool count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node) override;
bool report(JSContext* cx, CountBase& countBase, MutableHandleValue report) override;
};
CountBasePtr
@ -797,7 +787,7 @@ ByFilename::makeCount()
if (!noFilenameCount)
return nullptr;
UniquePtr<Count> count(census.new_<Count>(*this, Move(thenCount), Move(noFilenameCount)));
UniquePtr<Count> count(js_new<Count>(*this, Move(thenCount), Move(noFilenameCount)));
if (!count || !count->init())
return nullptr;
@ -814,14 +804,14 @@ ByFilename::traceCount(CountBase& countBase, JSTracer* trc)
}
bool
ByFilename::count(CountBase& countBase, const Node& node)
ByFilename::count(CountBase& countBase, mozilla::MallocSizeOf mallocSizeOf, const Node& node)
{
Count& count = static_cast<Count&>(countBase);
count.total_++;
const char* filename = node.scriptFilename();
if (!filename)
return count.noFilename->count(node);
return count.noFilename->count(mallocSizeOf, node);
Table::AddPtr p = count.table.lookupForAdd(filename);
if (!p) {
@ -829,21 +819,20 @@ ByFilename::count(CountBase& countBase, const Node& node)
if (!thenCount || !count.table.add(p, filename, Move(thenCount)))
return false;
}
return p->value()->count(node);
return p->value()->count(mallocSizeOf, node);
}
bool
ByFilename::report(CountBase& countBase, MutableHandleValue report)
ByFilename::report(JSContext* cx, CountBase& countBase, MutableHandleValue report)
{
Count& count = static_cast<Count&>(countBase);
JSContext* cx = census.cx;
RootedPlainObject obj(cx, cStringCountMapToObject(cx, count.table));
if (!obj)
return false;
RootedValue noFilenameReport(cx);
if (!count.noFilename->report(&noFilenameReport) ||
if (!count.noFilename->report(cx, &noFilenameReport) ||
!DefineProperty(cx, obj, cx->names().noFilename, noFilenameReport))
{
return false;
@ -876,11 +865,11 @@ CensusHandler::operator() (BreadthFirst<CensusHandler>& traversal,
Zone* zone = referent.zone();
if (census.targetZones.count() == 0 || census.targetZones.has(zone))
return rootCount->count(referent);
return rootCount->count(mallocSizeOf, referent);
if (zone == census.atomsZone) {
traversal.abandonReferent();
return rootCount->count(referent);
return rootCount->count(mallocSizeOf, referent);
}
traversal.abandonReferent();
@ -890,26 +879,21 @@ CensusHandler::operator() (BreadthFirst<CensusHandler>& traversal,
/*** Parsing Breakdowns ***************************************************************************/
static CountTypePtr ParseBreakdown(Census& census, HandleValue breakdownValue);
static CountTypePtr
ParseChildBreakdown(Census& census, HandleObject breakdown, PropertyName* prop)
ParseChildBreakdown(JSContext* cx, HandleObject breakdown, PropertyName* prop)
{
JSContext* cx = census.cx;
RootedValue v(cx);
if (!GetProperty(cx, breakdown, breakdown, prop, &v))
return nullptr;
return ParseBreakdown(census, v);
return ParseBreakdown(cx, v);
}
static CountTypePtr
ParseBreakdown(Census& census, HandleValue breakdownValue)
CountTypePtr
ParseBreakdown(JSContext* cx, HandleValue breakdownValue)
{
JSContext* cx = census.cx;
if (breakdownValue.isUndefined()) {
// Construct the default type, { by: 'count' }
CountTypePtr simple(census.new_<SimpleCount>(census));
CountTypePtr simple(js_new<SimpleCount>());
return simple;
}
@ -967,75 +951,73 @@ ParseBreakdown(Census& census, HandleValue breakdownValue)
return nullptr;
}
CountTypePtr simple(census.new_<SimpleCount>(census,
labelUnique,
ToBoolean(countValue),
ToBoolean(bytesValue)));
CountTypePtr simple(js_new<SimpleCount>(labelUnique,
ToBoolean(countValue),
ToBoolean(bytesValue)));
return simple;
}
if (StringEqualsAscii(by, "objectClass")) {
CountTypePtr thenType(ParseChildBreakdown(census, breakdown, cx->names().then));
CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then));
if (!thenType)
return nullptr;
CountTypePtr otherType(ParseChildBreakdown(census, breakdown, cx->names().other));
CountTypePtr otherType(ParseChildBreakdown(cx, breakdown, cx->names().other));
if (!otherType)
return nullptr;
return CountTypePtr(census.new_<ByObjectClass>(census, thenType, otherType));
return CountTypePtr(js_new<ByObjectClass>(thenType, otherType));
}
if (StringEqualsAscii(by, "coarseType")) {
CountTypePtr objectsType(ParseChildBreakdown(census, breakdown, cx->names().objects));
CountTypePtr objectsType(ParseChildBreakdown(cx, breakdown, cx->names().objects));
if (!objectsType)
return nullptr;
CountTypePtr scriptsType(ParseChildBreakdown(census, breakdown, cx->names().scripts));
CountTypePtr scriptsType(ParseChildBreakdown(cx, breakdown, cx->names().scripts));
if (!scriptsType)
return nullptr;
CountTypePtr stringsType(ParseChildBreakdown(census, breakdown, cx->names().strings));
CountTypePtr stringsType(ParseChildBreakdown(cx, breakdown, cx->names().strings));
if (!stringsType)
return nullptr;
CountTypePtr otherType(ParseChildBreakdown(census, breakdown, cx->names().other));
CountTypePtr otherType(ParseChildBreakdown(cx, breakdown, cx->names().other));
if (!otherType)
return nullptr;
return CountTypePtr(census.new_<ByCoarseType>(census,
objectsType,
scriptsType,
stringsType,
otherType));
return CountTypePtr(js_new<ByCoarseType>(objectsType,
scriptsType,
stringsType,
otherType));
}
if (StringEqualsAscii(by, "internalType")) {
CountTypePtr thenType(ParseChildBreakdown(census, breakdown, cx->names().then));
CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then));
if (!thenType)
return nullptr;
return CountTypePtr(census.new_<ByUbinodeType>(census, thenType));
return CountTypePtr(js_new<ByUbinodeType>(thenType));
}
if (StringEqualsAscii(by, "allocationStack")) {
CountTypePtr thenType(ParseChildBreakdown(census, breakdown, cx->names().then));
CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then));
if (!thenType)
return nullptr;
CountTypePtr noStackType(ParseChildBreakdown(census, breakdown, cx->names().noStack));
CountTypePtr noStackType(ParseChildBreakdown(cx, breakdown, cx->names().noStack));
if (!noStackType)
return nullptr;
return CountTypePtr(census.new_<ByAllocationStack>(census, thenType, noStackType));
return CountTypePtr(js_new<ByAllocationStack>(thenType, noStackType));
}
if (StringEqualsAscii(by, "filename")) {
CountTypePtr thenType(ParseChildBreakdown(census, breakdown, cx->names().then));
CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then));
if (!thenType)
return nullptr;
CountTypePtr noFilenameType(ParseChildBreakdown(census, breakdown, cx->names().noFilename));
CountTypePtr noFilenameType(ParseChildBreakdown(cx, breakdown, cx->names().noFilename));
if (!noFilenameType)
return nullptr;
return CountTypePtr(census.new_<ByFilename>(census, thenType, noFilenameType));
return CountTypePtr(js_new<ByFilename>(thenType, noFilenameType));
}
// We didn't recognize the breakdown type; complain.
@ -1059,25 +1041,22 @@ ParseBreakdown(Census& census, HandleValue breakdownValue)
// other: { by: "internalType" }
// }
static CountTypePtr
GetDefaultBreakdown(Census& census)
GetDefaultBreakdown()
{
CountTypePtr byClass(census.new_<SimpleCount>(census));
CountTypePtr byClassElse(census.new_<SimpleCount>(census));
CountTypePtr objects(census.new_<ByObjectClass>(census,
byClass,
byClassElse));
CountTypePtr byClass(js_new<SimpleCount>());
CountTypePtr byClassElse(js_new<SimpleCount>());
CountTypePtr objects(js_new<ByObjectClass>(byClass, byClassElse));
CountTypePtr scripts(census.new_<SimpleCount>(census));
CountTypePtr strings(census.new_<SimpleCount>(census));
CountTypePtr scripts(js_new<SimpleCount>());
CountTypePtr strings(js_new<SimpleCount>());
CountTypePtr byType(census.new_<SimpleCount>(census));
CountTypePtr other(census.new_<ByUbinodeType>(census, byType));
CountTypePtr byType(js_new<SimpleCount>());
CountTypePtr other(js_new<ByUbinodeType>(byType));
return CountTypePtr(census.new_<ByCoarseType>(census,
objects,
scripts,
strings,
other));
return CountTypePtr(js_new<ByCoarseType>(objects,
scripts,
strings,
other));
}
bool
@ -1088,8 +1067,8 @@ ParseCensusOptions(JSContext* cx, Census& census, HandleObject options, CountTyp
return false;
outResult = breakdown.isUndefined()
? GetDefaultBreakdown(census)
: ParseBreakdown(census, breakdown);
? GetDefaultBreakdown()
: ParseBreakdown(cx, breakdown);
return !!outResult;
}