Bug 722595 - Add memory reporters for misc things hanging off JS objects. r=bhackett.

--HG--
extra : rebase_source : 211b35134923f4cb99625bb240b96e81f0f28b4b
This commit is contained in:
Nicholas Nethercote 2012-01-30 18:12:03 -08:00
parent 9f28cf3032
commit a1ab9492f5
14 changed files with 106 additions and 36 deletions

View File

@ -102,6 +102,7 @@ struct CompartmentStats
size_t objectSlots;
size_t objectElements;
size_t objectMisc;
size_t stringChars;
size_t shapesExtraTreeTables;
size_t shapesExtraDictTables;

View File

@ -126,10 +126,12 @@ CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
} else {
cStats->gcHeapObjectsNonFunction += thingSize;
}
size_t slotsSize, elementsSize;
obj->sizeOfExcludingThis(rtStats->mallocSizeOf, &slotsSize, &elementsSize);
size_t slotsSize, elementsSize, miscSize;
obj->sizeOfExcludingThis(rtStats->mallocSizeOf, &slotsSize,
&elementsSize, &miscSize);
cStats->objectSlots += slotsSize;
cStats->objectElements += elementsSize;
cStats->objectMisc += miscSize;
break;
}
case JSTRACE_STRING:
@ -262,7 +264,8 @@ CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats)
rtStats->totalObjects += cStats.gcHeapObjectsNonFunction +
cStats.gcHeapObjectsFunction +
cStats.objectSlots +
cStats.objectElements;
cStats.objectElements +
cStats.objectMisc;
rtStats->totalShapes += cStats.gcHeapShapesTree +
cStats.gcHeapShapesDict +
cStats.gcHeapShapesBase +

View File

@ -978,7 +978,7 @@ JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
JS_PUBLIC_API(size_t)
JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
{
return obj->computedSizeOfIncludingThis();
return obj->computedSizeOfThisSlotsElements();
}
static size_t

View File

@ -1469,6 +1469,14 @@ fun_finalize(JSContext *cx, JSObject *obj)
obj->toFunction()->finalizeUpvars();
}
size_t
JSFunction::sizeOfMisc(JSMallocSizeOfFun mallocSizeOf) const
{
return (isFlatClosure() && hasFlatClosureUpvars()) ?
mallocSizeOf(getFlatClosureUpvars()) :
0;
}
/*
* Reserve two slots in all function objects for XPConnect. Note that this
* does not bloat every instance, only those on which reserved slots are set,

View File

@ -290,6 +290,12 @@ struct JSFunction : public JSObject
inline JSAtom *methodAtom() const;
inline void setMethodAtom(JSAtom *atom);
/*
* Measures things hanging off this JSFunction that are counted by the
* |miscSize| argument in JSObject::sizeOfExcludingThis().
*/
size_t sizeOfMisc(JSMallocSizeOfFun mallocSizeOf) const;
private:
/*
* These member functions are inherited from JSObject, but should never be applied to

View File

@ -4119,7 +4119,7 @@ JSObject::growSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount)
*/
JS_ASSERT(newCount < NELEMENTS_LIMIT);
size_t oldSize = Probes::objectResizeActive() ? computedSizeOfIncludingThis() : 0;
size_t oldSize = Probes::objectResizeActive() ? computedSizeOfThisSlotsElements() : 0;
size_t newSize = oldSize + (newCount - oldCount) * sizeof(Value);
/*
@ -4188,7 +4188,7 @@ JSObject::shrinkSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount)
if (isCall())
return;
size_t oldSize = Probes::objectResizeActive() ? computedSizeOfIncludingThis() : 0;
size_t oldSize = Probes::objectResizeActive() ? computedSizeOfThisSlotsElements() : 0;
size_t newSize = oldSize - (oldCount - newCount) * sizeof(Value);
if (newCount == 0) {
@ -4234,7 +4234,7 @@ JSObject::growElements(JSContext *cx, uintN newcap)
uint32_t oldcap = getDenseArrayCapacity();
JS_ASSERT(oldcap <= newcap);
size_t oldSize = Probes::objectResizeActive() ? computedSizeOfIncludingThis() : 0;
size_t oldSize = Probes::objectResizeActive() ? computedSizeOfThisSlotsElements() : 0;
uint32_t nextsize = (oldcap <= CAPACITY_DOUBLING_MAX)
? oldcap * 2
@ -4277,7 +4277,7 @@ JSObject::growElements(JSContext *cx, uintN newcap)
Debug_SetValueRangeToCrashOnTouch(elements + initlen, actualCapacity - initlen);
if (Probes::objectResizeActive())
Probes::resizeObject(cx, this, oldSize, computedSizeOfIncludingThis());
Probes::resizeObject(cx, this, oldSize, computedSizeOfThisSlotsElements());
return true;
}
@ -4290,7 +4290,7 @@ JSObject::shrinkElements(JSContext *cx, uintN newcap)
uint32_t oldcap = getDenseArrayCapacity();
JS_ASSERT(newcap <= oldcap);
size_t oldSize = Probes::objectResizeActive() ? computedSizeOfIncludingThis() : 0;
size_t oldSize = Probes::objectResizeActive() ? computedSizeOfThisSlotsElements() : 0;
/* Don't shrink elements below the minimum capacity. */
if (oldcap <= SLOT_CAPACITY_MIN || !hasDynamicElements())
@ -4309,7 +4309,7 @@ JSObject::shrinkElements(JSContext *cx, uintN newcap)
elements = newheader->elements();
if (Probes::objectResizeActive())
Probes::resizeObject(cx, this, oldSize, computedSizeOfIncludingThis());
Probes::resizeObject(cx, this, oldSize, computedSizeOfThisSlotsElements());
}
#ifdef DEBUG

