Bug 747202 - Separate and clean up JaegerMonkey's and IonMonkey's memory reporting. r=dvander.

This commit is contained in:
Nicholas Nethercote 2012-09-19 18:16:49 -07:00
Родитель 0580007f9d
Коммит 8fce2522d5
14 изменённых файлов: 114 добавлений и 86 удалений

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

@ -49,9 +49,10 @@ struct RuntimeSizes
, contexts(0)
, dtoa(0)
, temporary(0)
, mjitCode(0)
, jaegerCode(0)
, ionCode(0)
, regexpCode(0)
, unusedCodeMemory(0)
, unusedCode(0)
, stackCommitted(0)
, gcMarker(0)
, mathCache(0)
@ -65,9 +66,10 @@ struct RuntimeSizes
size_t contexts;
size_t dtoa;
size_t temporary;
size_t mjitCode;
size_t jaegerCode;
size_t ionCode;
size_t regexpCode;
size_t unusedCodeMemory;
size_t unusedCode;
size_t stackCommitted;
size_t gcMarker;
size_t mathCache;
@ -104,6 +106,7 @@ struct CompartmentStats
size_t gcHeapShapesBase;
size_t gcHeapScripts;
size_t gcHeapTypeObjects;
size_t gcHeapIonCodes;
#if JS_HAS_XML_SUPPORT
size_t gcHeapXML;
#endif
@ -118,7 +121,8 @@ struct CompartmentStats
size_t shapesExtraTreeShapeKids;
size_t shapesCompartmentTables;
size_t scriptData;
size_t mjitData;
size_t jaegerData;
size_t ionData;
size_t crossCompartmentWrappers;
TypeInferenceSizes typeInferenceSizes;
@ -138,6 +142,7 @@ struct CompartmentStats
ADD(gcHeapShapesBase);
ADD(gcHeapScripts);
ADD(gcHeapTypeObjects);
ADD(gcHeapIonCodes);
#if JS_HAS_XML_SUPPORT
ADD(gcHeapXML);
#endif
@ -152,7 +157,8 @@ struct CompartmentStats
ADD(shapesExtraTreeShapeKids);
ADD(shapesCompartmentTables);
ADD(scriptData);
ADD(mjitData);
ADD(jaegerData);
ADD(ionData);
ADD(crossCompartmentWrappers);
#undef ADD

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

@ -40,18 +40,21 @@ ExecutablePool::~ExecutablePool()
}
void
ExecutableAllocator::sizeOfCode(size_t *method, size_t *regexp, size_t *unused) const
ExecutableAllocator::sizeOfCode(size_t *jaeger, size_t *ion, size_t *regexp, size_t *unused) const
{
*method = 0;
*jaeger = 0;
*ion = 0;
*regexp = 0;
*unused = 0;
if (m_pools.initialized()) {
for (ExecPoolHashSet::Range r = m_pools.all(); !r.empty(); r.popFront()) {
ExecutablePool* pool = r.front();
*method += pool->m_mjitCodeMethod;
*regexp += pool->m_mjitCodeRegexp;
*unused += pool->m_allocation.size - pool->m_mjitCodeMethod - pool->m_mjitCodeRegexp;
*jaeger += pool->m_jaegerCodeBytes;
*ion += pool->m_ionCodeBytes;
*regexp += pool->m_regexpCodeBytes;
*unused += pool->m_allocation.size - pool->m_jaegerCodeBytes - pool->m_ionCodeBytes
- pool->m_regexpCodeBytes;
}
}
}

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

