Restore frame pointer at exception block entry before invoking any trap, bug 658491. r=jorendorff.
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 23 Aug 2011 14:43:26 -0500
changeset 77167 64d97a61fe681034ca819e65fb7d21654081e450
parent 77166 dad9e816d52d1ec8f4f48bc0cba9ac64ef593eca
child 77168 2b0b39d1a4858d5a98584d23d4a139c464af8d37
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)
reviewersjorendorff
bugs658491
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
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/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);