View File

@ -363,6 +363,7 @@ extern Class NormalArgumentsObjectClass;
extern Class ObjectClass;
extern Class ProxyClass;
extern Class RegExpClass;
extern Class RegExpStaticsClass;
extern Class SlowArrayClass;
extern Class StopIterationClass;
extern Class StringClass;
@ -672,11 +673,11 @@ struct JSObject : js::gc::Cell
inline bool hasPropertyTable() const;
inline size_t sizeOfThis() const;
inline size_t computedSizeOfIncludingThis() const;
inline size_t computedSizeOfThisSlotsElements() const;
/* mallocSizeOf can be NULL, in which case we compute the sizes analytically */
inline void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf,
size_t *slotsSize, size_t *elementsSize) const;
size_t *slotsSize, size_t *elementsSize,
size_t *miscSize) const;
inline size_t numFixedSlots() const;
@ -1416,6 +1417,7 @@ struct JSObject : js::gc::Cell
inline bool isPrimitive() const;
inline bool isProxy() const;
inline bool isRegExp() const;
inline bool isRegExpStatics() const;
inline bool isScope() const;
inline bool isScript() const;
inline bool isSlowArray() const;
@ -1448,6 +1450,7 @@ struct JSObject : js::gc::Cell
inline bool isCrossCompartmentWrapper() const;
inline js::ArgumentsObject &asArguments();
inline const js::ArgumentsObject &asArguments() const;
inline js::BlockObject &asBlock();
inline js::BooleanObject &asBoolean();
inline js::CallObject &asCall();

View File

@ -66,6 +66,7 @@
#include "gc/Barrier.h"
#include "js/TemplateLib.h"
#include "vm/GlobalObject.h"
#include "vm/RegExpStatics.h"
#include "jsatominlines.h"
#include "jsfuninlines.h"
@ -76,6 +77,7 @@
#include "gc/Barrier-inl.h"
#include "vm/String-inl.h"
#include "vm/RegExpStatics-inl.h"
inline bool
JSObject::hasPrivate() const
@ -936,6 +938,7 @@ inline bool JSObject::isNumber() const { return hasClass(&js::NumberClass); }
inline bool JSObject::isObject() const { return hasClass(&js::ObjectClass); }
inline bool JSObject::isPrimitive() const { return isNumber() || isString() || isBoolean(); }
inline bool JSObject::isRegExp() const { return hasClass(&js::RegExpClass); }
inline bool JSObject::isRegExpStatics() const { return hasClass(&js::RegExpStaticsClass); }
inline bool JSObject::isScope() const { return isCall() || isDeclEnv() || isNestedScope(); }
inline bool JSObject::isStaticBlock() const { return isBlock() && !getProto(); }
inline bool JSObject::isStopIteration() const { return hasClass(&js::StopIterationClass); }
@ -1208,31 +1211,43 @@ JSObject::sizeOfThis() const
}
inline size_t
JSObject::computedSizeOfIncludingThis() const
JSObject::computedSizeOfThisSlotsElements() const
{
size_t slotsSize, elementsSize;
sizeOfExcludingThis(NULL, &slotsSize, &elementsSize);
return sizeOfThis() + slotsSize + elementsSize;
size_t n = sizeOfThis();
if (hasDynamicSlots())
n += numDynamicSlots() * sizeof(js::Value);
if (hasDynamicElements())
n += (js::ObjectElements::VALUES_PER_HEADER + getElementsHeader()->capacity) *
sizeof(js::Value);
return n;
}
inline void
JSObject::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf,
size_t *slotsSize, size_t *elementsSize) const
size_t *slotsSize, size_t *elementsSize,
size_t *miscSize) const
{
*slotsSize = 0;
if (hasDynamicSlots()) {
size_t computedSize = numDynamicSlots() * sizeof(js::Value);
*slotsSize = mallocSizeOf ? mallocSizeOf(slots) : computedSize;
} else {
*slotsSize = 0;
*slotsSize += mallocSizeOf(slots);
}
*elementsSize = 0;
if (hasDynamicElements()) {
size_t computedSize =
(js::ObjectElements::VALUES_PER_HEADER +
getElementsHeader()->capacity) * sizeof(js::Value);
*elementsSize =
mallocSizeOf ? mallocSizeOf(getElementsHeader()) : computedSize;
} else {
*elementsSize = 0;
*elementsSize += mallocSizeOf(getElementsHeader());
}
/* Other things may be measured in the future if DMD indicates it is worthwhile. */
*miscSize = 0;
if (isFunction()) {
*miscSize += toFunction()->sizeOfMisc(mallocSizeOf);
} else if (isArguments()) {
*miscSize += asArguments().sizeOfMisc(mallocSizeOf);
} else if (isRegExpStatics()) {
*miscSize += js::SizeOfRegExpStaticsData(this, mallocSizeOf);
}
}

