Memory leak fix, don't root funobjs in call ICs.
☠☠ backed out by a45412e2929e ☠ ☠
authorDavid Anderson <danderson@mozilla.com>
Fri, 03 Sep 2010 00:37:47 -0700
changeset 74530 1021c20f8d6bbf9e5c9911f5e50c846bafd5dcda
parent 74529 52da34bd765d913ed30dcd94dfbfddb771fcddfb
child 74531 a45412e2929e360e76038e58694913088c50b868
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone2.0b6pre
Memory leak fix, don't root funobjs in call ICs.
js/src/methodjit/Compiler.cpp
js/src/methodjit/MethodJIT.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/MonoIC.h
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -434,16 +434,17 @@ mjit::Compiler::finishThisUp()
     } else {
         script->callICs = NULL;
     }
 
     for (size_t i = 0; i < callICs.length(); i++) {
         script->callICs[i].reset();
         script->callICs[i].funGuard = fullCode.locationOf(callICs[i].funGuard);
         script->callICs[i].funJump = fullCode.locationOf(callICs[i].funJump);
+        script->callICs[i].lastFunJump = script->callICs[i].funJump;
         script->callICs[i].slowPathStart = stubCode.locationOf(callICs[i].slowPathStart);
 
         /* Compute the hot call offset. */
         uint32 offset = fullCode.locationOf(callICs[i].hotCall) -
                         fullCode.locationOf(callICs[i].funGuard);
         script->callICs[i].hotCallOffset = offset;
         JS_ASSERT(script->callICs[i].hotCallOffset == offset);
 
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -851,32 +851,17 @@ mjit::ReleaseScriptCode(JSContext *cx, J
         // must protect against calling ReleaseScriptCode twice.
         script->jit = NULL;
     }
 }
 
 void
 mjit::TraceScriptCache(JSTracer *trc, JSScript *script)
 {
-#ifdef JS_MONOIC
-    uint32 numCallICs = script->jit->nCallICs;
-    for (uint32 i = 0; i < numCallICs; i++) {
-        ic::CallICInfo &ic = script->callICs[i];
-        if (ic.fastGuardedObject) {
-            JS_SET_TRACING_NAME(trc, "callIC fun");
-            Mark(trc, ic.fastGuardedObject, JSTRACE_OBJECT);
-        }
-        if (ic.fastGuardedNative) {
-            JS_SET_TRACING_NAME(trc, "callIC native");
-            Mark(trc, ic.fastGuardedNative, JSTRACE_OBJECT);
-        }
-        if (ic.isConstantThis)
-            MarkValue(trc, ic.constantThis, "callIC this");
-    }
-#endif
+    ic::PurgeCallICs(trc->context, script);
 }
 
 #ifdef JS_METHODJIT_PROFILE_STUBS
 void JS_FASTCALL
 mjit::ProfileStubCall(VMFrame &f)
 {
     JSOp op = JSOp(*f.regs.pc);
     StubCallsForOp[op]++;
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -393,23 +393,23 @@ class CallCompiler
     }
 
     void patchInlinePath(JSScript *script, JSObject *obj)
     {
         /* Very fast path. */
         uint8 *start = (uint8 *)ic.funGuard.executableAddress();
         JSC::RepatchBuffer repatch(start - 32, 64);
 
-        ic.fastGuardedObject = obj;
+        ic.guardedObject = obj;
 
         repatch.repatch(ic.funGuard, obj);
         repatch.relink(ic.funGuard.callAtOffset(ic.hotCallOffset),
                        JSC::FunctionPtr(script->ncode));
 
-        JaegerSpew(JSpew_PICs, "patched CALL path %p (obj: %)\n", start, ic.fastGuardedObject);
+        JaegerSpew(JSpew_PICs, "patched CALL path %p (obj: %)\n", start, ic.guardedObject);
     }
 
     bool generateStubForClosures(JSObject *obj)
     {
         /* Slightly less fast path - guard on fun->getFunctionPrivate() instead. */
         Assembler masm;
 
         Registers tempRegs;
@@ -436,22 +436,22 @@ class CallCompiler
         buffer.link(claspGuard, ic.slowPathStart);
         buffer.link(funGuard, ic.slowPathStart);
         buffer.link(done, ic.funGuard.labelAtOffset(ic.hotPathOffset));
         JSC::CodeLocationLabel cs = buffer.finalizeCodeAddendum();
 
         JaegerSpew(JSpew_PICs, "generated CALL closure stub %p (%d bytes)\n",
                    cs.executableAddress(), masm.size());
 
-        uint8 *start = (uint8 *)ic.funJump.executableAddress();
+        uint8 *start = (uint8 *)ic.lastFunJump.executableAddress();
         JSC::RepatchBuffer repatch(start - 32, 64);
-        repatch.relink(ic.funJump, cs);
+        repatch.relink(ic.lastFunJump, cs);
 
         /* Retarget funJump for future ICs. */
-        ic.funJump = buffer.locationOf(funGuard);
+        ic.lastFunJump = buffer.locationOf(funGuard);
 
         ic.hasJsFunCheck = true;
 
         return true;
     }
 
     bool generateNativeStub()
     {
@@ -468,17 +468,17 @@ class CallCompiler
         if (callingNew)
             vp[1].setMagicWithObjectOrNullPayload(NULL);
 
         Native fn = fun->u.n.native;
         if (!fn(cx, ic.argc, vp))
             THROWV(true);
 
         /* Right now, take slow-path for IC misses. */
-        if (ic.fastGuardedNative)
+        if (ic.guardedNative)
             return true;
 
         /* Native MIC needs to warm up first. */
         if (!ic.hit) {
             ic.hit = true;
             return true;
         }
 
@@ -586,24 +586,24 @@ class CallCompiler
         buffer.link(hasException, JSC::CodeLocationLabel(JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline)));
         buffer.link(funGuard, ic.slowPathStart);
         
         JSC::CodeLocationLabel cs = buffer.finalizeCodeAddendum();
 
         JaegerSpew(JSpew_PICs, "generated native CALL stub %p (%d bytes)\n",
                    cs.executableAddress(), masm.size());
 
