Fix various bugs in tracer integration (bug 593532, r=dmandelin).
authorDavid Anderson <danderson@mozilla.com>
Tue, 07 Sep 2010 22:52:15 -0700
changeset 53626 1b55ec0c7aeec9f3509afa087c9809a9e2342b10
parent 53625 4172f41539464c3712b3961fbadc0ba50fa06f6f
child 53627 d1e6b33c9a464679cf0a35e74141230296231e0c
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdmandelin
bugs593532
milestone2.0b6pre
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
Fix various bugs in tracer integration (bug 593532, r=dmandelin).
js/src/jscntxt.h
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jstracer.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MethodJIT.cpp
js/src/methodjit/MethodJIT.h
js/src/trace-test/lib/prolog.js
js/src/trace-test/tests/basic/testBug504520.js
js/src/trace-test/tests/basic/testBug504520Harder.js
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -2045,17 +2045,17 @@ struct JSContext
 
     bool hasfp() {
         JS_ASSERT_IF(regs, regs->fp);
         return !!regs;
     }
 
   public:
     friend class js::StackSpace;
-    friend bool js::Interpret(JSContext *, JSStackFrame *, uintN);
+    friend bool js::Interpret(JSContext *, JSStackFrame *, uintN, uintN);
 
     /* 'regs' must only be changed by calling this function. */
     void setCurrentRegs(JSFrameRegs *regs) {
         this->regs = regs;
     }
 
     /* Temporary arena pool used while compiling and decompiling. */
     JSArenaPool         tempPool;
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1953,17 +1953,17 @@ IteratorNext(JSContext *cx, JSObject *it
     }
     return js_IteratorNext(cx, iterobj, rval);
 }
 
 
 namespace js {
 
 JS_REQUIRES_STACK bool
-Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount)
+Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, uintN interpFlags)
 {
 #ifdef MOZ_TRACEVIS
     TraceVisStateObj tvso(cx, S_INTERP);
 #endif
     JSAutoResolveFlags rf(cx, JSRESOLVE_INFER);
 
 # ifdef DEBUG
     /*
@@ -2110,18 +2110,17 @@ Interpret(JSContext *cx, JSStackFrame *e
      * GET_FULL_INDEX macros below. As a register we use a pointer based on
      * the atom map to turn frequently executed LOAD_ATOM into simple array
      * access. For less frequent object and regexp loads we have to recover
      * the segment from atoms pointer first.
      */
     JSAtom **atoms = script->atomMap.vector;
 
 #ifdef JS_METHODJIT
-    bool leaveOnTracePoint = (fp->flags & JSFRAME_BAILING) && !fp->hasIMacroPC();
-# define CLEAR_LEAVE_ON_TRACE_POINT() ((void) (leaveOnTracePoint = false))
+# define CLEAR_LEAVE_ON_TRACE_POINT() ((void) (leaveOnSafePoint = false))
 #else
 # define CLEAR_LEAVE_ON_TRACE_POINT() ((void) 0)
 #endif
 
 #define LOAD_ATOM(PCOFF, atom)                                                \
     JS_BEGIN_MACRO                                                            \
         JS_ASSERT(fp->hasIMacroPC()                                           \
                   ? atoms == COMMON_ATOMS_START(&rt->atomState) &&            \
@@ -2207,26 +2206,28 @@ Interpret(JSContext *cx, JSStackFrame *e
             goto error;                                                       \
     JS_END_MACRO
 
 #ifndef TRACE_RECORDER
 #define TRACE_RECORDER(cx) (false)
 #endif
 
 #ifdef JS_METHODJIT
-# define LEAVE_ON_TRACE_POINT()                                               \
+# define LEAVE_ON_SAFE_POINT()                                               \
     do {                                                                      \
-        if (leaveOnTracePoint && !fp->hasIMacroPC() &&                        \
+        JS_ASSERT_IF(leaveOnSafePoint, !TRACE_RECORDER(cx));                  \
+        if (leaveOnSafePoint && !fp->hasIMacroPC() &&                         \
             script->nmap && script->nmap[regs.pc - script->code]) {           \
+            JS_ASSERT(!TRACE_RECORDER(cx));                                   \
             interpReturnOK = true;                                            \
             goto stop_recording;                                              \
         }                                                                     \
     } while (0)
 #else
-# define LEAVE_ON_TRACE_POINT() /* nop */
+# define LEAVE_ON_SAFE_POINT() /* nop */
 #endif
 
 #define BRANCH(n)                                                             \
     JS_BEGIN_MACRO                                                            \
         regs.pc += (n);                                                       \
         op = (JSOp) *regs.pc;                                                 \
         if ((n) <= 0) {                                                       \
             CHECK_BRANCH();                                                   \
@@ -2237,25 +2238,24 @@ Interpret(JSContext *cx, JSStackFrame *e
                 } else {                                                      \
                     op = (JSOp) *++regs.pc;                                   \
                 }                                                             \
             } else if (op == JSOP_TRACE) {                                    \
                 MONITOR_BRANCH();                                             \
                 op = (JSOp) *regs.pc;                                         \
             }                                                                 \
         }                                                                     \
-        LEAVE_ON_TRACE_POINT();                                               \
+        LEAVE_ON_SAFE_POINT();                                                \
         DO_OP();                                                              \
     JS_END_MACRO
 
     MUST_FLOW_THROUGH("exit");
 
-#ifdef JS_TRACER
-    bool wasRecording = !!(fp->flags & JSFRAME_RECORDING);
-    bool wasImacroRun = fp->hasIMacroPC() && !TRACE_RECORDER(cx);
+#if defined(JS_TRACER) && defined(JS_METHODJIT)
+    bool leaveOnSafePoint = !!(interpFlags & JSINTERP_SAFEPOINT);
 #endif
 
     ++cx->interpLevel;
 
     /*
      * Optimized Get and SetVersion for proper script language versioning.
      *
      * If any native method or a Class or ObjectOps hook calls js_SetVersion
@@ -2307,17 +2307,17 @@ Interpret(JSContext *cx, JSStackFrame *e
 #endif
 
 #ifdef JS_TRACER
     /*
      * The method JIT may have already initiated a recording, in which case
      * there should already be a valid recorder. Otherwise...
      * we cannot reenter the interpreter while recording.
      */
-    if (wasRecording) {
+    if (interpFlags & JSINTERP_RECORD) {
         JS_ASSERT(TRACE_RECORDER(cx));
         ENABLE_INTERRUPTS();
     } else if (TRACE_RECORDER(cx)) {
         AbortRecording(cx, "attempt to reenter interpreter while recording");
     }
 
     if (fp->hasIMacroPC())
         atoms = COMMON_ATOMS_START(&rt->atomState);
@@ -2402,16 +2402,31 @@ Interpret(JSContext *cx, JSStackFrame *e
             }
             moreInterrupts = true;
         }
 
 #ifdef JS_TRACER
         if (TraceRecorder* tr = TRACE_RECORDER(cx)) {
             AbortableRecordingStatus status = tr->monitorRecording(op);
             JS_ASSERT_IF(cx->throwing, status == ARECORD_ERROR);
+
+            if (interpFlags & (JSINTERP_RECORD | JSINTERP_SAFEPOINT)) {
+                switch (status) {
+                  case ARECORD_IMACRO_ABORTED:
+                  case ARECORD_ABORTED:
+                  case ARECORD_COMPLETED:
+                  case ARECORD_STOP:
+                    leaveOnSafePoint = true;
+                    LEAVE_ON_SAFE_POINT();
+                    break;
+                  default:
+                    break;
+                }
+            }
+
             switch (status) {
               case ARECORD_CONTINUE:
                 moreInterrupts = true;
                 break;
               case ARECORD_IMACRO:
               case ARECORD_IMACRO_ABORTED:
                 atoms = COMMON_ATOMS_START(&rt->atomState);
                 op = JSOp(*regs.pc);
@@ -2425,19 +2440,16 @@ Interpret(JSContext *cx, JSStackFrame *e
               case ARECORD_ABORTED:
               case ARECORD_COMPLETED:
                 break;
               case ARECORD_STOP:
                 /* A 'stop' error should have already aborted recording. */
               default:
                 JS_NOT_REACHED("Bad recording status");
             }
-        } else if (wasRecording) {
-            interpReturnOK = true;
-            goto stop_recording;
         }
 #endif /* !JS_TRACER */
 
 #if JS_THREADED_INTERP
 #ifdef MOZ_TRACEVIS
         if (!moreInterrupts)
             ExitTraceVisState(cx, R_ABORT);
 #endif
@@ -2458,17 +2470,17 @@ ADD_EMPTY_CASE(JSOP_TRY)
 ADD_EMPTY_CASE(JSOP_STARTXML)
 ADD_EMPTY_CASE(JSOP_STARTXMLEXPR)
 #endif
 ADD_EMPTY_CASE(JSOP_UNUSED180)
 END_EMPTY_CASES
 
 BEGIN_CASE(JSOP_TRACE)
 #ifdef JS_METHODJIT
-    LEAVE_ON_TRACE_POINT();
+    LEAVE_ON_SAFE_POINT();
 #endif
 END_CASE(JSOP_TRACE)
 
 /* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */
 BEGIN_CASE(JSOP_LINENO)
 BEGIN_CASE(JSOP_DEFUPVAR)
 END_CASE(JSOP_DEFUPVAR)
 
@@ -2551,27 +2563,17 @@ BEGIN_CASE(JSOP_STOP)
          * If we are at the end of an imacro, return to its caller in the
          * current frame.
          */
         JS_ASSERT(op == JSOP_STOP);
         JS_ASSERT((uintN)(regs.sp - fp->slots()) <= script->nslots);
         jsbytecode *imacpc = fp->getIMacroPC();
         regs.pc = imacpc + js_CodeSpec[*imacpc].length;
         fp->clearIMacroPC();
-# ifdef JS_METHODJIT
-        if ((wasImacroRun || wasRecording) && !TRACE_RECORDER(cx)) {
-            if (script->nmap && script->nmap[regs.pc - script->code]) {
-                interpReturnOK = true;
-                goto stop_recording;
-            }
-            leaveOnTracePoint = true;
-        }
-# endif
-        JS_ASSERT_IF(!(op == JSOP_STOP || (wasImacroRun && op == JSOP_IMACOP)),
-                     !(fp->flags & JSFRAME_RECORDING));
+        LEAVE_ON_SAFE_POINT();
         atoms = script->atomMap.vector;
         op = JSOp(*regs.pc);
         DO_OP();
     }
 #endif
 
     JS_ASSERT(regs.sp == fp->base());
     if ((fp->flags & JSFRAME_CONSTRUCTING) && fp->getReturnValue().isPrimitive()) {
@@ -6863,17 +6865,17 @@ END_CASE(JSOP_ARRAYPUSH)
      * frame pc.
      */
     JS_ASSERT(entryFrame == fp);
     JS_ASSERT(cx->regs == &regs);
     *prevContextRegs = regs;
     cx->setCurrentRegs(prevContextRegs);
 
 #ifdef JS_TRACER
-    JS_ASSERT_IF(interpReturnOK && wasRecording, !TRACE_RECORDER(cx));
+    JS_ASSERT_IF(interpReturnOK && (interpFlags & JSINTERP_RECORD), !TRACE_RECORDER(cx));
     if (TRACE_RECORDER(cx))
         AbortRecording(cx, "recording out of Interpret");
 #endif
 
     JS_ASSERT_IF(!fp->isGenerator(), !fp->hasBlockChain());
     JS_ASSERT_IF(!fp->isGenerator(), !js_IsActiveWithOrBlock(cx, fp->getScopeChain(), 0));
 
     /* Undo the remaining effects committed on entry to Interpret. */
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -62,25 +62,29 @@ enum JSFrameFlags {
     JSFRAME_OVERRIDE_ARGS      =   0x02, /* overridden arguments local variable */
     JSFRAME_ASSIGNING          =   0x04, /* a complex (not simplex JOF_ASSIGNING) op
                                            is currently assigning to a property */
     JSFRAME_DEBUGGER           =   0x08, /* frame for JS_EvaluateInStackFrame */
     JSFRAME_EVAL               =   0x10, /* frame for obj_eval */
     JSFRAME_FLOATING_GENERATOR =   0x20, /* frame copy stored in a generator obj */
     JSFRAME_YIELDING           =   0x40, /* js_Interpret dispatched JSOP_YIELD */
     JSFRAME_GENERATOR          =   0x80, /* frame belongs to generator-iterator */
-    JSFRAME_BAILING            =  0x100, /* walking out of a method JIT'd frame */
-    JSFRAME_RECORDING          =  0x200, /* recording a trace */
-    JSFRAME_BAILED_AT_RETURN   =  0x400, /* bailed at JSOP_RETURN */
-    JSFRAME_DUMMY              =  0x800, /* frame is a dummy frame */
-    JSFRAME_IN_IMACRO          = 0x1000, /* frame has imacpc value available */
+    JSFRAME_BAILED_AT_RETURN   =  0x100, /* bailed at JSOP_RETURN */
+    JSFRAME_DUMMY              =  0x200, /* frame is a dummy frame */
+    JSFRAME_IN_IMACRO          =  0x400, /* frame has imacpc value available */
 	
     JSFRAME_SPECIAL            = JSFRAME_DEBUGGER | JSFRAME_EVAL
 };
 
+/* Flags to toggle Interpret() execution. */
+enum JSInterpFlags {
+    JSINTERP_RECORD         =   0x01, /* interpreter has been started to record/run traces */
+    JSINTERP_SAFEPOINT      =   0x02  /* interpreter should leave on a method JIT safe point */
+};
+
 namespace js { namespace mjit {
     class Compiler;
     class InlineFrameAssembler;
 } }
 
 /*
  * JS stack frame, may be allocated on the C stack by native callers.  Always
  * allocated on cx->stackPool for calls from the interpreter to an interpreted
@@ -752,17 +756,17 @@ extern JS_FORCES_STACK bool
 Execute(JSContext *cx, JSObject *chain, JSScript *script,
         JSStackFrame *down, uintN flags, Value *result);
 
 /*
  * Execute the caller-initialized frame for a user-defined script or function
  * pointed to by cx->fp until completion or error.
  */
 extern JS_REQUIRES_STACK bool
-Interpret(JSContext *cx, JSStackFrame *stopFp, uintN inlineCallCount = 0);
+Interpret(JSContext *cx, JSStackFrame *stopFp, uintN inlineCallCount = 0, uintN interpFlags = 0);
 
 extern JS_REQUIRES_STACK bool
 RunScript(JSContext *cx, JSScript *script, JSFunction *fun, JSObject *scopeChain);
 
 #define JSPROP_INITIALIZER 0x100   /* NB: Not a valid property attribute. */
 
 extern bool
 CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -290,26 +290,26 @@ ValueToTypeChar(const Value &v)
 
 
 /* Blacklist parameters. */
 
 /*
  * Number of iterations of a loop where we start tracing.  That is, we don't
  * start tracing until the beginning of the HOTLOOP-th iteration.
  */
-#define HOTLOOP 4
+#define HOTLOOP 8
 
 /* Attempt recording this many times before blacklisting permanently. */
 #define BL_ATTEMPTS 2
 
 /* Skip this many hits before attempting recording again, after an aborted attempt. */
 #define BL_BACKOFF 32
 
 /* Minimum number of times a loop must execute, or else it is blacklisted. */
-#define MIN_LOOP_ITERS 2
+#define MIN_LOOP_ITERS 8
 
 /* Number of times we wait to exit on a side exit before we try to extend the tree. */
 #define HOTEXIT 1
 
 /* Number of times we try to extend the tree along a side exit. */
 #define MAXEXIT 3
 
 /* Maximum number of peer trees allowed. */
@@ -16249,20 +16249,17 @@ MonitorTracePoint(JSContext* cx, uintN& 
         return TPA_Nothing;
     if (!RecordTree(cx, tree->first, NULL, 0, globalSlots))
         return TPA_Nothing;
 
   interpret:
     JS_ASSERT(TRACE_RECORDER(cx));
 
     /* Locked and loaded with a recorder. Ask the interperter to go run some code. */
-    fp->flags |= JSFRAME_RECORDING;
-    if (!Interpret(cx, fp, inlineCallCount))
+    if (!Interpret(cx, fp, inlineCallCount, JSINTERP_RECORD))
         return TPA_Error;
 
-    fp->flags &= ~JSFRAME_RECORDING;
-
     return TPA_RanStuff;
 }
 
 #endif
 
 } /* namespace js */
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -678,21 +678,18 @@ js_InternalThrow(VMFrame &f)
             break;
 
         JS_ASSERT(f.regs.sp == cx->regs->sp);
         InlineReturn(f, JS_FALSE);
     }
 
     JS_ASSERT(f.regs.sp == cx->regs->sp);
 
-    if (!pc) {
-        *f.oldRegs = f.regs;
-        f.cx->setCurrentRegs(f.oldRegs);
+    if (!pc)
         return NULL;
-    }
 
     return cx->fp()->getScript()->pcToNative(pc);
 }
 
 void JS_FASTCALL
 stubs::GetCallObject(VMFrame &f)
 {
     JS_ASSERT(f.fp()->getFunction()->isHeavyweight());
@@ -776,19 +773,17 @@ PartialInterpret(VMFrame &f)
 {
     JSContext *cx = f.cx;
     JSStackFrame *fp = cx->fp();
 
     JS_ASSERT(fp->hasIMacroPC() || !fp->getScript()->nmap ||
               !fp->getScript()->nmap[cx->regs->pc - fp->getScript()->code]);
 
     JSBool ok = JS_TRUE;
-    fp->flags |= JSFRAME_BAILING;
-    ok = Interpret(cx, fp);
-    fp->flags &= ~JSFRAME_BAILING;
+    ok = Interpret(cx, fp, 0, JSINTERP_SAFEPOINT);
 
     f.fp() = cx->fp();
 
     return ok;
 }
 
 JS_STATIC_ASSERT(JSOP_NOP == 0);
 
@@ -802,44 +797,44 @@ FrameIsFinished(JSContext *cx)
         ? op
         : JSOP_NOP;
 }
 
 static bool
 RemoveExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
 {
     JSContext *cx = f.cx;
-    while (cx->fp() != entryFrame) {
+    while (cx->fp() != entryFrame || entryFrame->hasIMacroPC()) {
         JSStackFrame *fp = cx->fp();
-        fp->flags &= ~JSFRAME_RECORDING;
 
         if (AtSafePoint(cx)) {
             JSScript *script = fp->getScript();
             if (!JaegerShotAtSafePoint(cx, script->nmap[cx->regs->pc - script->code])) {
                 if (!SwallowErrors(f, entryFrame))
                     return false;
 
                 /* Could be anywhere - restart outer loop. */
                 continue;
             }
             InlineReturn(f, JS_TRUE);
             AdvanceReturnPC(cx);
         } else {
             if (!PartialInterpret(f)) {
                 if (!SwallowErrors(f, entryFrame))
                     return false;
-            } else {
+            } else if (cx->fp() != entryFrame) {
                 /*
                  * Partial interpret could have dropped us anywhere. Deduce the
                  * edge case: at a RETURN, needing to pop a frame.
                  */
-                if (!cx->fp()->hasIMacroPC() && FrameIsFinished(cx)) {
+                JS_ASSERT(!cx->fp()->hasIMacroPC());
+                if (FrameIsFinished(cx)) {
                     JSOp op = JSOp(*cx->regs->pc);
                     if (op == JSOP_RETURN && !(cx->fp()->flags & JSFRAME_BAILED_AT_RETURN))
-                        fp->setReturnValue(f.regs.sp[-1]);
+                        cx->fp()->setReturnValue(f.regs.sp[-1]);
                     InlineReturn(f, JS_TRUE);
                     AdvanceReturnPC(cx);
                 }
             }
         }
     }
 
     return true;
@@ -944,52 +939,43 @@ RunTracer(VMFrame &f)
      * moves |oldFp->rval| into the scripted return registers.
      */
 
   restart:
     /* Step 1. Initial removal of excess frames. */
     if (!RemoveExcessFrames(f, entryFrame))
         THROWV(NULL);
 
-    /* Step 2. If there's an imacro on the entry frame, remove it. */
-    entryFrame->flags &= ~JSFRAME_RECORDING;
-    while (entryFrame->hasIMacroPC()) {
-        if (!PartialInterpret(f)) {
-            if (!SwallowErrors(f, entryFrame))
-                THROWV(NULL);
-        }
+    /* IMacros are guaranteed to have been removed by now. */
+    JS_ASSERT(!entryFrame->hasIMacroPC());
 
-        /* After partial interpreting, we could have more frames again. */
-        goto restart;
-    }
-
-    /* Step 3.1. If entryFrame is at a safe point, just leave. */
+    /* Step 2. If entryFrame is at a safe point, just leave. */
     if (AtSafePoint(cx)) {
         uint32 offs = uint32(cx->regs->pc - entryFrame->getScript()->code);
         JS_ASSERT(entryFrame->getScript()->nmap[offs]);
         return entryFrame->getScript()->nmap[offs];
     }
 
-    /* Step 3.2. If entryFrame is at a RETURN, then leave slightly differently. */
+    /* Step 3. If entryFrame is at a RETURN, then leave slightly differently. */
     if (JSOp op = FrameIsFinished(cx)) {
         /* We're not guaranteed that the RETURN was run. */
         if (op == JSOP_RETURN && !(entryFrame->flags & JSFRAME_BAILED_AT_RETURN))
             entryFrame->setReturnValue(f.regs.sp[-1]);
 
         /* Don't pop the frame if it's maybe owned by an Invoke. */
         if (f.fp() != f.entryFp) {
             if (!InlineReturn(f, JS_TRUE))
                 THROWV(NULL);
         }
         void *retPtr = JS_FUNC_TO_DATA_PTR(void *, InjectJaegerReturn);
         *f.returnAddressLocation() = retPtr;
         return NULL;
     }
 
-    /* Step 3.3. Do a partial interp, then restart the whole process. */
+    /* Step 4. Do a partial interp, then restart the whole process. */
     if (!PartialInterpret(f)) {
         if (!SwallowErrors(f, entryFrame))
             THROWV(NULL);
     }
 
     goto restart;
 }
 
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -115,27 +115,19 @@ PopActiveVMFrame(VMFrame &f)
 {
     JS_ASSERT(JS_METHODJIT_DATA(f.cx).activeFrame);
     JS_METHODJIT_DATA(f.cx).activeFrame = JS_METHODJIT_DATA(f.cx).activeFrame->previous;    
 }
 
 extern "C" void JS_FASTCALL
 SetVMFrameRegs(VMFrame &f)
 {
-    f.oldRegs = f.cx->regs;
     f.cx->setCurrentRegs(&f.regs);
 }
 
-extern "C" void JS_FASTCALL
-UnsetVMFrameRegs(VMFrame &f)
-{
-    *f.oldRegs = f.regs;
-    f.cx->setCurrentRegs(f.oldRegs);
-}
-
 #if defined(__APPLE__) || defined(XP_WIN)
 # define SYMBOL_STRING(name) "_" #name
 #else
 # define SYMBOL_STRING(name) #name
 #endif
 
 JS_STATIC_ASSERT(offsetof(JSFrameRegs, sp) == 0);
 
@@ -222,18 +214,16 @@ SYMBOL_STRING(JaegerTrampoline) ":"     
     "call " SYMBOL_STRING_RELOC(PushActiveVMFrame) "\n"
 
     /*
      * Jump into into the JIT'd code.
      */
     "call *0(%rsp)"                      "\n"
     "movq %rsp, %rdi"                    "\n"
     "call " SYMBOL_STRING_RELOC(PopActiveVMFrame) "\n"
-    "movq %rsp, %rdi"                    "\n"
-    "call " SYMBOL_STRING_RELOC(UnsetVMFrameRegs) "\n"
 
     "addq $0x58, %rsp"                   "\n"
     "popq %rbx"                          "\n"
     "popq %r15"                          "\n"
     "popq %r14"                          "\n"
     "popq %r13"                          "\n"
     "popq %r12"                          "\n"
     "popq %rbp"                          "\n"
@@ -329,18 +319,16 @@ SYMBOL_STRING(JaegerTrampoline) ":"     
     "movl  %esp, %ecx"                   "\n"
     "call " SYMBOL_STRING_RELOC(SetVMFrameRegs) "\n"
     "movl  %esp, %ecx"                   "\n"
     "call " SYMBOL_STRING_RELOC(PushActiveVMFrame) "\n"
 
     "call  *16(%ebp)"                    "\n"
     "movl  %esp, %ecx"                   "\n"
     "call " SYMBOL_STRING_RELOC(PopActiveVMFrame) "\n"
-    "movl  %esp, %ecx"                   "\n"
-    "call " SYMBOL_STRING_RELOC(UnsetVMFrameRegs) "\n"
 
     "addl $0x2C, %esp"                   "\n"
     "popl %ebx"                          "\n"
     "popl %edi"                          "\n"
     "popl %esi"                          "\n"
     "popl %ebp"                          "\n"
     "movl $1, %eax"                      "\n"
     "ret"                                "\n"
@@ -504,18 +492,16 @@ SYMBOL_STRING(JaegerTrampoline) ":"     
 "   bl  " SYMBOL_STRING_RELOC(PushActiveVMFrame)"\n"
 
     /* Call the compiled JavaScript function. */
 "   blx     r4"                                 "\n"
 
     /* Tidy up. */
 "   mov     r0, sp"                             "\n"
 "   bl  " SYMBOL_STRING_RELOC(PopActiveVMFrame) "\n"
-"   mov     r0, sp"                             "\n"
-"   bl  " SYMBOL_STRING_RELOC(UnsetVMFrameRegs) "\n"
 
     /* Skip past the parameters we pushed (such as cx and the like). */
 "   add     sp, sp, #(4*7 + 4*4)"               "\n"
 
     /* Set a 'true' return value to indicate successful completion. */
 "   mov     r0, #1"                         "\n"
 "   pop     {r4-r11,pc}"                    "\n"
 );
@@ -623,18 +609,16 @@ extern "C" {
             mov  ecx, esp;
             call SetVMFrameRegs;
             mov  ecx, esp;
             call PushActiveVMFrame;
 
             call [ebp + 16];
             mov  ecx, esp;
             call PopActiveVMFrame;
-            mov  ecx, esp;
-            call UnsetVMFrameRegs;
 
             add esp, 0x2C;
 
             pop ebx;
             pop edi;
             pop esi;
             pop ebp;
             mov eax, 1;
@@ -765,19 +749,23 @@ EnterMethodJIT(JSContext *cx, JSStackFra
      * stack frame. By passing nslots = 0, we ensure only sizeof(JSStackFrame).
      */
     if (fpAsVp + VALUES_PER_STACK_FRAME >= stackLimit &&
         !stack.ensureSpace(cx, fpAsVp, cx->regs->sp, stackLimit, 0)) {
         js_ReportOutOfScriptQuota(cx);
         return false;
     }
 
+    JSFrameRegs *oldRegs = cx->regs;
+
     JSAutoResolveFlags rf(cx, JSRESOLVE_INFER);
     JSBool ok = JaegerTrampoline(cx, fp, code, stackLimit, safePoint);
 
+    cx->setCurrentRegs(oldRegs);
+
     JS_ASSERT(checkFp == cx->fp());
 
 #ifdef JS_METHODJIT_SPEW
     prof.stop();
     JaegerSpew(JSpew_Prof, "script run took %d ms\n", prof.time_ms());
 #endif
 
     return ok;
--- a/js/src/methodjit/MethodJIT.h
+++ b/js/src/methodjit/MethodJIT.h
@@ -61,17 +61,17 @@ struct VMFrame
         struct {
             void *ptr;
             void *ptr2;
             void *ptr3;
         } x;
     } u;
 
     VMFrame      *previous;
-    JSFrameRegs  *oldRegs;
+    void         *unused;
     JSFrameRegs  regs;
     JSContext    *cx;
     Value        *stackLimit;
     JSStackFrame *entryFp;
 
 #if defined(JS_CPU_X86)
     void *savedEBX;
     void *savedEDI;
--- a/js/src/trace-test/lib/prolog.js
+++ b/js/src/trace-test/lib/prolog.js
@@ -1,13 +1,13 @@
 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 
 const HAVE_TM = 'tracemonkey' in this;
 
-const HOTLOOP = HAVE_TM ? tracemonkey.HOTLOOP : 2;
+const HOTLOOP = HAVE_TM ? tracemonkey.HOTLOOP : 8;
 const RECORDLOOP = HOTLOOP;
 const RUNLOOP = HOTLOOP + 1;
 
 var checkStats;
 if (HAVE_TM) {
     checkStats = function(stats)
     {
         // Temporarily disabled while we work on heuristics.
--- a/js/src/trace-test/tests/basic/testBug504520.js
+++ b/js/src/trace-test/tests/basic/testBug504520.js
@@ -1,11 +1,11 @@
 function testBug504520() {
     // A bug involving comparisons.
-    var arr = [1/0, 1/0, 1/0, 1/0, 1/0, 0];
+    var arr = [1/0, 1/0, 1/0, 1/0, 1/0, 1/0, 1/0, 1/0, 1/0, 0];
     assertEq(arr.length > RUNLOOP, true);
 
     var s = '';
     for (var i = 0; i < arr.length; i++)
         arr[i] >= 1/0 ? null : (s += i);
-    assertEq(s, '5');
+    assertEq(s, '9');
 }
 testBug504520();
--- a/js/src/trace-test/tests/basic/testBug504520Harder.js
+++ b/js/src/trace-test/tests/basic/testBug504520Harder.js
@@ -6,19 +6,19 @@ function testBug504520Harder() {
         for each (var y in vals) {
             for each (var op in ops) {
                 for each (var z in vals) {
                     // Assume eval is correct. This depends on the global
                     // Infinity property not having been reassigned.
                     var xz = eval(x + op + z);
                     var yz = eval(y + op + z);
 
-                    var arr = [x, x, x, x, x, y];
+                    var arr = [x, x, x, x, x, x, x, x, x, y];
                     assertEq(arr.length > RUNLOOP, true);
-                    var expected = [xz, xz, xz, xz, xz, yz];
+                    var expected = [xz, xz, xz, xz, xz, xz, xz, xz, xz, yz];
 
                     // ?: looks superfluous but that's what we're testing here
                     var fun = eval(
                         '(function (arr, results) {\n' +
                         '    for (let i = 0; i < arr.length; i++)\n' +
                         '        results.push(arr[i]' + op + z + ' ? "true" : "false");\n' +
                         '});\n');
                     var actual = [];