View File

@ -121,6 +121,12 @@ ArgumentsObject::setStackFrame(StackFrame *frame)
setFixedSlot(STACK_FRAME_SLOT, PrivateValue(frame));
}
inline size_t
ArgumentsObject::sizeOfMisc(JSMallocSizeOfFun mallocSizeOf) const
{
return mallocSizeOf(data());
}
inline const js::Value &
NormalArgumentsObject::callee() const
{

View File

@ -213,6 +213,12 @@ class ArgumentsObject : public JSObject
/* The stack frame for this ArgumentsObject, if the frame is still active. */
inline js::StackFrame *maybeStackFrame() const;
inline void setStackFrame(js::StackFrame *frame);
/*
* Measures things hanging off this ArgumentsObject that are counted by the
* |miscSize| argument in JSObject::sizeOfExcludingThis().
*/
inline size_t sizeOfMisc(JSMallocSizeOfFun mallocSizeOf) const;
};
class NormalArgumentsObject : public ArgumentsObject
@ -246,21 +252,28 @@ js::NormalArgumentsObject &
JSObject::asNormalArguments()
{
JS_ASSERT(isNormalArguments());
return *reinterpret_cast<js::NormalArgumentsObject *>(this);
return *static_cast<js::NormalArgumentsObject *>(this);
}
js::StrictArgumentsObject &
JSObject::asStrictArguments()
{
JS_ASSERT(isStrictArguments());
return *reinterpret_cast<js::StrictArgumentsObject *>(this);
return *static_cast<js::StrictArgumentsObject *>(this);
}
js::ArgumentsObject &
JSObject::asArguments()
{
JS_ASSERT(isArguments());
return *reinterpret_cast<js::ArgumentsObject *>(this);
return *static_cast<js::ArgumentsObject *>(this);
}
const js::ArgumentsObject &
JSObject::asArguments() const
{
JS_ASSERT(isArguments());
return *static_cast<const js::ArgumentsObject *>(this);
}
#endif /* ArgumentsObject_h___ */

View File

@ -54,6 +54,12 @@ js::GlobalObject::getRegExpStatics() const
return static_cast<RegExpStatics *>(resObj.getPrivate());
}
inline size_t
SizeOfRegExpStaticsData(const JSObject *obj, JSMallocSizeOfFun mallocSizeOf)
{
return mallocSizeOf(obj->getPrivate());
}
inline
RegExpStatics::RegExpStatics()
: bufferLink(NULL),

View File

@ -69,7 +69,7 @@ resc_trace(JSTracer *trc, JSObject *obj)
res->mark(trc);
}
static Class regexp_statics_class = {
Class js::RegExpStaticsClass = {
"RegExpStatics",
JSCLASS_HAS_PRIVATE,
JS_PropertyStub, /* addProperty */
@ -92,7 +92,7 @@ static Class regexp_statics_class = {
JSObject *
RegExpStatics::create(JSContext *cx, GlobalObject *parent)
{
JSObject *obj = NewObjectWithGivenProto(cx, &regexp_statics_class, NULL, parent);
JSObject *obj = NewObjectWithGivenProto(cx, &RegExpStaticsClass, NULL, parent);
if (!obj)
return NULL;
RegExpStatics *res = cx->new_<RegExpStatics>();

View File

@ -261,6 +261,8 @@ class PreserveRegExpStatics
inline ~PreserveRegExpStatics();
};
size_t SizeOfRegExpStaticsData(const JSObject *obj, JSMallocSizeOfFun mallocSizeOf);
} /* namespace js */
#endif

View File

@ -1491,7 +1491,7 @@ ReportCompartmentStats(const JS::CompartmentStats &cStats,
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"object-slots"),
"objects/slots"),
nsIMemoryReporter::KIND_HEAP, cStats.objectSlots,
"Memory allocated for the compartment's non-fixed object slot arrays, "
"which are used to represent object properties. Some objects also "
@ -1501,12 +1501,19 @@ ReportCompartmentStats(const JS::CompartmentStats &cStats,
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"object-elements"),
"objects/elements"),
nsIMemoryReporter::KIND_HEAP, cStats.objectElements,
"Memory allocated for the compartment's object element arrays, "
"which are used to represent indexed object properties.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"objects/misc"),
nsIMemoryReporter::KIND_HEAP, cStats.objectMisc,
"Memory allocated for various small, miscellaneous "
"structures that hang off certain kinds of objects.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"string-chars"),
nsIMemoryReporter::KIND_HEAP, cStats.stringChars,