[INFER] Fix orange.
authorBrian Hackett <bhackett1024@gmail.com>
Mon, 12 Sep 2011 00:31:38 -0700
changeset 78383 0b9a541b2e0a2a097cd19d3a9c80c35f9d52e23a
parent 78382 820f11a3fdb154d335b2be1b6196fe15e0f99d3f
child 78384 19794de530f1ee4ce2822a0ff2c4366850b15c5d
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone9.0a1
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
[INFER] Fix orange.
js/src/methodjit/Compiler.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MethodJIT.h
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -6785,17 +6785,17 @@ mjit::Compiler::jumpAndTrace(Jump j, jsb
                                                    offsetof(TraceICInfo, loopCounter)));
 # endif
 
     /* Save and restore compiler-tracked PC, so cx->regs is right in InvokeTracer. */
     {
         jsbytecode* pc = PC;
         PC = target;
 
-        OOL_STUBCALL(stubs::InvokeTracer, REJOIN_NONE);
+        OOL_STUBCALL(stubs::InvokeTracer, REJOIN_FINISH_FRAME);
 
         PC = pc;
     }
 
     Jump no = stubcc.masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg,
                                         Registers::ReturnReg);
     if (!cx->typeInferenceEnabled())
         stubcc.masm.loadPtr(FrameAddress(VMFrame::offsetOfFp), JSFrameReg);
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -612,60 +612,56 @@ js_InternalThrow(VMFrame &f)
     JS_ASSERT(f.regs.sp == cx->regs().sp);
 
     if (!pc)
         return NULL;
 
     StackFrame *fp = cx->fp();
     JSScript *script = fp->script();
 
