зеркало из https://github.com/mozilla/gecko-dev.git
Bug 571249 - Add memory reporters for JSScripts, non-fixed object slot arrays, and string chars. r=igor.
This commit is contained in:
Родитель
012fd6ce4c
Коммит
642276f276
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче