Bug 571249 - Add memory reporters for JSScripts, non-fixed object slot arrays, and string chars. r=igor.

This commit is contained in:
Nicholas Nethercote 2011-06-16 13:01:04 +10:00
Родитель 012fd6ce4c
Коммит 642276f276
5 изменённых файлов: 152 добавлений и 9 удалений

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

@ -1258,7 +1258,7 @@ typedef void (*IterateCallback)(JSContext *cx, void *data, size_t traceKind, voi
* selected. The mask should be constructed by ORing |TraceKindMask(...)|
* results.
*/
void
extern JS_FRIEND_API(void)
IterateCells(JSContext *cx, JSCompartment *comp, uint64 traceKindMask,
void *data, IterateCallback callback);

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

@ -320,7 +320,6 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
uint16 nClosedArgs = 0, nClosedVars = 0;
JSPrincipals *principals;
uint32 encodeable;
jssrcnote *sn;
JSSecurityCallbacks *callbacks;
uint32 scriptBits = 0;
@ -471,12 +470,8 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
nslots = (uint32)((script->staticLevel << 16) | script->nslots);
natoms = (uint32)script->atomMap.length;
/* Count the srcnotes, keeping notes pointing at the first one. */
notes = script->notes();
for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
continue;
nsrcnotes = sn - notes;
nsrcnotes++; /* room for the terminator */
nsrcnotes = script->numNotes();
if (JSScript::isValidOffset(script->objectsOffset))
nobjects = script->objects()->length;
@ -1422,6 +1417,29 @@ bad:
return NULL;
}
size_t
JSScript::totalSize()
{
return code +
length * sizeof(jsbytecode) +
numNotes() * sizeof(jssrcnote) -
(uint8 *) this;
}
/*
* Nb: srcnotes are variable-length. This function computes the number of
* srcnote *slots*, which may be greater than the number of srcnotes.
*/
uint32
JSScript::numNotes()
{
jssrcnote *sn;
jssrcnote *notes_ = notes();
for (sn = notes_; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
continue;
return sn - notes_ + 1; /* +1 for the terminator */
}
JS_FRIEND_API(void)
js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
{

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

@ -458,16 +458,17 @@ struct JSScript {
private:
uint16 version; /* JS version under which script was compiled */
size_t callCount_; /* Number of times the script has been called. */
public:
uint16 nfixed; /* number of slots besides stack operands in
slot array */
private:
size_t callCount_; /* Number of times the script has been called. */
/*
* Offsets to various array structures from the end of this script, or
* JSScript::INVALID_OFFSET if the array has length 0.
*/
public:
uint8 objectsOffset; /* offset to the array of nested function,
block, scope, xml and one-time regexps
objects */
@ -576,6 +577,9 @@ struct JSScript {
}
#endif
JS_FRIEND_API(size_t) totalSize(); /* Size of the JSScript and all sections */
uint32 numNotes(); /* Number of srcnote slots in the srcnotes section */
/* Script notes are allocated right after the code. */
jssrcnote *notes() { return (jssrcnote *)(code + length); }

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

@ -1303,6 +1303,119 @@ NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSStack,
GetJSStack,
NULL)
static PRInt64
GetCompartmentScriptsSize(JSCompartment *c)
{
PRInt64 n = 0;
for (JSScript *script = (JSScript *)c->scripts.next;
&script->links != &c->scripts;
script = (JSScript *)script->links.next)
{
n += script->totalSize();
}
return n;
}
static PRInt64
GetJSScripts(void *data)
{
return GetPerCompartmentSize(GetCompartmentScriptsSize);
}
struct PRInt64Data {
PRInt64Data() : n(0) { }
PRInt64 n;
};
void
GetJSObjectSlotsCallback(JSContext *cx, void *v, size_t traceKind, void *thing)
{
JS_ASSERT(traceKind == JSTRACE_OBJECT);
JSObject *obj = (JSObject *)thing;
if (obj->hasSlotsArray()) {
PRInt64Data *data = (PRInt64Data *) v;
data->n += obj->numSlots() * sizeof(js::Value);
}
}
static PRInt64
GetJSObjectSlots(void *dummy)
{
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
JSContext *cx = JS_NewContext(rt, 0);
if (!cx) {
NS_ERROR("couldn't create context for memory tracing");
return (PRInt64) -1;
}
PRInt64Data data;
js::IterateCells(cx, NULL, js::TraceKindMask(JSTRACE_OBJECT), &data,
*GetJSObjectSlotsCallback);
JS_DestroyContextNoGC(cx);
return data.n;
}
void
GetJSStringCharsCallback(JSContext *cx, void *v, size_t traceKind, void *thing)
{
JS_ASSERT(traceKind == JSTRACE_STRING);
JSString *str = (JSString *)thing;
PRInt64Data *data = (PRInt64Data *) v;
data->n += str->charsHeapSize();
}
static PRInt64
GetJSStringChars(void *dummy)
{
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
JSContext *cx = JS_NewContext(rt, 0);
if (!cx) {
NS_ERROR("couldn't create context for memory tracing");
return (PRInt64) -1;
}
PRInt64Data data;
js::IterateCells(cx, NULL, js::TraceKindMask(JSTRACE_STRING), &data,
*GetJSStringCharsCallback);
JS_DestroyContextNoGC(cx);
return data.n;
}
NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSScripts,
"explicit/js/scripts",
MR_HEAP,
"Memory allocated for JSScripts. A JSScript is created for each "
"user-defined function in a script. One is also created for "
"the top-level code in a script. Each JSScript includes byte-code and "
"various other things.",
GetJSScripts,
NULL)
NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSObjectSlots,
"explicit/js/object-slots",
MR_HEAP,
"Memory allocated for non-fixed object slot arrays, which are used "
"to represent object properties. Some objects also contain a fixed "
"number of slots which are stored on the JavaScript heap; those slots "
"are not counted here.",
GetJSObjectSlots,
NULL)
NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSStringChars,
"explicit/js/string-chars",
MR_HEAP,
"Memory allocated to hold string characters. Not all of this allocated "
"memory is necessarily used to hold characters. Each string also "
"includes a header which is stored on the JavaScript heap; that header "
"is not counted here.",
GetJSStringChars,
NULL)
#ifdef JS_METHODJIT
static PRInt64
@ -1476,6 +1589,10 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSStack));
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSScripts));
// XXX: these two are disabled due to crashes. See bug 664647.
//NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSObjectSlots));
//NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSStringChars));
#ifdef JS_METHODJIT
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSMjitCode));
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSMjitData));

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

@ -21,8 +21,12 @@
// Remove all the real reporters; save them to restore at the end.
var e = mgr.enumerateReporters();
var realReporters = [];
var dummy = 0;
while (e.hasMoreElements()) {
var mr = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
// Get the memoryUsed field, even though we don't use it, just to test
// that the reporter doesn't crash or anything.
dummy += mr.memoryUsed;
mgr.unregisterReporter(mr);
realReporters.push(mr);
}