[INFER] Rewrite CompileFunction as an UncachedNew/UncachedCall wrapper, bug 660850.
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 31 May 2011 10:31:39 -0700
changeset 75127 750eb028fb0674774641a4345eaff3d999967ebe
parent 75126 0d8de54ff33232b0024937ecd7ee714c7613a951
child 75128 1ac2a4e0ebe20aaf60d11a62f525b4a7ba110593
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs660850
milestone6.0a1
[INFER] Rewrite CompileFunction as an UncachedNew/UncachedCall wrapper, bug 660850.
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/Retcon.cpp
js/src/vm/Stack.h
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -275,92 +275,37 @@ stubs::FixupArity(VMFrame &f, uint32 nac
 
     /* Reset the part of the stack frame set by the prologue up to now. */
     newfp->initCallFrameEarlyPrologue(fun, nactual);
 
     /* The caller takes care of assigning fp to regs. */
     return newfp;
 }
 
+struct ResetStubRejoin {
+    VMFrame &f;
+    ResetStubRejoin(VMFrame &f) : f(f) {}
+    ~ResetStubRejoin() { f.stubRejoin = 0; }
+};
+
 void * JS_FASTCALL
-stubs::CompileFunction(VMFrame &f, uint32 nactual)
+stubs::CompileFunction(VMFrame &f, uint32 argc)
 {
     /*
      * Note: the stubRejoin kind for the frame was written before the call, and
      * needs to be cleared out on all return paths (doing this directly in the
      * IC stub will not handle cases where we recompiled or threw).
      */
     JS_ASSERT_IF(f.cx->typeInferenceEnabled(), f.stubRejoin);
-
-    /*
-     * We have a partially constructed frame. That's not really good enough to
-     * compile though because we could throw, so get a full, adjusted frame.
-     */
-    JSContext *cx = f.cx;
-    StackFrame *fp = f.fp();
-
-    /*
-     * Since we can only use members set by initCallFrameCallerHalf,
-     * we must carefully extract the callee from the nactual.
-     */
-    JSObject &callee = fp->formalArgsEnd()[-(int(nactual) + 2)].toObject();
-    JSFunction *fun = callee.getFunctionPrivate();
-    JSScript *script = fun->script();
-
-    /*
-     * FixupArity/RemovePartialFrame expect to be called after the early
-     * prologue.
-     */
-    fp->initCallFrameEarlyPrologue(fun, nactual);
-
-    if (nactual != fp->numFormalArgs()) {
-        fp = (StackFrame *)FixupArity(f, nactual);
-        if (!fp) {
-            f.stubRejoin = 0;
-            return NULL;
-        }
-    }
-
-    CallArgs args = CallArgsFromArgv(fp->numFormalArgs(), fp->formalArgs());
-    cx->typeMonitorCall(args, fp->isConstructing());
+    ResetStubRejoin reset(f);
 
-    /* Finish frame initialization. */
-    fp->initCallFrameLatePrologue();
-
-    /* These would have been initialized by the prologue. */
-    f.regs.prepareToRun(fp, script);
-
-    if (fun->isHeavyweight() && !js::CreateFunCallObject(cx, fp)) {
-        f.stubRejoin = 0;
-        THROWV(NULL);
-    }
-
-    CompileStatus status = CanMethodJIT(cx, script, fp, CompileRequest_JIT);
-    if (status == Compile_Okay) {
-        void *entry = script->getJIT(fp->isConstructing())->invokeEntry;
+    bool isConstructing = f.fp()->isConstructing();
+    f.regs.popPartialFrame((Value *)f.fp());
 
-        /* Same constraint on fp as UncachedInlineCall. */
-        f.regs.popFrame((Value *) f.regs.fp());
-        f.stubRejoin = 0;
-        return entry;
-    }
-
-    /* Force computation of the previous PC, as Interpret will clear it. */
-    fp->prev()->pc(cx, fp);
-
-    /* Function did not compile... interpret it. */
-    JSBool ok = Interpret(cx, fp);
-    InlineReturn(f);
-
-    f.stubRejoin = 0;
-
-    if (!ok)
-        THROWV(NULL);
-
-    return NULL;
+    return isConstructing ? UncachedNew(f, argc) : UncachedCall(f, argc);
 }
 
 static inline bool
 UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint32 argc)
 {
     JSContext *cx = f.cx;
     Value *vp = f.regs.sp - (argc + 2);
     JSObject &callee = vp->toObject();
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -662,30 +662,35 @@ class CallCompiler : public BaseCompiler
              * ICs automatically).
              */
             masm.storePtr(ImmPtr((void *) ic.frameSize.rejoinState(f.pc(), false)),
                           FrameAddress(offsetof(VMFrame, stubRejoin)));
         }
 
         /* Try and compile. On success we get back the nmap pointer. */
         void *compilePtr = JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction);
