Bug 623281: about:memory reporting for method JIT space usage, r=dvander
authorMike Shaver <shaver@mozilla.org>
Tue, 04 Jan 2011 22:48:46 -0800
changeset 60207 d6675a84589d251a1733032ff67aad69645f31b8
parent 60206 ca11457ed5fe6ff90cff2bcfe1f595fb2ee5eab8
child 60208 8d7836a659e8f0cc32996a1453e17e540d945024
push id17881
push usercleary@mozilla.com
push dateFri, 07 Jan 2011 19:57:21 +0000
treeherdermozilla-central@54576be62860 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs623281
milestone2.0b9pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 623281: about:memory reporting for method JIT space usage, r=dvander
js/src/jscntxt.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/MethodJIT.cpp
js/src/methodjit/MethodJIT.h
js/src/shell/js.cpp
js/src/xpconnect/src/xpcjsruntime.cpp
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1430,16 +1430,20 @@ struct JSRuntime {
 
     FunctionCountMap    methodReadBarrierCountMap;
     FunctionCountMap    unjoinedFunctionCountMap;
 #endif
 
     JSWrapObjectCallback wrapObjectCallback;
     JSPreWrapCallback    preWrapObjectCallback;
 
+#ifdef JS_METHODJIT
+    uint32               mjitMemoryUsed;
+#endif
+
     JSRuntime();
     ~JSRuntime();
 
     bool init(uint32 maxbytes);
 
     void setGCTriggerFactor(uint32 factor);
     void setGCLastBytes(size_t lastBytes);
 
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -412,16 +412,17 @@ mjit::Compiler::finishThisUp(JITScript *
 
     size_t nNmapLive = 0;
     for (size_t i = 0; i < script->length; i++) {
         analyze::Bytecode *opinfo = analysis->maybeCode(i);
         if (opinfo && opinfo->safePoint)
             nNmapLive++;
     }
 
+    /* Please keep in sync with JITScript::scriptDataSize! */
     size_t totalBytes = sizeof(JITScript) +
                         sizeof(NativeMapEntry) * nNmapLive +
 #if defined JS_MONOIC
                         sizeof(ic::MICInfo) * mics.length() +
                         sizeof(ic::CallICInfo) * callICs.length() +
                         sizeof(ic::EqualityICInfo) * equalityICs.length() +
                         sizeof(ic::TraceICInfo) * traceICs.length() +
 #endif
@@ -813,16 +814,19 @@ mjit::Compiler::finishThisUp(JITScript *
     }
 
     JS_ASSERT(size_t(cursor - (uint8*)jit) == totalBytes);
 
     jit->nmap = nmap;
     jit->nNmapPairs = nNmapLive;
     *jitp = jit;
 
+    /* We tolerate a race in the stats. */
+    cx->runtime->mjitMemoryUsed += totalSize + totalBytes;
+
     return Compile_Okay;
 }
 
 class SrcNoteLineScanner {
     ptrdiff_t offset;
     jssrcnote *sn;
 
 public:
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -833,33 +833,58 @@ mjit::JITScript::~JITScript()
         (*pExecPool)->release();
     }
     
     for (uint32 i = 0; i < nCallICs; i++)
         callICs[i].releasePools();
 #endif
 }
 
