Bug 1004447 - Fix unwound scope override pc logic to only override pc if we need to call the debug epilogue. (r=jandem)
authorShu-yu Guo <shu@rfrn.org>
Thu, 01 May 2014 14:23:53 -0700
changeset 181651 2194f49fce4f9f71d321abb2be47af975747ae00
parent 181650 734b0e34e002dc218c64abc4aa50f2d780b2a6d5
child 181652 1efb117b969c1267463c1abf50b3fbc17b58be7e
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersjandem
bugs1004447
milestone32.0a1
Bug 1004447 - Fix unwound scope override pc logic to only override pc if we need to call the debug epilogue. (r=jandem)
js/src/jit-test/tests/debug/bug1004447.js
js/src/jit/IonFrames.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1004447.js
@@ -0,0 +1,23 @@
+// Tests that earlier try notes don't interfere with later exception handling.
+
+var g = newGlobal();
+g.debuggeeGlobal = this;
+g.eval("(" + function () {
+  dbg = new Debugger(debuggeeGlobal);
+} + ")();");
+var myObj = { p1: 'a', }
+try {
+  with(myObj) {
+    do {
+      throw value;
+    } while(false);
+  }
+} catch(e) {
+  // The above is expected to throw.
+}
+
+try {
+  if(!(p1 === 1)) { }
+} catch (e) {
+  // The above is expected to throw.
+}
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -459,17 +459,17 @@ HandleExceptionIon(JSContext *cx, const 
           default:
             MOZ_ASSUME_UNREACHABLE("Unexpected try note");
         }
     }
 }
 
 static void
 HandleExceptionBaseline(JSContext *cx, const JitFrameIterator &frame, ResumeFromException *rfe,
-                        bool *calledDebugEpilogue)
+                        jsbytecode **unwoundScopeToPc, bool *calledDebugEpilogue)
 {
     JS_ASSERT(frame.isBaselineJS());
     JS_ASSERT(!*calledDebugEpilogue);
 
     RootedScript script(cx);
     jsbytecode *pc;
     frame.baselineScriptAndPc(script.address(), &pc);
 
@@ -523,27 +523,18 @@ HandleExceptionBaseline(JSContext *cx, c
         // See the big comment in TryNoteIter::settle for more info.
         JS_ASSERT(frame.baselineFrame()->numValueSlots() >= script->nfixed());
         size_t stackDepth = frame.baselineFrame()->numValueSlots() - script->nfixed();
         if (tn->stackDepth > stackDepth)
             continue;
 
         // Unwind scope chain (pop block objects).
         if (cx->isExceptionPending()) {
-            jsbytecode *unwindPc = script->main() + tn->start;
-            UnwindScope(cx, si, unwindPc);
-
-            // If we still need to call DebugEpilogue, we must remember the pc
-            // we unwound the scope chain to, as it will be out of sync with
-            // the frame's actual pc.
-            if (tn->kind != JSTRY_CATCH && tn->kind != JSTRY_FINALLY &&
-                cx->compartment()->debugMode() && !*calledDebugEpilogue)
-            {
-                frame.baselineFrame()->setUnwoundScopeOverridePc(unwindPc);
-            }
+            *unwoundScopeToPc = script->main() + tn->start;
+            UnwindScope(cx, si, *unwoundScopeToPc);
         }
 
         // Compute base pointer and stack pointer.
         rfe->framePointer = frame.fp() - BaselineFrame::FramePointerOffset;
         rfe->stackPointer = rfe->framePointer - BaselineFrame::Size() -
             (script->nfixed() + tn->stackDepth) * sizeof(Value);
 
         switch (tn->kind) {
@@ -665,17 +656,20 @@ HandleException(ResumeFromException *rfe
 
             if (invalidated)
                 ionScript->decref(cx->runtime()->defaultFreeOp());
 
         } else if (iter.isBaselineJS()) {
             // It's invalid to call DebugEpilogue twice for the same frame.
             bool calledDebugEpilogue = false;
 
-            HandleExceptionBaseline(cx, iter, rfe, &calledDebugEpilogue);
+            // Remember the pc we unwound the scope to.
+            jsbytecode *unwoundScopeToPc = nullptr;
+
+            HandleExceptionBaseline(cx, iter, rfe, &unwoundScopeToPc, &calledDebugEpilogue);
 
             // If we are propagating an exception through a frame with
             // on-stack recompile info, we should free the allocated
             // RecompileInfo struct before we leave this block, as we will not
             // be returning to the recompile handler.
             //
             // We cannot delete it immediately because of the call to
             // iter.baselineScriptAndPc below.
@@ -689,16 +683,22 @@ HandleException(ResumeFromException *rfe
             probes::ExitScript(cx, script, script->functionNonDelazifying(),
                                iter.baselineFrame()->hasPushedSPSFrame());
             // After this point, any pushed SPS frame would have been popped if it needed
             // to be.  Unset the flag here so that if we call DebugEpilogue below,
             // it doesn't try to pop the SPS frame again.
             iter.baselineFrame()->unsetPushedSPSFrame();
 
             if (cx->compartment()->debugMode() && !calledDebugEpilogue) {
+                // If we still need to call the DebugEpilogue, we must
+                // remember the pc we unwound the scope chain to, as it will
+                // be out of sync with the frame's actual pc.
+                if (unwoundScopeToPc)
+                    iter.baselineFrame()->setUnwoundScopeOverridePc(unwoundScopeToPc);
+
                 // If DebugEpilogue returns |true|, we have to perform a forced
                 // return, e.g. return frame->returnValue() to the caller.
                 BaselineFrame *frame = iter.baselineFrame();
                 RootedScript script(cx);
                 jsbytecode *pc;
                 iter.baselineScriptAndPc(script.address(), &pc);
                 if (jit::DebugEpilogue(cx, frame, pc, false)) {
                     JS_ASSERT(frame->hasReturnValue());