+        DataLabelPtr inlined;
         if (ic.frameSize.isStatic()) {
             masm.move(Imm32(ic.frameSize.staticArgc()), Registers::ArgReg1);
             masm.fallibleVMCall(cx->typeInferenceEnabled(),
-                                compilePtr, NULL, NULL, ic.frameSize.staticLocalSlots());
+                                compilePtr, f.regs.pc, &inlined, ic.frameSize.staticLocalSlots());
         } else {
             masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), Registers::ArgReg1);
             masm.fallibleVMCall(cx->typeInferenceEnabled(),
-                                compilePtr, NULL, NULL, -1);
+                                compilePtr, f.regs.pc, &inlined, -1);
         }
 
         Jump notCompiled = masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg,
                                               Registers::ReturnReg);
         masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.sp)), JSFrameReg);
 
+        /* Compute the value of ncode to use at this call site. */
+        uint8 *ncode = (uint8 *) f.jit()->code.m_code.executableAddress() + ic.call->codeOffset;
+        masm.storePtr(ImmPtr(ncode), Address(JSFrameReg, StackFrame::offsetOfNcode()));
+
         masm.jump(Registers::ReturnReg);
 
         hasCode.linkTo(masm.label(), &masm);
 
         /* Get nmap[ARITY], set argc, call. */
         if (ic.frameSize.isStatic())
             masm.move(Imm32(ic.frameSize.staticArgc()), JSParamReg_Argc);
         else
@@ -703,16 +708,21 @@ class CallCompiler : public BaseCompiler
         }
 
         linker.link(notCompiled, ic.slowPathStart.labelAtOffset(ic.slowJoinOffset));
         JSC::CodeLocationLabel cs = linker.finalize();
 
         JaegerSpew(JSpew_PICs, "generated CALL stub %p (%d bytes)\n", cs.executableAddress(),
                    masm.size());
 
+        if (f.regs.inlined()) {
+            JSC::LinkBuffer code((uint8 *) cs.executableAddress(), masm.size());
+            code.patch(inlined, f.regs.inlined());
+        }
+
         Repatcher repatch(from);
         JSC::CodeLocationJump oolJump = ic.slowPathStart.jumpAtOffset(ic.oolJumpOffset);
         repatch.relink(oolJump, cs);
 
         return true;
     }
 
     bool patchInlinePath(JITScript *from, JSScript *script, JSObject *obj)
--- a/js/src/methodjit/Retcon.cpp
+++ b/js/src/methodjit/Retcon.cpp
@@ -241,19 +241,19 @@ Recompiler::expandInlineFrames(JSContext
     uint8* codeStart = (uint8 *)fp->jit()->code.m_code.executableAddress();
 
     InlineFrame *inner = &fp->jit()->inlineFrames()[inlined->inlineIndex];
     jsbytecode *innerpc = inner->fun->script()->code + inlined->pcOffset;
 
     StackFrame *innerfp = expandInlineFrameChain(cx, fp, inner);
 
     /* Check if the VMFrame returns into the inlined frame. */
-    if (f->stubRejoin && (f->stubRejoin & 0x1) && f->regs.fp()->prev() == fp) {
+    if (f->stubRejoin && (f->stubRejoin & 0x1) && f->fp() == fp) {
         /* The VMFrame is calling CompileFunction. */
-        fp->prev()->setRejoin(StubRejoin((RejoinState) f->stubRejoin));
+        innerfp->setRejoin(StubRejoin((RejoinState) f->stubRejoin));
         *frameAddr = JS_FUNC_TO_DATA_PTR(void *, JaegerInterpoline);
     }
     if (*frameAddr == codeStart + inlined->codeOffset) {
         /* The VMFrame returns directly into the expanded frame. */
         SetRejoinState(innerfp, *inlined, frameAddr);
     }
 
     if (f->fp() == fp) {
@@ -412,18 +412,18 @@ Recompiler::recompile(bool resetUses)
         if (rejoin == REJOIN_NATIVE || rejoin == REJOIN_NATIVE_LOWERED) {
             // Native call.
             if (fp->script() == script && fp->isConstructing())
                 patchNative(cx, script->jitCtor, fp, fp->pc(cx, NULL), NULL, rejoin);
             else if (fp->script() == script)
                 patchNative(cx, script->jitNormal, fp, fp->pc(cx, NULL), NULL, rejoin);
         } else if (rejoin) {
             /* Recompilation triggered by CompileFunction. */
-            if (fp->prev()->script() == script) {
-                fp->prev()->setRejoin(StubRejoin(rejoin));
+            if (fp->script() == script) {
+                fp->setRejoin(StubRejoin(rejoin));
                 *addr = JS_FUNC_TO_DATA_PTR(void *, JaegerInterpoline);
             }
         } else if (script->jitCtor && script->jitCtor->isValidCode(*addr)) {
             patchCall(script->jitCtor, fp, addr);
         } else if (script->jitNormal && script->jitNormal->isValidCode(*addr)) {
             patchCall(script->jitNormal, fp, addr);
         }
 
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1056,17 +1056,16 @@ class FrameRegs
         sp = newsp;
         fp_ = fp_->prev();
     }
 
     /* For FixupArity: */
     void popPartialFrame(Value *newsp) {
         sp = newsp;
         fp_ = fp_->prev();
-        inlined_ = NULL;
     }
 
     /* For InternalInterpret: */
     void restorePartialFrame(Value *newfp) {
         fp_ = (StackFrame *) newfp;
     }
 
     /* For stubs::CompileFunction, ContextStack: */