+/* Please keep in sync with Compiler::finishThisUp! */
+size_t
+mjit::JITScript::scriptDataSize()
+{
+    return sizeof(JITScript) +
+        sizeof(NativeMapEntry) * nNmapPairs +
+#if defined JS_MONOIC
+        sizeof(ic::MICInfo) * nMICs +
+        sizeof(ic::CallICInfo) * nCallICs +
+        sizeof(ic::EqualityICInfo) * nEqualityICs +
+        sizeof(ic::TraceICInfo) * nTraceICs +
+#endif
+#if defined JS_POLYIC
+        sizeof(ic::PICInfo) * nPICs +
+        sizeof(ic::GetElementIC) * nGetElems +
+        sizeof(ic::SetElementIC) * nSetElems +
+#endif
+        sizeof(CallSite) * nCallSites;
+}
+
 void
 mjit::ReleaseScriptCode(JSContext *cx, JSScript *script)
 {
     // NB: The recompiler may call ReleaseScriptCode, in which case it
     // will get called again when the script is destroyed, so we
     // must protect against calling ReleaseScriptCode twice.
+    JITScript *jscr;
 
-    if (script->jitNormal) {
-        script->jitNormal->~JITScript();
-        cx->free(script->jitNormal);
+    if ((jscr = script->jitNormal)) {
+        cx->runtime->mjitMemoryUsed -= jscr->scriptDataSize() + jscr->mainCodeSize();
+
+        jscr->~JITScript();
+        cx->free(jscr);
         script->jitNormal = NULL;
         script->jitArityCheckNormal = NULL;
     }
 
-    if (script->jitCtor) {
-        script->jitCtor->~JITScript();
-        cx->free(script->jitCtor);
+    if ((jscr = script->jitCtor)) {
+        cx->runtime->mjitMemoryUsed -= jscr->scriptDataSize() + jscr->mainCodeSize();
+
+        jscr->~JITScript();
+        cx->free(jscr);
         script->jitCtor = NULL;
         script->jitArityCheckCtor = NULL;
     }
 }
 
 #ifdef JS_METHODJIT_PROFILE_STUBS
 void JS_FASTCALL
 mjit::ProfileStubCall(VMFrame &f)
--- a/js/src/methodjit/MethodJIT.h
+++ b/js/src/methodjit/MethodJIT.h
@@ -349,16 +349,20 @@ struct JITScript {
         char *jcheck = (char *)ptr;
         return jcheck >= jitcode && jcheck < jitcode + code.m_size;
     }
 
     void nukeScriptDependentICs();
     void sweepCallICs(bool purgeAll);
     void purgeMICs();
     void purgePICs();
+
+    size_t auxCodeSize();
+
+    size_t mainCodeSize() { return code.m_size; } /* doesn't account for fragmentation */
 };
 
 /*
  * Execute the given mjit code. This is a low-level call and callers must
  * provide the same guarantees as JaegerShot/CheckStackAndEnterMethodJIT.
  */
 JSBool EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, Value *stackLimit);
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4294,16 +4294,23 @@ DefGlobalPropIf(JSContext *cx, uintN arg
     if (!JS_ValueToId(cx, argv[1], &id))
         return false;
 
     JSObject *global = JS_GetGlobalForScopeChain(cx);
     JSBool ignore;
     return global && JS_DefineOwnProperty(cx, global, id, argv[2], &ignore);
 }
 
+JSBool
+MJitStats(JSContext *cx, uintN argc, jsval *vp)
+{
+    JS_SET_RVAL(cx, vp, INT_TO_JSVAL(cx->runtime->mjitMemoryUsed));
+    return true;
+}
+
 /* We use a mix of JS_FS and JS_FN to test both kinds of natives. */
 static JSFunctionSpec shell_functions[] = {
     JS_FN("version",        Version,        0,0),
     JS_FN("revertVersion",  RevertVersion,  0,0),
     JS_FN("options",        Options,        0,0),
     JS_FN("load",           Load,           1,0),
     JS_FN("readline",       ReadLine,       0,0),
     JS_FN("print",          Print,          0,0),
@@ -4393,16 +4400,19 @@ static JSFunctionSpec shell_functions[] 
     JS_FN("timeout",        Timeout,        1,0),
     JS_FN("elapsed",        Elapsed,        0,0),
     JS_FN("parent",         Parent,         1,0),
     JS_FN("wrap",           Wrap,           1,0),
     JS_FN("serialize",      Serialize,      1,0),
     JS_FN("deserialize",    Deserialize,    1,0),
     JS_FN("setGlobalPropIf",SetGlobalPropIf,3,0),
     JS_FN("defGlobalPropIf",DefGlobalPropIf,3,0),
+#ifdef JS_METHODJIT
+    JS_FN("mjitstats",      MJitStats,      0,0),
+#endif
     JS_FS_END
 };
 
 static const char shell_help_header[] =
 "Command                  Description\n"
 "=======                  ===========\n";
 
 static const char *const shell_help_messages[] = {
@@ -4525,16 +4535,19 @@ static const char *const shell_help_mess
 "elapsed()                Execution time elapsed for the current context.",
 "parent(obj)              Returns the parent of obj.\n",
 "wrap(obj)                Wrap an object into a noop wrapper.\n",
 "serialize(sd)            Serialize sd using JS_WriteStructuredClone. Returns a TypedArray.\n",
 "deserialize(a)           Deserialize data generated by serialize.\n",
 "setGlobalPropIf(b,id,v)  If b, get the global object o and perform o[id] = v.\n",
 "defGlobalPropIf(b,id,dsc)If b, get the global object o and perform\n"
 "                         Object.defineProperty(o, id, dsc).\n"
+#ifdef JS_METHODJIT
+,"mjitstats()             Return stats on mjit memory usage.\n"
+#endif
 };
 
 /* Help messages must match shell functions. */
 JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages) + 1 ==
                  JS_ARRAY_LENGTH(shell_functions));
 
 #ifdef DEBUG
 static void
