Bug 1063328 - Fix on-stack live iterator handling when bailing out in-place due to debug mode OSR. (r=jandem)
authorShu-yu Guo <shu@rfrn.org>
Thu, 13 Nov 2014 14:39:40 -0800
changeset 215677 1176cc3c3b34
parent 215676 bb2f13ba7b1c
child 215678 f8e316fa65bb
push id27823
push usercbook@mozilla.com
push date2014-11-14 11:59 +0000
treeherdermozilla-central@bbb68df450c2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1063328
milestone36.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
Bug 1063328 - Fix on-stack live iterator handling when bailing out in-place due to debug mode OSR. (r=jandem)
js/src/jit/BaselineBailouts.cpp
js/src/jit/IonFrames.cpp
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -440,16 +440,38 @@ GetNextNonLoopEntryPc(jsbytecode *pc)
     JSOp op = JSOp(*pc);
     if (op == JSOP_GOTO)
         return pc + GET_JUMP_OFFSET(pc);
     if (op == JSOP_LOOPENTRY || op == JSOP_NOP || op == JSOP_LOOPHEAD)
         return GetNextPc(pc);
     return pc;
 }
 
+static bool
+HasLiveIteratorAtStackDepth(JSScript *script, jsbytecode *pc, uint32_t stackDepth)
+{
+    if (!script->hasTrynotes())
+        return false;
+
+    JSTryNote *tn = script->trynotes()->vector;
+    JSTryNote *tnEnd = tn + script->trynotes()->length;
+    uint32_t pcOffset = uint32_t(pc - script->main());
+    for (; tn != tnEnd; ++tn) {
+        if (pcOffset < tn->start)
+            continue;
+        if (pcOffset >= tn->start + tn->length)
+            continue;
+
+        if (tn->kind == JSTRY_ITER && stackDepth == tn->stackDepth)
+            return true;
+    }
+
+    return false;
+}
+
 // For every inline frame, we write out the following data:
 //
 //                      |      ...      |
 //                      +---------------+
 //                      |  Descr(???)   |  --- Descr size here is (PREV_FRAME_SIZE)
 //                      +---------------+
 //                      |  ReturnAddr   |
 //             --       +===============+  --- OVERWRITE STARTS HERE  (START_STACK_ADDR)
@@ -842,20 +864,21 @@ InitFromBailout(JSContext *cx, HandleScr
             v = cx->runtime()->jitRuntime()->takeIonReturnOverride();
         } else if (excInfo && excInfo->propagatingIonExceptionForDebugMode()) {
             // If we are in the middle of propagating an exception from Ion by
             // bailing to baseline due to debug mode, we might not have all
             // the stack if we are at the newest frame.
             //
             // For instance, if calling |f()| pushed an Ion frame which threw,
             // the snapshot expects the return value to be pushed, but it's
-            // possible nothing was pushed before we threw. Iterators might
-            // still be on the stack, so we can't just drop the stack.
+            // possible nothing was pushed before we threw. We can't drop
+            // iterators, however, so read them out. They will be closed by
+            // HandleExceptionBaseline.
             MOZ_ASSERT(cx->compartment()->isDebuggee());
-            if (iter.moreFrames())
+            if (iter.moreFrames() || HasLiveIteratorAtStackDepth(script, pc, i + 1))
                 v = iter.read();
             else
                 v = MagicValue(JS_OPTIMIZED_OUT);
         } else {
             v = iter.read();
         }
         if (!builder.writeValue(v, "StackValue"))
             return false;
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -415,17 +415,16 @@ CloseLiveIterator(JSContext *cx, const I
 
 static void
 HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromException *rfe,
                    bool *overrecursed)
 {
     RootedScript script(cx, frame.script());
     jsbytecode *pc = frame.pc();
 
-    bool bailedOutForDebugMode = false;
     if (cx->compartment()->isDebuggee()) {
         // We need to bail when debug mode is active to observe the Debugger's
         // exception unwinding handler if either a Debugger is observing all
         // execution in the compartment, or it has observed this frame, i.e.,
         // by there being a debuggee RematerializedFrame.
         bool shouldBail = cx->compartment()->debugObservesAllExecution();
         if (!shouldBail) {
             JitActivation *act = cx->mainThread().activation()->asJit();
@@ -445,17 +444,18 @@ HandleExceptionIon(JSContext *cx, const 
             //
             // An empty exception info denotes that we're propagating an Ion
             // exception due to debug mode, which BailoutIonToBaseline needs to
             // know. This is because we might not be able to fully reconstruct up
             // to the stack depth at the snapshot, as we could've thrown in the
             // middle of a call.
             ExceptionBailoutInfo propagateInfo;
             uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, propagateInfo, overrecursed);
-            bailedOutForDebugMode = retval == BAILOUT_RETURN_OK;
+            if (retval == BAILOUT_RETURN_OK)
+                return;
         }
     }
 
     if (!script->hasTrynotes())
         return;
 
     JSTryNote *tn = script->trynotes()->vector;
     JSTryNote *tnEnd = tn + script->trynotes()->length;
@@ -476,17 +476,17 @@ HandleExceptionIon(JSContext *cx, const 
             CloseLiveIterator(cx, frame, localSlot);
             break;
           }
 
           case JSTRY_LOOP:
             break;
 
           case JSTRY_CATCH:
-            if (cx->isExceptionPending() && !bailedOutForDebugMode) {
+            if (cx->isExceptionPending()) {
                 // Ion can compile try-catch, but bailing out to catch
                 // exceptions is slow. Reset the warm-up counter so that if we
                 // catch many exceptions we won't Ion-compile the script.
                 script->resetWarmUpCounter();
 
                 // Bailout at the start of the catch block.
                 jsbytecode *catchPC = script->main() + tn->start + tn->length;
                 ExceptionBailoutInfo excInfo(frame.frameNo(), catchPC, tn->stackDepth);