-        uint8 *start = (uint8 *)ic.funJump.executableAddress();
+        uint8 *start = (uint8 *)ic.lastFunJump.executableAddress();
         JSC::RepatchBuffer repatch(start - 32, 64);
-        repatch.relink(ic.funJump, cs);
+        repatch.relink(ic.lastFunJump, cs);
 
-        ic.fastGuardedNative = obj;
+        ic.guardedNative = true;
 
         /* Retarget funJump for future ICs. */
-        ic.funJump = buffer.locationOf(funGuard);
+        ic.lastFunJump = buffer.locationOf(funGuard);
 
         return true;
     }
 
     void *update()
     {
         JSObject *obj;
         if (!IsFunctionObject(*vp, &obj) || !(cx->options & JSOPTION_METHODJIT)) {
@@ -648,20 +648,20 @@ class CallCompiler
         if (callingNew)
             stubs::NewObject(f, ic.argc);
 
         if (!ic.hit) {
             if (ic.argc < fun->nargs) {
                 if (!generateFullCallStub(script, flags))
                     THROWV(NULL);
             } else {
-                if (!ic.fastGuardedObject) {
+                if (!ic.guardedObject) {
                     patchInlinePath(script, obj);
                 } else if (!ic.hasJsFunCheck &&
-                           ic.fastGuardedObject->getFunctionPrivate() == fun) {
+                           ic.guardedObject->getFunctionPrivate() == fun) {
                     if (!generateStubForClosures(obj))
                         THROWV(NULL);
                 } else {
                     if (!generateFullCallStub(script, flags))
                         THROWV(NULL);
                 }
             }
         } else {
@@ -742,10 +742,31 @@ ic::PurgeMICs(JSContext *cx, JSScript *s
             break;
           default:
             JS_NOT_REACHED("Unknown MIC type during purge");
             break;
         }
     }
 }
 
+void
+ic::PurgeCallICs(JSContext *cx, JSScript *script)
+{
+    uint32 numCallICs = script->jit->nCallICs;
+    for (uint32 i = 0; i < numCallICs; i++) {
+        ic::CallICInfo &ic = script->callICs[i];
+
+        if (!ic.guardedNative && !ic.guardedObject)
+            continue;
+
+        /* Very fast path. */
+        uint8 *start = (uint8 *)ic.funGuard.executableAddress();
+        JSC::RepatchBuffer repatch(start - 32, 64);
+
+        repatch.repatch(ic.funGuard, NULL);
+        repatch.relink(ic.funJump, ic.slowPathStart);
+        ic.lastFunJump = ic.funJump;
+        ic.partialReset();
+    }
+}
+
 #endif /* JS_MONOIC */
 
--- a/js/src/methodjit/MonoIC.h
+++ b/js/src/methodjit/MonoIC.h
@@ -116,32 +116,31 @@ struct CallICInfo {
         Pool_ScriptStub,
         Pool_ClosureStub,
         Pool_NativeStub,
         Total_Pools
     };
 
     JSC::ExecutablePool *pools[Total_Pools];
 
-    /* Used for rooting and reification. */
-    JSObject *fastGuardedObject;
-    JSObject *fastGuardedNative;
+    JSObject *guardedObject;
     Value constantThis;
 
     uint32 argc : 16;
     uint32 frameDepth : 16;
 
     /* Function object identity guard. */
     JSC::CodeLocationDataLabelPtr funGuard;
 
     /* Starting point for all slow call paths. */
     JSC::CodeLocationLabel slowPathStart;
 
-    /* Inline to OOL jump, redirected by stubs. */
+    /* Inline to OOL jump, second is redirected by stubs. */
     JSC::CodeLocationJump funJump;
+    JSC::CodeLocationJump lastFunJump;
 
     /* Offset to inline scripted call, from funGuard. */
     uint32 hotCallOffset   : 8;
     uint32 joinPointOffset : 8;
 
     /* Out of line slow call. */
     uint32 oolCallOffset   : 8;
 
@@ -154,43 +153,54 @@ struct CallICInfo {
     /* Join point for all slow call paths. */
     uint32 slowJoinOffset  : 9;
 
     RegisterID funObjReg : 5;
     RegisterID funPtrReg : 5;
     bool isConstantThis : 1;
     bool hit : 1;
     bool hasJsFunCheck : 1;
+    bool guardedNative : 1;
+
+    inline void partialReset() {
+        guardedObject = NULL;
+        guardedNative = false;
+        hasJsFunCheck = false;
+        releasePool(Pool_ClosureStub);
+        releasePool(Pool_NativeStub);
+    }
 
     inline void reset() {
-        fastGuardedObject = NULL;
-        fastGuardedNative = NULL;
+        guardedObject = NULL;
+        guardedNative = false;
         hit = false;
         hasJsFunCheck = false;
         pools[0] = pools[1] = pools[2] = NULL;
     }
 
     inline void releasePools() {
         releasePool(Pool_ScriptStub);
         releasePool(Pool_ClosureStub);
         releasePool(Pool_NativeStub);
     }
 
-  private:
     inline void releasePool(PoolIndex index) {
-        if (pools[index])
+        if (pools[index]) {
             pools[index]->release();
+            pools[index] = NULL;
+        }
     }
 };
 
 void * JS_FASTCALL New(VMFrame &f, uint32 index);
 void * JS_FASTCALL Call(VMFrame &f, uint32 index);
 void JS_FASTCALL NativeNew(VMFrame &f, uint32 index);
 void JS_FASTCALL NativeCall(VMFrame &f, uint32 index);
 
 void PurgeMICs(JSContext *cx, JSScript *script);
+void PurgeCallICs(JSContext *cx, JSScript *script);
 
 } /* namespace ic */
 } /* namespace mjit */
 } /* namespace js */
 
 #endif /* jsjaeger_mono_ic_h__ */