зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1023719 - Report notable classes in the JS memory reporter. r=till.
--HG-- extra : rebase_source : 5a842c36cf7202f6751290da80cefb005fd8db95
This commit is contained in:
Родитель
cb1a5a5562
Коммит
feeaf7db9a
|
@ -115,31 +115,45 @@ enum {
|
|||
|
||||
namespace JS {
|
||||
|
||||
// Data for tracking memory usage of things hanging off objects.
|
||||
struct ObjectsExtraSizes
|
||||
struct ClassInfo
|
||||
{
|
||||
#define FOR_EACH_SIZE(macro) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapSlots) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapElementsNonAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapElementsAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, nonHeapElementsAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, nonHeapElementsMapped) \
|
||||
macro(Objects, NotLiveGCThing, nonHeapCodeAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapAsmJSModuleData) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapArgumentsData) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapRegExpStatics) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapPropertyIteratorData) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapCtypesData)
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeap) \
|
||||
macro(Objects, NotLiveGCThing, objectsMallocHeapSlots) \
|
||||
macro(Objects, NotLiveGCThing, objectsMallocHeapElementsNonAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, objectsMallocHeapElementsAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, objectsNonHeapElementsAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, objectsNonHeapElementsMapped) \
|
||||
macro(Objects, NotLiveGCThing, objectsNonHeapCodeAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, objectsMallocHeapMisc) \
|
||||
\
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapTree) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapDict) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapBase) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapTreeTables) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapDictTables) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapTreeKids) \
|
||||
|
||||
ObjectsExtraSizes()
|
||||
ClassInfo()
|
||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||
dummy()
|
||||
{}
|
||||
|
||||
void add(const ObjectsExtraSizes &other) {
|
||||
void add(const ClassInfo &other) {
|
||||
FOR_EACH_SIZE(ADD_OTHER_SIZE)
|
||||
}
|
||||
|
||||
void subtract(const ClassInfo &other) {
|
||||
FOR_EACH_SIZE(SUB_OTHER_SIZE)
|
||||
}
|
||||
|
||||
bool isNotable() const {
|
||||
static const size_t NotabilityThreshold = 16 * 1024;
|
||||
size_t n = 0;
|
||||
FOR_EACH_SIZE(ADD_SIZE_TO_N)
|
||||
return n >= NotabilityThreshold;
|
||||
}
|
||||
|
||||
size_t sizeOfLiveGCThings() const {
|
||||
size_t n = 0;
|
||||
FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
|
||||
|
@ -156,6 +170,29 @@ struct ObjectsExtraSizes
|
|||
#undef FOR_EACH_SIZE
|
||||
};
|
||||
|
||||
// Holds data about a notable class (one whose combined object and shape
|
||||
// instances use more than a certain amount of memory) so we can report it
|
||||
// individually.
|
||||
//
|
||||
// The only difference between this class and ClassInfo is that this class
|
||||
// holds a copy of the filename.
|
||||
struct NotableClassInfo : public ClassInfo
|
||||
{
|
||||
NotableClassInfo();
|
||||
NotableClassInfo(const char *className, const ClassInfo &info);
|
||||
NotableClassInfo(NotableClassInfo &&info);
|
||||
NotableClassInfo &operator=(NotableClassInfo &&info);
|
||||
|
||||
~NotableClassInfo() {
|
||||
js_free(className_);
|
||||
}
|
||||
|
||||
char *className_;
|
||||
|
||||
private:
|
||||
NotableClassInfo(const NotableClassInfo& info) MOZ_DELETE;
|
||||
};
|
||||
|
||||
// Data for tracking JIT-code memory usage.
|
||||
struct CodeSizes
|
||||
{
|
||||
|
@ -486,20 +523,7 @@ struct ZoneStats
|
|||
struct CompartmentStats
|
||||
{
|
||||
#define FOR_EACH_SIZE(macro) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapOrdinary) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapFunction) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapDenseArray) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapSlowArray) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapCrossCompartmentWrapper) \
|
||||
macro(Private, NotLiveGCThing, objectsPrivate) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapTreeGlobalParented) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapTreeNonGlobalParented) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapDict) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapBase) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapTreeTables) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapDictTables) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapTreeShapeKids) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapCompartmentTables) \
|
||||
macro(Other, IsLiveGCThing, scriptsGCHeap) \
|
||||
macro(Other, NotLiveGCThing, scriptsMallocHeapData) \
|
||||
macro(Other, NotLiveGCThing, baselineData) \
|
||||
|
@ -510,6 +534,7 @@ struct CompartmentStats
|
|||
macro(Other, NotLiveGCThing, typeInferenceArrayTypeTables) \
|
||||
macro(Other, NotLiveGCThing, typeInferenceObjectTypeTables) \
|
||||
macro(Other, NotLiveGCThing, compartmentObject) \
|
||||
macro(Other, NotLiveGCThing, compartmentTables) \
|
||||
macro(Other, NotLiveGCThing, crossCompartmentWrappersTable) \
|
||||
macro(Other, NotLiveGCThing, regexpCompartment) \
|
||||
macro(Other, NotLiveGCThing, debuggeesSet) \
|
||||
|
@ -517,39 +542,69 @@ struct CompartmentStats
|
|||
|
||||
CompartmentStats()
|
||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||
objectsExtra(),
|
||||
extra()
|
||||
classInfo(),
|
||||
extra(),
|
||||
allClasses(nullptr),
|
||||
notableClasses(),
|
||||
isTotals(true)
|
||||
{}
|
||||
|
||||
CompartmentStats(const CompartmentStats &other)
|
||||
CompartmentStats(CompartmentStats &&other)
|
||||
: FOR_EACH_SIZE(COPY_OTHER_SIZE)
|
||||
objectsExtra(other.objectsExtra),
|
||||
extra(other.extra)
|
||||
{}
|
||||
classInfo(mozilla::Move(other.classInfo)),
|
||||
extra(other.extra),
|
||||
allClasses(other.allClasses),
|
||||
notableClasses(mozilla::Move(other.notableClasses)),
|
||||
isTotals(other.isTotals)
|
||||
{
|
||||
other.allClasses = nullptr;
|
||||
MOZ_ASSERT(!other.isTotals);
|
||||
}
|
||||
|
||||
void add(const CompartmentStats &other) {
|
||||
~CompartmentStats() {
|
||||
// |allClasses| is usually deleted and set to nullptr before this
|
||||
// destructor runs. But there are failure cases due to OOMs that may
|
||||
// prevent that, so it doesn't hurt to try again here.
|
||||
js_delete(allClasses);
|
||||
}
|
||||
|
||||
bool initClasses(JSRuntime *rt);
|
||||
|
||||
void addSizes(const CompartmentStats &other) {
|
||||
MOZ_ASSERT(isTotals);
|
||||
FOR_EACH_SIZE(ADD_OTHER_SIZE)
|
||||
objectsExtra.add(other.objectsExtra);
|
||||
// Do nothing with |extra|.
|
||||
classInfo.add(other.classInfo);
|
||||
}
|
||||
|
||||
size_t sizeOfLiveGCThings() const {
|
||||
MOZ_ASSERT(isTotals);
|
||||
size_t n = 0;
|
||||
FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
|
||||
n += objectsExtra.sizeOfLiveGCThings();
|
||||
// Do nothing with |extra|.
|
||||
n += classInfo.sizeOfLiveGCThings();
|
||||
return n;
|
||||
}
|
||||
|
||||
void addToTabSizes(TabSizes *sizes) const {
|
||||
MOZ_ASSERT(isTotals);
|
||||
FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
|
||||
objectsExtra.addToTabSizes(sizes);
|
||||
// Do nothing with |extra|.
|
||||
classInfo.addToTabSizes(sizes);
|
||||
}
|
||||
|
||||
// The class measurements in |classInfo| are initially for all classes. At
|
||||
// the end, if the measurement granularity is FineGrained, we subtract the
|
||||
// measurements of the notable classes and move them into |notableClasses|.
|
||||
FOR_EACH_SIZE(DECL_SIZE)
|
||||
ObjectsExtraSizes objectsExtra;
|
||||
void *extra; // This field can be used by embedders.
|
||||
ClassInfo classInfo;
|
||||
void *extra; // This field can be used by embedders.
|
||||
|
||||
typedef js::HashMap<const char*, ClassInfo,
|
||||
js::CStringHashPolicy,
|
||||
js::SystemAllocPolicy> ClassesHashMap;
|
||||
|
||||
// These are similar to |allStrings| and |notableStrings| in ZoneStats.
|
||||
ClassesHashMap *allClasses;
|
||||
js::Vector<NotableClassInfo, 0, js::SystemAllocPolicy> notableClasses;
|
||||
bool isTotals;
|
||||
|
||||
#undef FOR_EACH_SIZE
|
||||
};
|
||||
|
|
|
@ -951,7 +951,7 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
|||
size_t *tiArrayTypeTables,
|
||||
size_t *tiObjectTypeTables,
|
||||
size_t *compartmentObject,
|
||||
size_t *shapesCompartmentTables,
|
||||
size_t *compartmentTables,
|
||||
size_t *crossCompartmentWrappersArg,
|
||||
size_t *regexpCompartment,
|
||||
size_t *debuggeesSet,
|
||||
|
@ -960,10 +960,10 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
|||
*compartmentObject += mallocSizeOf(this);
|
||||
types.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables,
|
||||
tiArrayTypeTables, tiObjectTypeTables);
|
||||
*shapesCompartmentTables += baseShapes.sizeOfExcludingThis(mallocSizeOf)
|
||||
+ initialShapes.sizeOfExcludingThis(mallocSizeOf)
|
||||
+ newTypeObjects.sizeOfExcludingThis(mallocSizeOf)
|
||||
+ lazyTypeObjects.sizeOfExcludingThis(mallocSizeOf);
|
||||
*compartmentTables += baseShapes.sizeOfExcludingThis(mallocSizeOf)
|
||||
+ initialShapes.sizeOfExcludingThis(mallocSizeOf)
|
||||
+ newTypeObjects.sizeOfExcludingThis(mallocSizeOf)
|
||||
+ lazyTypeObjects.sizeOfExcludingThis(mallocSizeOf);
|
||||
*crossCompartmentWrappersArg += crossCompartmentWrappers.sizeOfExcludingThis(mallocSizeOf);
|
||||
*regexpCompartment += regExps.sizeOfExcludingThis(mallocSizeOf);
|
||||
*debuggeesSet += debuggees.sizeOfExcludingThis(mallocSizeOf);
|
||||
|
|
|
@ -225,7 +225,7 @@ struct JSCompartment
|
|||
size_t *tiArrayTypeTables,
|
||||
size_t *tiObjectTypeTables,
|
||||
size_t *compartmentObject,
|
||||
size_t *shapesCompartmentTables,
|
||||
size_t *compartmentTables,
|
||||
size_t *crossCompartmentWrappers,
|
||||
size_t *regexpCompartment,
|
||||
size_t *debuggeesSet,
|
||||
|
|
|
@ -6027,14 +6027,14 @@ js_DumpBacktrace(JSContext *cx)
|
|||
}
|
||||
|
||||
void
|
||||
JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ObjectsExtraSizes *sizes)
|
||||
JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ClassInfo *info)
|
||||
{
|
||||
if (hasDynamicSlots())
|
||||
sizes->mallocHeapSlots += mallocSizeOf(slots);
|
||||
info->objectsMallocHeapSlots += mallocSizeOf(slots);
|
||||
|
||||
if (hasDynamicElements()) {
|
||||
js::ObjectElements *elements = getElementsHeader();
|
||||
sizes->mallocHeapElementsNonAsmJS += mallocSizeOf(elements);
|
||||
info->objectsMallocHeapElementsNonAsmJS += mallocSizeOf(elements);
|
||||
}
|
||||
|
||||
// Other things may be measured in the future if DMD indicates it is worthwhile.
|
||||
|
@ -6056,22 +6056,22 @@ JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Objects
|
|||
// - ( 1.0%, 96.4%): Proxy
|
||||
|
||||
} else if (is<ArgumentsObject>()) {
|
||||
sizes->mallocHeapArgumentsData += as<ArgumentsObject>().sizeOfMisc(mallocSizeOf);
|
||||
info->objectsMallocHeapMisc += as<ArgumentsObject>().sizeOfMisc(mallocSizeOf);
|
||||
} else if (is<RegExpStaticsObject>()) {
|
||||
sizes->mallocHeapRegExpStatics += as<RegExpStaticsObject>().sizeOfData(mallocSizeOf);
|
||||
info->objectsMallocHeapMisc += as<RegExpStaticsObject>().sizeOfData(mallocSizeOf);
|
||||
} else if (is<PropertyIteratorObject>()) {
|
||||
sizes->mallocHeapPropertyIteratorData += as<PropertyIteratorObject>().sizeOfMisc(mallocSizeOf);
|
||||
info->objectsMallocHeapMisc += as<PropertyIteratorObject>().sizeOfMisc(mallocSizeOf);
|
||||
} else if (is<ArrayBufferObject>() || is<SharedArrayBufferObject>()) {
|
||||
ArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf, sizes);
|
||||
ArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf, info);
|
||||
#ifdef JS_ION
|
||||
} else if (is<AsmJSModuleObject>()) {
|
||||
as<AsmJSModuleObject>().addSizeOfMisc(mallocSizeOf, &sizes->nonHeapCodeAsmJS,
|
||||
&sizes->mallocHeapAsmJSModuleData);
|
||||
as<AsmJSModuleObject>().addSizeOfMisc(mallocSizeOf, &info->objectsNonHeapCodeAsmJS,
|
||||
&info->objectsMallocHeapMisc);
|
||||
#endif
|
||||
#ifdef JS_HAS_CTYPES
|
||||
} else {
|
||||
// This must be the last case.
|
||||
sizes->mallocHeapCtypesData +=
|
||||
info->objectsMallocHeapMisc +=
|
||||
js::SizeOfDataIfCDataObject(mallocSizeOf, const_cast<JSObject *>(this));
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "vm/Xdr.h"
|
||||
|
||||
namespace JS {
|
||||
struct ObjectsExtraSizes;
|
||||
struct ClassInfo;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
@ -334,7 +334,7 @@ class JSObject : public js::ObjectImpl
|
|||
return lastProperty()->hasTable();
|
||||
}
|
||||
|
||||
void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ObjectsExtraSizes *sizes);
|
||||
void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ClassInfo *info);
|
||||
|
||||
bool hasIdempotentProtoChain() const;
|
||||
|
||||
|
|
|
@ -765,7 +765,7 @@ ArrayBufferObject::stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffe
|
|||
}
|
||||
|
||||
/* static */ void
|
||||
ArrayBufferObject::addSizeOfExcludingThis(JSObject *obj, mozilla::MallocSizeOf mallocSizeOf, JS::ObjectsExtraSizes *sizes)
|
||||
ArrayBufferObject::addSizeOfExcludingThis(JSObject *obj, mozilla::MallocSizeOf mallocSizeOf, JS::ClassInfo *info)
|
||||
{
|
||||
ArrayBufferObject &buffer = AsArrayBuffer(obj);
|
||||
|
||||
|
@ -776,14 +776,14 @@ ArrayBufferObject::addSizeOfExcludingThis(JSObject *obj, mozilla::MallocSizeOf m
|
|||
#if defined (JS_CPU_X64)
|
||||
// On x64, ArrayBufferObject::prepareForAsmJS switches the
|
||||
// ArrayBufferObject to use mmap'd storage.
|
||||
sizes->nonHeapElementsAsmJS += buffer.byteLength();
|
||||
info->objectsNonHeapElementsAsmJS += buffer.byteLength();
|
||||
#else
|
||||
sizes->mallocHeapElementsAsmJS += mallocSizeOf(buffer.dataPointer());
|
||||
info->objectsMallocHeapElementsAsmJS += mallocSizeOf(buffer.dataPointer());
|
||||
#endif
|
||||
} else if (MOZ_UNLIKELY(buffer.isMappedArrayBuffer())) {
|
||||
sizes->nonHeapElementsMapped += buffer.byteLength();
|
||||
info->objectsNonHeapElementsMapped += buffer.byteLength();
|
||||
} else if (buffer.dataPointer()) {
|
||||
sizes->mallocHeapElementsNonAsmJS += mallocSizeOf(buffer.dataPointer());
|
||||
info->objectsMallocHeapElementsNonAsmJS += mallocSizeOf(buffer.dataPointer());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ class ArrayBufferObject : public JSObject
|
|||
}
|
||||
|
||||
static void addSizeOfExcludingThis(JSObject *obj, mozilla::MallocSizeOf mallocSizeOf,
|
||||
JS::ObjectsExtraSizes *sizes);
|
||||
JS::ClassInfo *info);
|
||||
|
||||
void addView(ArrayBufferViewObject *view);
|
||||
|
||||
|
|
|
@ -155,6 +155,37 @@ NotableStringInfo &NotableStringInfo::operator=(NotableStringInfo &&info)
|
|||
return *this;
|
||||
}
|
||||
|
||||
NotableClassInfo::NotableClassInfo()
|
||||
: ClassInfo(),
|
||||
className_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
NotableClassInfo::NotableClassInfo(const char *className, const ClassInfo &info)
|
||||
: ClassInfo(info)
|
||||
{
|
||||
size_t bytes = strlen(className) + 1;
|
||||
className_ = js_pod_malloc<char>(bytes);
|
||||
if (!className_)
|
||||
MOZ_CRASH("oom");
|
||||
PodCopy(className_, className, bytes);
|
||||
}
|
||||
|
||||
NotableClassInfo::NotableClassInfo(NotableClassInfo &&info)
|
||||
: ClassInfo(Move(info))
|
||||
{
|
||||
className_ = info.className_;
|
||||
info.className_ = nullptr;
|
||||
}
|
||||
|
||||
NotableClassInfo &NotableClassInfo::operator=(NotableClassInfo &&info)
|
||||
{
|
||||
MOZ_ASSERT(this != &info, "self-move assignment is prohibited");
|
||||
this->~NotableClassInfo();
|
||||
new (this) NotableClassInfo(Move(info));
|
||||
return *this;
|
||||
}
|
||||
|
||||
NotableScriptSourceInfo::NotableScriptSourceInfo()
|
||||
: ScriptSourceInfo(),
|
||||
filename_(nullptr)
|
||||
|
@ -246,6 +277,8 @@ StatsCompartmentCallback(JSRuntime *rt, void *data, JSCompartment *compartment)
|
|||
// CollectRuntimeStats reserves enough space.
|
||||
MOZ_ALWAYS_TRUE(rtStats->compartmentStatsVector.growBy(1));
|
||||
CompartmentStats &cStats = rtStats->compartmentStatsVector.back();
|
||||
if (!cStats.initClasses(rt))
|
||||
MOZ_CRASH("oom");
|
||||
rtStats->initExtraCompartmentStats(compartment, &cStats);
|
||||
|
||||
compartment->compartmentStats = &cStats;
|
||||
|
@ -256,7 +289,7 @@ StatsCompartmentCallback(JSRuntime *rt, void *data, JSCompartment *compartment)
|
|||
&cStats.typeInferenceArrayTypeTables,
|
||||
&cStats.typeInferenceObjectTypeTables,
|
||||
&cStats.compartmentObject,
|
||||
&cStats.shapesMallocHeapCompartmentTables,
|
||||
&cStats.compartmentTables,
|
||||
&cStats.crossCompartmentWrappersTable,
|
||||
&cStats.regexpCompartment,
|
||||
&cStats.debuggeesSet,
|
||||
|
@ -292,6 +325,25 @@ enum Granularity {
|
|||
CoarseGrained // Corresponds to AddSizeOfTab()
|
||||
};
|
||||
|
||||
static void
|
||||
AddClassInfo(Granularity granularity, CompartmentStats *cStats, const char *className,
|
||||
JS::ClassInfo &info)
|
||||
{
|
||||
if (granularity == FineGrained) {
|
||||
if (!className)
|
||||
className = "<no class name>";
|
||||
CompartmentStats::ClassesHashMap::AddPtr p =
|
||||
cStats->allClasses->lookupForAdd(className);
|
||||
if (!p) {
|
||||
// Ignore failure -- we just won't record the
|
||||
// object/shape/base-shape as notable.
|
||||
(void)cStats->allClasses->add(p, className, info);
|
||||
} else {
|
||||
p->value().add(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The various kinds of hashing are expensive, and the results are unused when
|
||||
// doing coarse-grained measurements. Skipping them more than doubles the
|
||||
// profile speed for complex pages such as gmail.com.
|
||||
|
@ -307,16 +359,16 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin
|
|||
case JSTRACE_OBJECT: {
|
||||
JSObject *obj = static_cast<JSObject *>(thing);
|
||||
CompartmentStats *cStats = GetCompartmentStats(obj->compartment());
|
||||
if (obj->is<JSFunction>())
|
||||
cStats->objectsGCHeapFunction += thingSize;
|
||||
else if (obj->is<ArrayObject>())
|
||||
cStats->objectsGCHeapDenseArray += thingSize;
|
||||
else if (obj->is<CrossCompartmentWrapperObject>())
|
||||
cStats->objectsGCHeapCrossCompartmentWrapper += thingSize;
|
||||
else
|
||||
cStats->objectsGCHeapOrdinary += thingSize;
|
||||
|
||||
obj->addSizeOfExcludingThis(rtStats->mallocSizeOf_, &cStats->objectsExtra);
|
||||
JS::ClassInfo info; // This zeroes all the sizes.
|
||||
info.objectsGCHeap += thingSize;
|
||||
obj->addSizeOfExcludingThis(rtStats->mallocSizeOf_, &info);
|
||||
|
||||
cStats->classInfo.add(info);
|
||||
|
||||
const Class *clasp = obj->getClass();
|
||||
const char *className = clasp->name;
|
||||
AddClassInfo(granularity, cStats, className, info);
|
||||
|
||||
if (ObjectPrivateVisitor *opv = closure->opv) {
|
||||
nsISupports *iface;
|
||||
|
@ -351,30 +403,36 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin
|
|||
case JSTRACE_SHAPE: {
|
||||
Shape *shape = static_cast<Shape *>(thing);
|
||||
CompartmentStats *cStats = GetCompartmentStats(shape->compartment());
|
||||
if (shape->inDictionary()) {
|
||||
cStats->shapesGCHeapDict += thingSize;
|
||||
|
||||
// nullptr because kidsSize shouldn't be incremented in this case.
|
||||
shape->addSizeOfExcludingThis(rtStats->mallocSizeOf_,
|
||||
&cStats->shapesMallocHeapDictTables, nullptr);
|
||||
} else {
|
||||
JSObject *parent = shape->base()->getObjectParent();
|
||||
if (parent && parent->is<GlobalObject>())
|
||||
cStats->shapesGCHeapTreeGlobalParented += thingSize;
|
||||
else
|
||||
cStats->shapesGCHeapTreeNonGlobalParented += thingSize;
|
||||
JS::ClassInfo info; // This zeroes all the sizes.
|
||||
if (shape->inDictionary())
|
||||
info.shapesGCHeapDict += thingSize;
|
||||
else
|
||||
info.shapesGCHeapTree += thingSize;
|
||||
shape->addSizeOfExcludingThis(rtStats->mallocSizeOf_, &info);
|
||||
|
||||
shape->addSizeOfExcludingThis(rtStats->mallocSizeOf_,
|
||||
&cStats->shapesMallocHeapTreeTables,
|
||||
&cStats->shapesMallocHeapTreeShapeKids);
|
||||
}
|
||||
cStats->classInfo.add(info);
|
||||
|
||||
const BaseShape *base = shape->base();
|
||||
const Class *clasp = base->clasp();
|
||||
const char *className = clasp->name;
|
||||
AddClassInfo(granularity, cStats, className, info);
|
||||
break;
|
||||
}
|
||||
|
||||
case JSTRACE_BASE_SHAPE: {
|
||||
BaseShape *base = static_cast<BaseShape *>(thing);
|
||||
CompartmentStats *cStats = GetCompartmentStats(base->compartment());
|
||||
cStats->shapesGCHeapBase += thingSize;
|
||||
|
||||
JS::ClassInfo info; // This zeroes all the sizes.
|
||||
info.shapesGCHeapBase += thingSize;
|
||||
// No malloc-heap measurements.
|
||||
|
||||
cStats->classInfo.add(info);
|
||||
|
||||
const Class *clasp = base->clasp();
|
||||
const char *className = clasp->name;
|
||||
AddClassInfo(granularity, cStats, className, info);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -450,6 +508,32 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin
|
|||
zStats->unusedGCThings -= thingSize;
|
||||
}
|
||||
|
||||
bool
|
||||
ZoneStats::initStrings(JSRuntime *rt)
|
||||
{
|
||||
isTotals = false;
|
||||
allStrings = rt->new_<StringsHashMap>();
|
||||
if (!allStrings || !allStrings->init()) {
|
||||
js_delete(allStrings);
|
||||
allStrings = nullptr;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CompartmentStats::initClasses(JSRuntime *rt)
|
||||
{
|
||||
isTotals = false;
|
||||
allClasses = rt->new_<ClassesHashMap>();
|
||||
if (!allClasses || !allClasses->init()) {
|
||||
js_delete(allClasses);
|
||||
allClasses = nullptr;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
FindNotableStrings(ZoneStats &zStats)
|
||||
{
|
||||
|
@ -482,18 +566,39 @@ FindNotableStrings(ZoneStats &zStats)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ZoneStats::initStrings(JSRuntime *rt)
|
||||
static bool
|
||||
FindNotableClasses(CompartmentStats &cStats)
|
||||
{
|
||||
isTotals = false;
|
||||
allStrings = rt->new_<StringsHashMap>();
|
||||
if (!allStrings)
|
||||
return false;
|
||||
if (!allStrings->init()) {
|
||||
js_delete(allStrings);
|
||||
allStrings = nullptr;
|
||||
return false;
|
||||
using namespace JS;
|
||||
|
||||
// We should only run FindNotableClasses once per ZoneStats object.
|
||||
MOZ_ASSERT(cStats.notableClasses.empty());
|
||||
|
||||
for (CompartmentStats::ClassesHashMap::Range r = cStats.allClasses->all();
|
||||
!r.empty();
|
||||
r.popFront())
|
||||
{
|
||||
const char *className = r.front().key();
|
||||
ClassInfo &info = r.front().value();
|
||||
|
||||
// If this class isn't notable, or if we can't grow the notableStrings
|
||||
// vector, skip this string.
|
||||
if (!info.isNotable())
|
||||
continue;
|
||||
|
||||
if (!cStats.notableClasses.growBy(1))
|
||||
return false;
|
||||
|
||||
cStats.notableClasses.back() = NotableClassInfo(className, info);
|
||||
|
||||
// We're moving this class from a non-notable to a notable bucket, so
|
||||
// subtract it out of the non-notable tallies.
|
||||
cStats.classInfo.subtract(info);
|
||||
}
|
||||
// Delete |allClasses| now, rather than waiting for zStats's destruction,
|
||||
// to reduce peak memory consumption during reporting.
|
||||
js_delete(cStats.allClasses);
|
||||
cStats.allClasses = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -577,11 +682,21 @@ JS::CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisit
|
|||
|
||||
MOZ_ASSERT(!zTotals.allStrings);
|
||||
|
||||
for (size_t i = 0; i < rtStats->compartmentStatsVector.length(); i++) {
|
||||
CompartmentStats &cStats = rtStats->compartmentStatsVector[i];
|
||||
rtStats->cTotals.add(cStats);
|
||||
CompartmentStatsVector &cs = rtStats->compartmentStatsVector;
|
||||
CompartmentStats &cTotals = rtStats->cTotals;
|
||||
|
||||
// As with the zones, we sum all compartments first, and then get the
|
||||
// notable classes within each zone.
|
||||
for (size_t i = 0; i < cs.length(); i++)
|
||||
cTotals.addSizes(cs[i]);
|
||||
|
||||
for (size_t i = 0; i < cs.length(); i++) {
|
||||
if (!FindNotableClasses(cs[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!cTotals.allClasses);
|
||||
|
||||
rtStats->gcHeapGCThings = rtStats->zTotals.sizeOfLiveGCThings() +
|
||||
rtStats->cTotals.sizeOfLiveGCThings();
|
||||
|
||||
|
@ -685,10 +800,8 @@ AddSizeOfTab(JSRuntime *rt, HandleObject obj, MallocSizeOf mallocSizeOf, ObjectP
|
|||
JS_ASSERT(rtStats.zoneStatsVector.length() == 1);
|
||||
rtStats.zTotals.addSizes(rtStats.zoneStatsVector[0]);
|
||||
|
||||
for (size_t i = 0; i < rtStats.compartmentStatsVector.length(); i++) {
|
||||
CompartmentStats &cStats = rtStats.compartmentStatsVector[i];
|
||||
rtStats.cTotals.add(cStats);
|
||||
}
|
||||
for (size_t i = 0; i < rtStats.compartmentStatsVector.length(); i++)
|
||||
rtStats.cTotals.addSizes(rtStats.compartmentStatsVector[i]);
|
||||
|
||||
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
|
||||
comp->compartmentStats = nullptr;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "gc/Marking.h"
|
||||
#include "gc/Rooting.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "vm/PropDesc.h"
|
||||
|
||||
|
@ -719,12 +720,17 @@ class Shape : public gc::BarrieredCell<Shape>
|
|||
ShapeTable &table() const { return base()->table(); }
|
||||
|
||||
void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
||||
size_t *propTableSize, size_t *kidsSize) const {
|
||||
if (hasTable())
|
||||
*propTableSize += table().sizeOfIncludingThis(mallocSizeOf);
|
||||
JS::ClassInfo *info) const
|
||||
{
|
||||
if (hasTable()) {
|
||||
if (inDictionary())
|
||||
info->shapesMallocHeapDictTables += table().sizeOfIncludingThis(mallocSizeOf);
|
||||
else
|
||||
info->shapesMallocHeapTreeTables += table().sizeOfIncludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
if (!inDictionary() && kids.isHash())
|
||||
*kidsSize += kids.toHash()->sizeOfIncludingThis(mallocSizeOf);
|
||||
info->shapesMallocHeapTreeKids += kids.toHash()->sizeOfIncludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
bool isNative() const {
|
||||
|
|
|
@ -2012,6 +2012,109 @@ ReportZoneStats(const JS::ZoneStats &zStats,
|
|||
# undef STRING_LENGTH
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ReportClassStats(const ClassInfo &classInfo, const nsACString &path,
|
||||
nsIHandleReportCallback *cb, nsISupports *closure,
|
||||
size_t &gcTotal)
|
||||
{
|
||||
// We deliberately don't use ZCREPORT_BYTES, so that these per-class values
|
||||
// don't go into sundries.
|
||||
|
||||
if (classInfo.objectsGCHeap > 0) {
|
||||
REPORT_GC_BYTES(path + NS_LITERAL_CSTRING("objects/gc-heap"),
|
||||
classInfo.objectsGCHeap,
|
||||
"Objects, including fixed slots.");
|
||||
}
|
||||
|
||||
if (classInfo.objectsMallocHeapSlots > 0) {
|
||||
REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/malloc-heap/slots"),
|
||||
KIND_HEAP, classInfo.objectsMallocHeapSlots,
|
||||
"Non-fixed object slots.");
|
||||
}
|
||||
|
||||
if (classInfo.objectsMallocHeapElementsNonAsmJS > 0) {
|
||||
REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/malloc-heap/elements/non-asm.js"),
|
||||
KIND_HEAP, classInfo.objectsMallocHeapElementsNonAsmJS,
|
||||
"Non-asm.js indexed elements.");
|
||||
}
|
||||
|
||||
// asm.js arrays are heap-allocated on some platforms and
|
||||
// non-heap-allocated on others. We never put them under sundries,
|
||||
// because (a) in practice they're almost always larger than the sundries
|
||||
// threshold, and (b) we'd need a third category of sundries ("non-heap"),
|
||||
// which would be a pain.
|
||||
size_t mallocHeapElementsAsmJS = classInfo.objectsMallocHeapElementsAsmJS;
|
||||
size_t nonHeapElementsAsmJS = classInfo.objectsNonHeapElementsAsmJS;
|
||||
MOZ_ASSERT(mallocHeapElementsAsmJS == 0 || nonHeapElementsAsmJS == 0);
|
||||
if (mallocHeapElementsAsmJS > 0) {
|
||||
REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/malloc-heap/elements/asm.js"),
|
||||
KIND_HEAP, mallocHeapElementsAsmJS,
|
||||
"asm.js array buffer elements on the malloc heap.");
|
||||
}
|
||||
if (nonHeapElementsAsmJS > 0) {
|
||||
REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/non-heap/elements/asm.js"),
|
||||
KIND_NONHEAP, nonHeapElementsAsmJS,
|
||||
"asm.js array buffer elements outside both the malloc heap and "
|
||||
"the GC heap.");
|
||||
}
|
||||
|
||||
if (classInfo.objectsNonHeapElementsMapped > 0) {
|
||||
REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/non-heap/elements/mapped"),
|
||||
KIND_NONHEAP, classInfo.objectsNonHeapElementsMapped,
|
||||
"Memory-mapped array buffer elements.");
|
||||
}
|
||||
|
||||
if (classInfo.objectsNonHeapCodeAsmJS > 0) {
|
||||
REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/non-heap/code/asm.js"),
|
||||
KIND_NONHEAP, classInfo.objectsNonHeapCodeAsmJS,
|
||||
"AOT-compiled asm.js code.");
|
||||
}
|
||||
|
||||
if (classInfo.objectsMallocHeapMisc > 0) {
|
||||
REPORT_BYTES(path + NS_LITERAL_CSTRING("objects/malloc-heap/misc"),
|
||||
KIND_HEAP, classInfo.objectsMallocHeapMisc,
|
||||
"Miscellaneous object data.");
|
||||
}
|
||||
|
||||
if (classInfo.shapesGCHeapTree > 0) {
|
||||
REPORT_GC_BYTES(path + NS_LITERAL_CSTRING("shapes/gc-heap/tree"),
|
||||
classInfo.shapesGCHeapTree,
|
||||
"Shapes in a property tree.");
|
||||
}
|
||||
|
||||
if (classInfo.shapesGCHeapDict > 0) {
|
||||
REPORT_GC_BYTES(path + NS_LITERAL_CSTRING("shapes/gc-heap/dict"),
|
||||
classInfo.shapesGCHeapDict,
|
||||
"Shapes in dictionary mode.");
|
||||
}
|
||||
|
||||
if (classInfo.shapesGCHeapBase > 0) {
|
||||
REPORT_GC_BYTES(path + NS_LITERAL_CSTRING("shapes/gc-heap/base"),
|
||||
classInfo.shapesGCHeapBase,
|
||||
"Base shapes, which collate data common to many shapes.");
|
||||
}
|
||||
|
||||
if (classInfo.shapesMallocHeapTreeTables > 0) {
|
||||
REPORT_BYTES(path + NS_LITERAL_CSTRING("shapes/malloc-heap/tree-tables"),
|
||||
KIND_HEAP, classInfo.shapesMallocHeapTreeTables,
|
||||
"Property tables of shapes in a property tree.");
|
||||
}
|
||||
|
||||
if (classInfo.shapesMallocHeapDictTables > 0) {
|
||||
REPORT_BYTES(path + NS_LITERAL_CSTRING("shapes/malloc-heap/dict-tables"),
|
||||
KIND_HEAP, classInfo.shapesMallocHeapDictTables,
|
||||
"Property tables of shapes in dictionary mode.");
|
||||
}
|
||||
|
||||
if (classInfo.shapesMallocHeapTreeKids > 0) {
|
||||
REPORT_BYTES(path + NS_LITERAL_CSTRING("shapes/malloc-heap/tree-kids"),
|
||||
KIND_HEAP, classInfo.shapesMallocHeapTreeKids,
|
||||
"Kid hashes of shapes in a property tree.");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ReportCompartmentStats(const JS::CompartmentStats &cStats,
|
||||
const xpc::CompartmentStatsExtras &extras,
|
||||
|
@ -2024,6 +2127,9 @@ ReportCompartmentStats(const JS::CompartmentStats &cStats,
|
|||
size_t gcTotal = 0, sundriesGCHeap = 0, sundriesMallocHeap = 0;
|
||||
nsAutoCString cJSPathPrefix = extras.jsPathPrefix;
|
||||
nsAutoCString cDOMPathPrefix = extras.domPathPrefix;
|
||||
nsresult rv;
|
||||
|
||||
MOZ_ASSERT(!gcTotalOut == cStats.isTotals);
|
||||
|
||||
// Only attempt to prefix if we got a location and the path wasn't already
|
||||
// prefixed.
|
||||
|
@ -2044,26 +2150,25 @@ ReportCompartmentStats(const JS::CompartmentStats &cStats,
|
|||
}
|
||||
}
|
||||
|
||||
ZCREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/gc-heap/ordinary"),
|
||||
cStats.objectsGCHeapOrdinary,
|
||||
"Ordinary objects, i.e. not otherwise distinguished by memory "
|
||||
"reporters.");
|
||||
nsCString nonNotablePath = cJSPathPrefix;
|
||||
nonNotablePath += cStats.isTotals
|
||||
? NS_LITERAL_CSTRING("classes/")
|
||||
: NS_LITERAL_CSTRING("classes/class(<non-notable classes>)/");
|
||||
|
||||
ZCREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/gc-heap/function"),
|
||||
cStats.objectsGCHeapFunction,
|
||||
"Function objects.");
|
||||
rv = ReportClassStats(cStats.classInfo, nonNotablePath, cb, closure,
|
||||
gcTotal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
ZCREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/gc-heap/dense-array"),
|
||||
cStats.objectsGCHeapDenseArray,
|
||||
"Dense array objects.");
|
||||
for (size_t i = 0; i < cStats.notableClasses.length(); i++) {
|
||||
MOZ_ASSERT(!cStats.isTotals);
|
||||
const JS::NotableClassInfo& classInfo = cStats.notableClasses[i];
|
||||
|
||||
ZCREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/gc-heap/slow-array"),
|
||||
cStats.objectsGCHeapSlowArray,
|
||||
"Slow array objects.");
|
||||
nsCString classPath = cJSPathPrefix +
|
||||
nsPrintfCString("classes/class(%s)/", classInfo.className_);
|
||||
|
||||
ZCREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/gc-heap/cross-compartment-wrapper"),
|
||||
cStats.objectsGCHeapCrossCompartmentWrapper,
|
||||
"Cross-compartment wrapper objects.");
|
||||
rv = ReportClassStats(classInfo, classPath, cb, closure, gcTotal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Note that we use cDOMPathPrefix here. This is because we measure orphan
|
||||
// DOM nodes in the JS reporter, but we want to report them in a "dom"
|
||||
|
@ -2073,41 +2178,6 @@ ReportCompartmentStats(const JS::CompartmentStats &cStats,
|
|||
"Orphan DOM nodes, i.e. those that are only reachable from JavaScript "
|
||||
"objects.");
|
||||
|
||||
ZCREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("shapes/gc-heap/tree/global-parented"),
|
||||
cStats.shapesGCHeapTreeGlobalParented,
|
||||
"Shapes that (a) are in a property tree, and (b) represent an object "
|
||||
"whose parent is the global object.");
|
||||
|
||||
ZCREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("shapes/gc-heap/tree/non-global-parented"),
|
||||
cStats.shapesGCHeapTreeNonGlobalParented,
|
||||
"Shapes that (a) are in a property tree, and (b) represent an object "
|
||||
"whose parent is not the global object.");
|
||||
|
||||
ZCREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("shapes/gc-heap/dict"),
|
||||
cStats.shapesGCHeapDict,
|
||||
"Shapes that are in dictionary mode.");
|
||||
|
||||
ZCREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("shapes/gc-heap/base"),
|
||||
cStats.shapesGCHeapBase,
|
||||
"Base shapes, which collate data common to many shapes.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("shapes/malloc-heap/tree-tables"),
|
||||
cStats.shapesMallocHeapTreeTables,
|
||||
"Property tables belonging to shapes that are in a property tree.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("shapes/malloc-heap/dict-tables"),
|
||||
cStats.shapesMallocHeapDictTables,
|
||||
"Property tables that belong to shapes that are in dictionary mode.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("shapes/malloc-heap/tree-shape-kids"),
|
||||
cStats.shapesMallocHeapTreeShapeKids,
|
||||
"Kid hashes that belong to shapes that are in a property tree.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("shapes/malloc-heap/compartment-tables"),
|
||||
cStats.shapesMallocHeapCompartmentTables,
|
||||
"Compartment-wide tables storing shape information used during object "
|
||||
"construction.");
|
||||
|
||||
ZCREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("scripts/gc-heap"),
|
||||
cStats.scriptsGCHeap,
|
||||
"JSScript instances. There is one per user-defined function in a "
|
||||
|
@ -2149,6 +2219,10 @@ ReportCompartmentStats(const JS::CompartmentStats &cStats,
|
|||
cStats.compartmentObject,
|
||||
"The JSCompartment object itself.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("compartment-tables"),
|
||||
cStats.compartmentTables,
|
||||
"Compartment-wide tables storing shape and type object information.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("cross-compartment-wrapper-table"),
|
||||
cStats.crossCompartmentWrappersTable,
|
||||
"The cross-compartment wrapper table.");
|
||||
|
@ -2161,64 +2235,6 @@ ReportCompartmentStats(const JS::CompartmentStats &cStats,
|
|||
cStats.debuggeesSet,
|
||||
"The debuggees set.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/malloc-heap/slots"),
|
||||
cStats.objectsExtra.mallocHeapSlots,
|
||||
"Non-fixed object slot arrays, which represent object properties.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/malloc-heap/elements/non-asm.js"),
|
||||
cStats.objectsExtra.mallocHeapElementsNonAsmJS,
|
||||
"Non-asm.js indexed elements.");
|
||||
|
||||
// asm.js arrays are heap-allocated on some platforms and
|
||||
// non-heap-allocated on others. We never put them under sundries,
|
||||
// because (a) in practice they're almost always larger than the sundries
|
||||
// threshold, and (b) we'd need a third category of sundries ("non-heap"),
|
||||
// which would be a pain.
|
||||
size_t mallocHeapElementsAsmJS = cStats.objectsExtra.mallocHeapElementsAsmJS;
|
||||
size_t nonHeapElementsAsmJS = cStats.objectsExtra.nonHeapElementsAsmJS;
|
||||
MOZ_ASSERT(mallocHeapElementsAsmJS == 0 || nonHeapElementsAsmJS == 0);
|
||||
if (mallocHeapElementsAsmJS > 0) {
|
||||
REPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/malloc-heap/elements/asm.js"),
|
||||
KIND_HEAP, mallocHeapElementsAsmJS,
|
||||
"asm.js array buffer elements on the malloc heap.");
|
||||
}
|
||||
if (nonHeapElementsAsmJS > 0) {
|
||||
REPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/non-heap/elements/asm.js"),
|
||||
KIND_NONHEAP, nonHeapElementsAsmJS,
|
||||
"asm.js array buffer elements outside both the malloc heap and "
|
||||
"the GC heap.");
|
||||
}
|
||||
|
||||
if (cStats.objectsExtra.nonHeapElementsMapped > 0) {
|
||||
REPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/non-heap/elements/mapped"),
|
||||
KIND_NONHEAP, cStats.objectsExtra.nonHeapElementsMapped,
|
||||
"Memory-mapped array buffer elements.");
|
||||
}
|
||||
|
||||
REPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/non-heap/code/asm.js"),
|
||||
KIND_NONHEAP, cStats.objectsExtra.nonHeapCodeAsmJS,
|
||||
"AOT-compiled asm.js code.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/malloc-heap/asm.js-module-data"),
|
||||
cStats.objectsExtra.mallocHeapAsmJSModuleData,
|
||||
"asm.js module data.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/malloc-heap/arguments-data"),
|
||||
cStats.objectsExtra.mallocHeapArgumentsData,
|
||||
"Data belonging to Arguments objects.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/malloc-heap/regexp-statics"),
|
||||
cStats.objectsExtra.mallocHeapRegExpStatics,
|
||||
"Data belonging to the RegExpStatics object.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/malloc-heap/property-iterator-data"),
|
||||
cStats.objectsExtra.mallocHeapPropertyIteratorData,
|
||||
"Data belonging to property iterator objects.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/malloc-heap/ctypes-data"),
|
||||
cStats.objectsExtra.mallocHeapCtypesData,
|
||||
"Data belonging to ctypes objects.");
|
||||
|
||||
if (sundriesGCHeap > 0) {
|
||||
// We deliberately don't use ZCREPORT_GC_BYTES here.
|
||||
REPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("sundries/gc-heap"),
|
||||
|
@ -2288,9 +2304,10 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
|
|||
}
|
||||
|
||||
for (size_t i = 0; i < rtStats.compartmentStatsVector.length(); i++) {
|
||||
JS::CompartmentStats cStats = rtStats.compartmentStatsVector[i];
|
||||
const JS::CompartmentStats &cStats = rtStats.compartmentStatsVector[i];
|
||||
const xpc::CompartmentStatsExtras *extras =
|
||||
static_cast<const xpc::CompartmentStatsExtras*>(cStats.extra);
|
||||
|
||||
rv = ReportCompartmentStats(cStats, *extras, addonManager, cb, closure,
|
||||
&gcTotal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
Загрузка…
Ссылка в новой задаче