Restore frame pointer at exception block entry before invoking any trap, bug 658491. r=jorendorff.
☠☠ backed out by f7697e32bbf5 ☠ ☠
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 23 Aug 2011 14:43:26 -0500
changeset 75763 62f8ca0717d690f45d2975ad6a2168fdd88fe139
parent 75762 305a3a0e26fdeb31669d76ee901d84073aadeb00
child 75764 d44b0dd28b0d1fe7f1ed83ccc85dad95a1be1cd6
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersjorendorff
bugs658491
milestone9.0a1
Restore frame pointer at exception block entry before invoking any trap, bug 658491. r=jorendorff.
js/src/jit-test/tests/basic/bug657975.js
js/src/jit-test/tests/debug/onEnterFrame-04.js
js/src/jsapi-tests/testDebugger.cpp
js/src/methodjit/Compiler.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug657975.js
@@ -0,0 +1,8 @@
+// |jit-test| debug
+
+// bug 658491
+function f7() {
+  try { y = w; } catch(y) {}
+}
+trap(f7, 14, '')
+f7()
--- a/js/src/jsapi-tests/testDebugger.cpp
+++ b/js/src/jsapi-tests/testDebugger.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=99:
  */
 
 #include "tests.h"
 #include "jsdbgapi.h"
+#include "jscntxt.h"
 
 static int callCount[2] = {0, 0};
 
 static void *
 callCountHook(JSContext *cx, JSStackFrame *fp, JSBool before, JSBool *ok, void *closure)
 {
     callCount[before]++;
 
@@ -247,8 +248,47 @@ bool testIndirectEval(JSObject *scope, J
     }
 
     jsval hitsv;
     EVAL("hits", &hitsv);
     CHECK_SAME(hitsv, INT_TO_JSVAL(expectedHits));
     return true;
 }
 END_TEST(testDebugger_newScriptHook)
+
+BEGIN_TEST(testDebugger_singleStepThrow)
+    {
+        CHECK(JS_SetDebugModeForCompartment(cx, cx->compartment, true));
+        CHECK(JS_SetInterrupt(rt, onStep, NULL));
+
+        uint32 opts = JS_GetOptions(cx);
+        opts |= JSOPTION_METHODJIT | JSOPTION_METHODJIT_ALWAYS;
+        opts &= ~JSOPTION_JIT;
+        JS_SetOptions(cx, opts);
+
+        CHECK(JS_DefineFunction(cx, global, "setStepMode", setStepMode, 0, 0));
+        EXEC("var e;\n"
+             "setStepMode();\n"
+             "function f() { throw 0; }\n"
+             "try { f(); }\n"
+             "catch (x) { e = x; }\n");
+        return true;
+    }
+
+    static JSBool
+    setStepMode(JSContext *cx, uintN argc, jsval *vp)
+    {
+        JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
+        JS_ASSERT(fp);
+        JSScript *script = JS_GetFrameScript(cx, fp);
+        JS_ASSERT(script);
+        if (!JS_SetSingleStepMode(cx, script, true))
+            return false;
+        JS_SET_RVAL(cx, vp, JSVAL_VOID);
+        return true;
+    }
+
+    static JSTrapStatus
+    onStep(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure)
+    {
+        return JSTRAP_CONTINUE;
+    }
+END_TEST(testDebugger_singleStepThrow)
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -937,16 +937,27 @@ mjit::Compiler::generateMethod()
             frame.syncAndForgetEverything(opinfo->stackDepth);
             opinfo->safePoint = true;
         }
         jumpMap[uint32(PC - script->code)] = masm.label();
 
         SPEW_OPCODE();
         JS_ASSERT(frame.stackDepth() == opinfo->stackDepth);
 
+        // If this is an exception entry point, then jsl_InternalThrow has set
+        // VMFrame::fp to the correct fp for the entry point. We need to copy
+        // that value here to FpReg so that FpReg also has the correct sp.
+        // Otherwise, we would simply be using a stale FpReg value.
+        // Additionally, we check the interrupt flag to allow interrupting
+        // deeply nested exception handling.
+        if (op == JSOP_ENTERBLOCK && analysis->getCode(PC).exceptionEntry) {
+            restoreFrameRegs(masm);
+            interruptCheckHelper();
+        }
+
         if (trap) {
             prepareStubCall(Uses(0));
             masm.move(Imm32(trap), Registers::ArgReg1);
             Call cl = emitStubCall(JS_FUNC_TO_DATA_PTR(void *, stubs::Trap));
             InternalCallSite site(masm.callReturnOffset(cl), PC,
                                   CallSite::MAGIC_TRAP_ID, true, false);
             addCallSite(site);
         } else if (savedTraps && savedTraps[PC - script->code]) {
@@ -4826,27 +4837,16 @@ mjit::Compiler::jumpAndTrace(Jump j, jsb
     stubcc.masm.jump(Registers::ReturnReg);
 #endif
     return true;
 }
 
 void
 mjit::Compiler::enterBlock(JSObject *obj)
 {
-    // If this is an exception entry point, then jsl_InternalThrow has set
-    // VMFrame::fp to the correct fp for the entry point. We need to copy
-    // that value here to FpReg so that FpReg also has the correct sp.
-    // Otherwise, we would simply be using a stale FpReg value.
-    // Additionally, we check the interrupt flag to allow interrupting
-    // deeply nested exception handling.
-    if (analysis->getCode(PC).exceptionEntry) {
-        restoreFrameRegs(masm);
-        interruptCheckHelper();
-    }
-
     uint32 oldFrameDepth = frame.localSlots();
 
     /* For now, don't bother doing anything for this opcode. */
     frame.syncAndForgetEverything();
     masm.move(ImmPtr(obj), Registers::ArgReg1);
     uint32 n = js_GetEnterBlockStackDefs(cx, script, PC);
     INLINE_STUBCALL(stubs::EnterBlock);
     frame.enterBlock(n);