--- a/js/src/xpconnect/src/xpcjsruntime.cpp
+++ b/js/src/xpconnect/src/xpcjsruntime.cpp
@@ -1187,21 +1187,41 @@ private:
 
 protected:
     PRUint32 mNumGCChunksInUse;
 };
 
 static XPConnectGCChunkAllocator gXPCJSChunkAllocator;
 
 NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSRuntimeGCChunks,
-                             "xpconnect/js/gcchunks",
-                             "Memory in use by main JS Runtime GC chunks",
+                             "js/gc-heap",
+                             "Main JS GC heap",
                              XPConnectGCChunkAllocator::GetGCChunkBytesInUse,
                              &gXPCJSChunkAllocator)
 
+/* FIXME: use API provided by bug 623271 */
+#include "jscntxt.h"
+
+static PRInt64
+GetJSMethodJitCodeMemoryInUse(void *data)
+{
+    JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
+#ifdef JS_METHODJIT
+    return rt->mjitMemoryUsed;
+#else
+    return 0;
+#endif
+}
+
+NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSMethodJitCode,
+                             "js/mjit-code",
+                             "Memory in use by method-JIT for compiled code",
+                             GetJSMethodJitCodeMemoryInUse,
+                             NULL)
+
 XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
  : mXPConnect(aXPConnect),
    mJSRuntime(nsnull),
    mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_SIZE)),
    mWrappedJSClassMap(IID2WrappedJSClassMap::newMap(XPC_JS_CLASS_MAP_SIZE)),
    mIID2NativeInterfaceMap(IID2NativeInterfaceMap::newMap(XPC_NATIVE_INTERFACE_MAP_SIZE)),
    mClassInfo2NativeSetMap(ClassInfo2NativeSetMap::newMap(XPC_NATIVE_SET_MAP_SIZE)),
    mNativeSetMap(NativeSetMap::newMap(XPC_NATIVE_SET_MAP_SIZE)),
@@ -1254,16 +1274,17 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
                                   xpc::WrapperFactory::PrepareForWrapping);
         mWatchdogWakeup = JS_NEW_CONDVAR(mJSRuntime->gcLock);
 
         mJSRuntime->setActivityCallback(ActivityCallback, this);
 
         mJSRuntime->setCustomGCChunkAllocator(&gXPCJSChunkAllocator);
 
         NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSRuntimeGCChunks));
+        NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSMethodJitCode));
     }
 
     if(!JS_DHashTableInit(&mJSHolders, JS_DHashGetStubOps(), nsnull,
                           sizeof(ObjectHolder), 512))
         mJSHolders.ops = nsnull;
 
     mCompartmentMap.Init();
     mMTCompartmentMap.Init();