-    if (cx->typeInferenceEnabled() || !fp->jit()) {
-        /*
-         * Fall back to EnterMethodJIT and finish the frame in the interpreter.
-         * With type inference enabled, we may wipe out all JIT code on the
-         * stack without patching ncode values to jump to the interpreter, and
-         * thus can only enter JIT code via EnterMethodJIT (which overwrites
-         * its entry frame's ncode). See ClearAllFrames.
-         */
-        cx->compartment->jaegerCompartment()->setLastUnfinished(Jaeger_Unfinished);
-
-        if (!script->ensureRanAnalysis(cx)) {
-            js_ReportOutOfMemory(cx);
-            return NULL;
-        }
-
-        analyze::AutoEnterAnalysis enter(cx);
-
-        cx->regs().pc = pc;
-        cx->regs().sp = fp->base() + script->analysis()->getCode(pc).stackDepth;
+    /*
+     * Fall back to EnterMethodJIT and finish the frame in the interpreter.
+     * We may wipe out all JIT code on the stack without patching ncode values
+     * to jump to the interpreter, and thus can only enter JIT code via
+     * EnterMethodJIT (which overwrites its entry frame's ncode).
+     * See ClearAllFrames.
+     */
+    cx->compartment->jaegerCompartment()->setLastUnfinished(Jaeger_Unfinished);
 
-        /*
-         * Interpret the ENTERBLOCK and EXCEPTION opcodes, so that we don't go
-         * back into the interpreter with a pending exception. This will cause
-         * it to immediately rethrow.
-         */
-        if (cx->isExceptionPending()) {
-            JS_ASSERT(js_GetOpcode(cx, script, pc) == JSOP_ENTERBLOCK);
-            JSObject *obj = script->getObject(GET_SLOTNO(pc));
-            Value *vp = cx->regs().sp + OBJ_BLOCK_COUNT(cx, obj);
-            SetValueRangeToUndefined(cx->regs().sp, vp);
-            cx->regs().sp = vp;
-            JS_ASSERT(js_GetOpcode(cx, script, pc + JSOP_ENTERBLOCK_LENGTH) == JSOP_EXCEPTION);
-            cx->regs().sp[0] = cx->getPendingException();
-            cx->clearPendingException();
-            cx->regs().sp++;
-            cx->regs().pc = pc + JSOP_ENTERBLOCK_LENGTH + JSOP_EXCEPTION_LENGTH;
-        }
-
-        *f.oldregs = f.regs;
-
+    if (!script->ensureRanAnalysis(cx)) {
+        js_ReportOutOfMemory(cx);
         return NULL;
     }
 
-    return script->nativeCodeForPC(fp->isConstructing(), pc);
+    analyze::AutoEnterAnalysis enter(cx);
+
+    cx->regs().pc = pc;
+    cx->regs().sp = fp->base() + script->analysis()->getCode(pc).stackDepth;
+
+    /*
+     * Interpret the ENTERBLOCK and EXCEPTION opcodes, so that we don't go
+     * back into the interpreter with a pending exception. This will cause
+     * it to immediately rethrow.
+     */
+    if (cx->isExceptionPending()) {
+        JS_ASSERT(js_GetOpcode(cx, script, pc) == JSOP_ENTERBLOCK);
+        JSObject *obj = script->getObject(GET_SLOTNO(pc));
+        Value *vp = cx->regs().sp + OBJ_BLOCK_COUNT(cx, obj);
+        SetValueRangeToUndefined(cx->regs().sp, vp);
+        cx->regs().sp = vp;
+        JS_ASSERT(js_GetOpcode(cx, script, pc + JSOP_ENTERBLOCK_LENGTH) == JSOP_EXCEPTION);
+        cx->regs().sp[0] = cx->getPendingException();
+        cx->clearPendingException();
+        cx->regs().sp++;
+        cx->regs().pc = pc + JSOP_ENTERBLOCK_LENGTH + JSOP_EXCEPTION_LENGTH;
+    }
+
+    *f.oldregs = f.regs;
+
+    return NULL;
 }
 
 void JS_FASTCALL
 stubs::CreateThis(VMFrame &f, JSObject *proto)
 {
     JSContext *cx = f.cx;
     StackFrame *fp = f.fp();
     JSObject *callee = &fp->callee();
@@ -1055,16 +1051,18 @@ RunTracer(VMFrame &f)
     hits = ic.loopCounterStart;
 #else
     traceData = NULL;
     traceEpoch = NULL;
     loopCounter = NULL;
     hits = 1;
 #endif
 
+    RecompilationMonitor monitor(cx);
+
     {
         /*
          * While the tracer is running, redirect the regs to a local variable here.
          * If the tracer exits during an inlined frame, it will synthesize those
          * frames, point f.regs.fp at them and then enter the interpreter. If the
          * interpreter pops the frames it will not be reflected here as a local
          * set of regs is used by the interpreter, and f->regs end up pointing at
          * garbage, confusing the recompiler.
@@ -1073,19 +1071,21 @@ RunTracer(VMFrame &f)
         PreserveRegsGuard regsGuard(cx, regs);
 
         tpa = MonitorTracePoint(f.cx, &blacklist, traceData, traceEpoch,
                                 loopCounter, hits);
         JS_ASSERT(!TRACE_RECORDER(cx));
     }
 
 #if JS_MONOIC
-    ic.loopCounterStart = *loopCounter;
-    if (blacklist)
-        DisableTraceHint(entryFrame->jit(), ic);
+    if (!monitor.recompiled()) {
+        ic.loopCounterStart = *loopCounter;
+        if (blacklist)
+            DisableTraceHint(entryFrame->jit(), ic);
+    }
 #endif
 
     // Even though ExecuteTree() bypasses the interpreter, it should propagate
     // error failures correctly.
     JS_ASSERT_IF(cx->isExceptionPending(), tpa == TPA_Error);
 
     JS_ASSERT(f.fp() == cx->fp());
     switch (tpa) {
@@ -1135,17 +1135,19 @@ RunTracer(VMFrame &f)
     /* IMacros are guaranteed to have been removed by now. */
     JS_ASSERT(f.fp() == entryFrame);
     JS_ASSERT(!entryFrame->hasImacropc());
 
     /* Step 2. If entryFrame is done, use a special path to return to EnterMethodJIT(). */
     if (FrameIsFinished(cx)) {
         if (!HandleFinishedFrame(f, entryFrame))
             THROWV(NULL);
-        *f.returnAddressLocation() = cx->jaegerCompartment()->forceReturnFromFastCall();
+        void *addr = *f.returnAddressLocation();
+        if (addr != JaegerInterpoline)
+            *f.returnAddressLocation() = cx->jaegerCompartment()->forceReturnFromFastCall();
         return NULL;
     }
 
     /* Step 3. If entryFrame is at a safe point, just leave. */
     if (void *ncode = AtSafePoint(cx))
         return ncode;
 
     /* Step 4. Do a partial interp, then restart the whole process. */
@@ -1565,16 +1567,22 @@ js_InternalInterpret(void *returnData, v
         }
         if (takeBranch)
             f.regs.pc = nextpc + GET_JUMP_OFFSET(nextpc);
         else
             f.regs.pc = nextpc + analyze::GetBytecodeLength(nextpc);
         break;
       }
 
+      case REJOIN_FINISH_FRAME:
+        /* InvokeTracer finishes the frame it is given, including the epilogue. */
+        if (fp->isFunctionFrame())
+            fp->markFunctionEpilogueDone();
+        break;
+
       default:
         JS_NOT_REACHED("Missing rejoin");
     }
 
     if (nextDepth == uint32(-1))
         nextDepth = analysis->getCode(f.regs.pc).stackDepth;
     f.regs.sp = fp->base() + nextDepth;
 
--- a/js/src/methodjit/MethodJIT.h
+++ b/js/src/methodjit/MethodJIT.h
@@ -312,17 +312,20 @@ enum RejoinState {
     REJOIN_GETTER,
     REJOIN_POS,
     REJOIN_BINARY,
 
     /*
      * For an opcode fused with IFEQ/IFNE, call returns a boolean indicating
      * the result of the comparison and whether to take or not take the branch.
      */
-    REJOIN_BRANCH
+    REJOIN_BRANCH,
+
+    /* Calls to RunTracer which finished the given frame. */
+    REJOIN_FINISH_FRAME
 };
 
 /* Helper to watch for recompilation and frame expansion activity on a compartment. */
 struct RecompilationMonitor
 {
     JSContext *cx;
 
     /*