@ -82,9 +82,9 @@ namespace JSC {
class ExecutableAllocator;
enum CodeKind { METHOD_CODE, REGEXP_CODE };
enum CodeKind { JAEGER_CODE, ION_CODE, REGEXP_CODE };
// These are reference-counted. A new one starts with a count of 1.
// These are reference-counted. A new one starts with a count of 1.
class ExecutablePool {
friend class ExecutableAllocator;
@ -104,10 +104,11 @@ private:
// Reference count for automatic reclamation.
unsigned m_refCount;
// Number of bytes currently used for Method and Regexp JIT code.
size_t m_mjitCodeMethod;
size_t m_mjitCodeRegexp;
size_t m_jaegerCodeBytes;
size_t m_ionCodeBytes;
size_t m_regexpCodeBytes;
public:
// Flag for downstream use, whether to try to release references to this pool.
@ -118,7 +119,7 @@ public:
size_t m_gcNumber;
void release(bool willDestroy = false)
{
{
JS_ASSERT(m_refCount != 0);
// XXX: disabled, see bug 654820.
//JS_ASSERT_IF(willDestroy, m_refCount == 1);
@ -128,7 +129,8 @@ public:
ExecutablePool(ExecutableAllocator* allocator, Allocation a)
: m_allocator(allocator), m_freePtr(a.pages), m_end(m_freePtr + a.size), m_allocation(a),
m_refCount(1), m_mjitCodeMethod(0), m_mjitCodeRegexp(0), m_destroy(false), m_gcNumber(0)
m_refCount(1), m_jaegerCodeBytes(0), m_ionCodeBytes(0), m_regexpCodeBytes(0),
m_destroy(false), m_gcNumber(0)
{ }
~ExecutablePool();
@ -149,15 +151,16 @@ private:
void *result = m_freePtr;
m_freePtr += n;
if ( kind == REGEXP_CODE )
m_mjitCodeRegexp += n;
else
m_mjitCodeMethod += n;
switch (kind) {
case JAEGER_CODE: m_jaegerCodeBytes += n; break;
case ION_CODE: m_ionCodeBytes += n; break;
case REGEXP_CODE: m_regexpCodeBytes += n; break;
default: JS_NOT_REACHED("bad code kind"); break;
}
return result;
}
size_t available() const {
size_t available() const {
JS_ASSERT(m_end >= m_freePtr);
return m_end - m_freePtr;
}
@ -243,7 +246,7 @@ public:
m_pools.remove(m_pools.lookup(pool)); // this asserts if |pool| is not in m_pools
}
void sizeOfCode(size_t *method, size_t *regexp, size_t *unused) const;
void sizeOfCode(size_t *jaeger, size_t *ion, size_t *regexp, size_t *unused) const;
void setDestroyCallback(DestroyCallback destroyCallback) {
this->destroyCallback = destroyCallback;

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

@ -80,9 +80,6 @@ class IonCode : public gc::Cell
size_t instructionsSize() const {
return insnSize_;
}
size_t bufferSize() const {
return bufferSize_;
}
void trace(JSTracer *trc);
void finalize(FreeOp *fop);
void setInvalidated() {
@ -336,8 +333,8 @@ struct IonScript
size_t scriptEntries() const {
return scriptEntries_;
}
size_t size() const {
return scriptList_ + scriptEntries_ * sizeof(JSScript *);
size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const {
return mallocSizeOf(this);
}
HeapValue &getConstant(size_t index) {
JS_ASSERT(index < numConstants());

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

@ -40,7 +40,7 @@ class Linker
if (bytesNeeded >= MAX_BUFFER_SIZE)
return fail(cx);
uint8 *result = (uint8 *)comp->execAlloc()->alloc(bytesNeeded, &pool, JSC::METHOD_CODE);
uint8 *result = (uint8 *)comp->execAlloc()->alloc(bytesNeeded, &pool, JSC::ION_CODE);
if (!result)
return fail(cx);

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

@ -115,40 +115,44 @@ void CompartmentCallback(JSRuntime *rt, void *vdata, JSCompartment *compartment)
}
void
JSRuntime::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, RuntimeSizes *runtime)
JSRuntime::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, RuntimeSizes *rtSizes)
{
runtime->object = mallocSizeOf(this);
rtSizes->object = mallocSizeOf(this);
runtime->atomsTable = atoms.sizeOfExcludingThis(mallocSizeOf);
rtSizes->atomsTable = atoms.sizeOfExcludingThis(mallocSizeOf);
runtime->contexts = 0;
rtSizes->contexts = 0;
for (ContextIter acx(this); !acx.done(); acx.next())
runtime->contexts += acx->sizeOfIncludingThis(mallocSizeOf);
rtSizes->contexts += acx->sizeOfIncludingThis(mallocSizeOf);
runtime->dtoa = mallocSizeOf(dtoaState);
rtSizes->dtoa = mallocSizeOf(dtoaState);
runtime->temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
rtSizes->temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
if (execAlloc_)
execAlloc_->sizeOfCode(&runtime->mjitCode, &runtime->regexpCode,
&runtime->unusedCodeMemory);
else
runtime->mjitCode = runtime->regexpCode = runtime->unusedCodeMemory = 0;
if (execAlloc_) {
execAlloc_->sizeOfCode(&rtSizes->jaegerCode, &rtSizes->ionCode, &rtSizes->regexpCode,
&rtSizes->unusedCode);
} else {
rtSizes->jaegerCode = 0;
rtSizes->ionCode = 0;
rtSizes->regexpCode = 0;
rtSizes->unusedCode = 0;
}
runtime->stackCommitted = stackSpace.sizeOfCommitted();
rtSizes->stackCommitted = stackSpace.sizeOfCommitted();
runtime->gcMarker = gcMarker.sizeOfExcludingThis(mallocSizeOf);
rtSizes->gcMarker = gcMarker.sizeOfExcludingThis(mallocSizeOf);
runtime->mathCache = mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
rtSizes->mathCache = mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
runtime->scriptFilenames = scriptFilenameTable.sizeOfExcludingThis(mallocSizeOf);
rtSizes->scriptFilenames = scriptFilenameTable.sizeOfExcludingThis(mallocSizeOf);
for (ScriptFilenameTable::Range r = scriptFilenameTable.all(); !r.empty(); r.popFront())
runtime->scriptFilenames += mallocSizeOf(r.front());
rtSizes->scriptFilenames += mallocSizeOf(r.front());
runtime->compartmentObjects = 0;
rtSizes->compartmentObjects = 0;
CallbackData data(mallocSizeOf);
JS_IterateCompartments(this, &data, CompartmentCallback);
runtime->compartmentObjects = data.n;
rtSizes->compartmentObjects = data.n;
}
size_t
@ -157,9 +161,9 @@ JSRuntime::sizeOfExplicitNonHeap()
if (!execAlloc_)
return 0;
size_t mjitCode, regexpCode, unusedCodeMemory;
execAlloc_->sizeOfCode(&mjitCode, &regexpCode, &unusedCodeMemory);
return mjitCode + regexpCode + unusedCodeMemory + stackSpace.sizeOfCommitted();
size_t jaegerCode, ionCode, regexpCode, unusedCode;
execAlloc_->sizeOfCode(&jaegerCode, &ionCode, &regexpCode, &unusedCode);
return jaegerCode + ionCode + regexpCode + unusedCode + stackSpace.sizeOfCommitted();
}
void

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

@ -53,6 +53,7 @@ CompartmentStats::gcHeapThingsSize()
n += gcHeapShapesBase;
n += gcHeapScripts;
n += gcHeapTypeObjects;
n += gcHeapIonCodes;
#if JS_HAS_XML_SUPPORT
n += gcHeapXML;
#endif
@ -182,10 +183,10 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin
cStats->gcHeapScripts += thingSize;
cStats->scriptData += script->sizeOfData(rtStats->mallocSizeOf);
#ifdef JS_METHODJIT
cStats->mjitData += script->sizeOfJitScripts(rtStats->mallocSizeOf);
cStats->jaegerData += script->sizeOfJitScripts(rtStats->mallocSizeOf);
# ifdef JS_ION
if (script->hasIonScript())
cStats->mjitData += script->ion->size();
cStats->ionData += script->ion->sizeOfIncludingThis(rtStats->mallocSizeOf);
# endif
#endif
@ -201,9 +202,8 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin
{
#ifdef JS_METHODJIT
# ifdef JS_ION
ion::IonCode *code = static_cast<ion::IonCode *>(thing);
cStats->gcHeapScripts += thingSize;
cStats->mjitData += code->bufferSize();
cStats->gcHeapIonCodes += thingSize;
// The code for a script is counted in ExecutableAllocator::sizeOfCode().
# endif
#endif
break;

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

@ -170,7 +170,7 @@ class NativeStubLinker : public LinkerHelper
#endif
NativeStubLinker(Assembler &masm, JITChunk *chunk, jsbytecode *pc, FinalJump done)
: LinkerHelper(masm, JSC::METHOD_CODE), chunk(chunk), pc(pc), done(done)
: LinkerHelper(masm, JSC::JAEGER_CODE), chunk(chunk), pc(pc), done(done)
{}
bool init(JSContext *cx);

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

@ -927,7 +927,7 @@ MakeJITScript(JSContext *cx, JSScript *script)
masm.fallibleVMCall(true, JS_FUNC_TO_DATA_PTR(void *, stubs::CrossChunkShim),
pc, NULL, script->nfixed + analysis->getCode(pc).stackDepth);
}
LinkerHelper linker(masm, JSC::METHOD_CODE);
LinkerHelper linker(masm, JSC::JAEGER_CODE);
JSC::ExecutablePool *ep = linker.init(cx);
if (!ep)
return NULL;
@ -1398,7 +1398,7 @@ mjit::Compiler::finishThisUp()
JSC::ExecutableAllocator &execAlloc = cx->runtime->execAlloc();
JSC::ExecutablePool *execPool;
uint8_t *result = (uint8_t *)execAlloc.alloc(codeSize, &execPool, JSC::METHOD_CODE);
uint8_t *result = (uint8_t *)execAlloc.alloc(codeSize, &execPool, JSC::JAEGER_CODE);
if (!result) {
js_ReportOutOfMemory(cx);
return Compile_Error;
@ -1408,8 +1408,8 @@ mjit::Compiler::finishThisUp()
masm.executableCopy(result);
stubcc.masm.executableCopy(result + masm.size());
JSC::LinkBuffer fullCode(result, codeSize, JSC::METHOD_CODE);
JSC::LinkBuffer stubCode(result + masm.size(), stubcc.size(), JSC::METHOD_CODE);
JSC::LinkBuffer fullCode(result, codeSize, JSC::JAEGER_CODE);
JSC::LinkBuffer stubCode(result + masm.size(), stubcc.size(), JSC::JAEGER_CODE);
JS_ASSERT(!loop);

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

@ -173,7 +173,7 @@ class EqualityICLinker : public LinkerHelper
public:
EqualityICLinker(Assembler &masm, VMFrame &f)
: LinkerHelper(masm, JSC::METHOD_CODE), f(f)
: LinkerHelper(masm, JSC::JAEGER_CODE), f(f)
{ }
bool init(JSContext *cx) {
@ -912,7 +912,7 @@ class CallCompiler : public BaseCompiler
masm.load32(FrameAddress(VMFrame::offsetOfDynamicArgc()), JSParamReg_Argc);
masm.jump(t0);
LinkerHelper linker(masm, JSC::METHOD_CODE);
LinkerHelper linker(masm, JSC::JAEGER_CODE);
JSC::ExecutablePool *ep = poolForSize(linker, CallICInfo::Pool_ScriptStub);
if (!ep)
return false;
@ -933,7 +933,7 @@ class CallCompiler : public BaseCompiler
(unsigned long) masm.size());
if (f.regs.inlined()) {
JSC::LinkBuffer code((uint8_t *) cs.executableAddress(), masm.size(), JSC::METHOD_CODE);
JSC::LinkBuffer code((uint8_t *) cs.executableAddress(), masm.size(), JSC::JAEGER_CODE);
code.patch(inlined, f.regs.inlined());
}
@ -997,7 +997,7 @@ class CallCompiler : public BaseCompiler
ImmPtr(obj->toFunction()->script()));
Jump done = masm.jump();
LinkerHelper linker(masm, JSC::METHOD_CODE);
LinkerHelper linker(masm, JSC::JAEGER_CODE);
JSC::ExecutablePool *ep = poolForSize(linker, CallICInfo::Pool_ClosureStub);
if (!ep)
return false;
@ -1442,7 +1442,7 @@ ic::GenerateArgumentCheckStub(VMFrame &f)
Jump done = masm.jump();
LinkerHelper linker(masm, JSC::METHOD_CODE);
LinkerHelper linker(masm, JSC::JAEGER_CODE);
JSC::ExecutablePool *ep = linker.init(f.cx);
if (!ep)
return;

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

@ -46,7 +46,7 @@ class PICLinker : public LinkerHelper
public:
PICLinker(Assembler &masm, ic::BasePolyIC &ic)
: LinkerHelper(masm, JSC::METHOD_CODE), ic(ic)
: LinkerHelper(masm, JSC::JAEGER_CODE), ic(ic)
{ }
bool init(JSContext *cx) {
@ -2795,7 +2795,7 @@ SetElementIC::attachHoleStub(VMFrame &f, JSObject *obj, int32_t keyval)
JS_ASSERT(!execPool);
JS_ASSERT(!inlineHoleGuardPatched);
LinkerHelper buffer(masm, JSC::METHOD_CODE);
LinkerHelper buffer(masm, JSC::JAEGER_CODE);
execPool = buffer.init(cx);
if (!execPool)
return error(cx);
@ -2884,7 +2884,7 @@ SetElementIC::attachTypedArray(VMFrame &f, JSObject *obj, int32_t key)
// by a GC or shape regenerated GC. We let this stub live for the lifetime
// of the script.
JS_ASSERT(!execPool);
LinkerHelper buffer(masm, JSC::METHOD_CODE);
LinkerHelper buffer(masm, JSC::JAEGER_CODE);
execPool = buffer.init(cx);
if (!execPool)
return error(cx);

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

@ -177,8 +177,8 @@ StubCompiler::emitStubCall(void *ptr, RejoinState rejoin, Uses uses, int32_t slo
void
StubCompiler::fixCrossJumps(uint8_t *ncode, size_t offset, size_t total)
{
JSC::LinkBuffer fast(ncode, total, JSC::METHOD_CODE);
JSC::LinkBuffer slow(ncode + offset, total - offset, JSC::METHOD_CODE);
JSC::LinkBuffer fast(ncode, total, JSC::JAEGER_CODE);
JSC::LinkBuffer slow(ncode + offset, total - offset, JSC::JAEGER_CODE);
for (size_t i = 0; i < exits.length(); i++)
fast.link(exits[i].from, slow.locationOf(exits[i].to));

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

@ -64,7 +64,7 @@ TrampolineCompiler::compileTrampoline(Trampolines::TrampolinePtr *where,
JS_ASSERT(entry.isSet());
bool ok;
JSC::LinkBuffer buffer(&masm, execAlloc, poolp, &ok, JSC::METHOD_CODE);
JSC::LinkBuffer buffer(&masm, execAlloc, poolp, &ok, JSC::JAEGER_CODE);
if (!ok)
return false;
masm.finalize(buffer);

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

@ -1426,6 +1426,12 @@ ReportCompartmentStats(const JS::CompartmentStats &cStats,
"Memory on the garbage-collected JavaScript "
"heap that holds type inference information.");
CREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("gc-heap/ion-codes"),
cStats.gcHeapIonCodes,
"Memory on the garbage-collected JavaScript "
"heap that holds references to executable code pools "
"used by IonMonkey.");
#if JS_HAS_XML_SUPPORT
CREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("gc-heap/xml"),
cStats.gcHeapXML,
@ -1494,11 +1500,15 @@ ReportCompartmentStats(const JS::CompartmentStats &cStats,
"Memory allocated for JSScript bytecode and various "
"variable-length tables.");
CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("mjit-data"),
cStats.mjitData,
"Memory used by the method JIT for "
"compilation data: JITScripts, native maps, and inline "
"cache structs.");
CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("jaeger-data"),
cStats.jaegerData,
"Memory used by the JaegerMonkey JIT for compilation data: "
"JITScripts, native maps, and inline cache structs.");
CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("ion-data"),
cStats.ionData,
"Memory used by the IonMonkey JIT for compilation data: "
"IonScripts.");
CREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("cross-compartment-wrappers"),
cStats.crossCompartmentWrappers,
@ -1597,18 +1607,23 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
"Memory held transiently in JSRuntime and used during "
"compilation. It mostly holds parse nodes.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/mjit-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.mjitCode,
"Memory used by the method JIT to hold the runtime's "
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/jaeger-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.jaegerCode,
"Memory used by the JaegerMonkey JIT to hold the runtime's "
"generated code.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/ion-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.ionCode,
"Memory used by the IonMonkey JIT to hold the runtime's "
"generated code.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/regexp-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.regexpCode,
"Memory used by the regexp JIT to hold generated code.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/unused-code-memory"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.unusedCodeMemory,
"Memory allocated by the method and/or regexp JIT to hold the "
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/unused-code"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.unusedCode,
"Memory allocated by one of the JITs to hold the "
"runtime's code, but which is currently unused.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/stack-committed"),