Bug 1334799 - Handle stack value in correct order when leaving for-of loop from finally block. r=shu, a=ritu
authorTooru Fujisawa <arai_a@mac.com>
Sun, 29 Jan 2017 05:53:41 +0900
changeset 358857 62764baa6ef6dec70b1f9248c6386eecc002ba7b
parent 358856 900c746565fd10fb9feb7e28b6582030e77fee1b
child 358858 cb0502e9fcd7562a25d6e24b490bb9908042db7b
push id10664
push userryanvm@gmail.com
push dateWed, 01 Feb 2017 23:16:10 +0000
treeherdermozilla-aurora@d06f2bf30b22 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshu, ritu
bugs1334799
milestone53.0a2
Bug 1334799 - Handle stack value in correct order when leaving for-of loop from finally block. r=shu, a=ritu
js/src/frontend/BytecodeEmitter.cpp
js/src/tests/ecma_6/Statements/for-inof-finally.js
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2397,16 +2397,19 @@ NonLocalExitControl::prepareForNonLocalJ
                 return false;
             break;
 
           default:
             break;
         }
     }
 
+    if (!flushPops(bce_))
+        return false;
+
     if (target && target->is<ForOfLoopControl>() && emitIteratorCloseAtTarget) {
         hasForOfLoopsWithIteratorClose = true;
         if (!target->as<ForOfLoopControl>().finishIterCloseTryNote(bce_))
             return false;
 
         // The iterator and the current value are on the stack. At the level
         // of the target block, there's bytecode after the loop that will pop
         // the iterator and the value, so duplicate the iterator and call
@@ -2418,19 +2421,16 @@ NonLocalExitControl::prepareForNonLocalJ
     }
 
     EmitterScope* targetEmitterScope = target ? target->emitterScope() : bce_->varEmitterScope;
     for (; es != targetEmitterScope; es = es->enclosingInFrame()) {
         if (!leaveScope(es))
             return false;
     }
 
-    if (!flushPops(bce_))
-        return false;
-
     // See comment in ForOfLoopControl.
     if (hasForOfLoopsWithIteratorClose) {
         for (NestableControl* control = bce_->innermostNestableControl;
              control != target;
              control = control->enclosing())
         {
             if (control->is<ForOfLoopControl>())
                 control->as<ForOfLoopControl>().startNewIterCloseTryNote(bce_);
--- a/js/src/tests/ecma_6/Statements/for-inof-finally.js
+++ b/js/src/tests/ecma_6/Statements/for-inof-finally.js
@@ -1,54 +1,78 @@
 var BUGNUMBER = 1332881;
 var summary =
   "Leaving for-in and try should handle stack value in correct order";
 
 print(BUGNUMBER + ": " + summary);
 
+var called = 0;
+function reset() {
+  called = 0;
+}
+var obj = {
+  [Symbol.iterator]() {
+    return {
+      next() {
+        return { value: 10, done: false };
+      },
+      return() {
+        called++;
+        return {};
+      }
+    };
+  }
+};
+
 var a = (function () {
     for (var x in [0]) {
         try {} finally {
             return 11;
         }
     }
 })();
 assertEq(a, 11);
 
+reset();
 var b = (function () {
-    for (var x of [0]) {
+    for (var x of obj) {
         try {} finally {
             return 12;
         }
     }
 })();
+assertEq(called, 1);
 assertEq(b, 12);
 
+reset();
 var c = (function () {
     for (var x in [0]) {
-        for (var y of [0]) {
+        for (var y of obj) {
             try {} finally {
                 return 13;
             }
         }
     }
 })();
+assertEq(called, 1);
 assertEq(c, 13);
 
+reset();
 var d = (function () {
     for (var x in [0]) {
-        for (var y of [0]) {
+        for (var y of obj) {
             try {} finally {
                 for (var z in [0]) {
-                    for (var w of [0]) {
+                    for (var w of obj) {
                         try {} finally {
                             return 14;
                         }
                     }
                 }
             }
         }
     }
 })();
+assertEq(called, 2);
 assertEq(d, 14);
 
 if (typeof reportCompare === "function")
   reportCompare(true, true);