Bug 1480390: Use TryNoteIter in HasLiveStackValueAtDepth r=tcampbell
☠☠ backed out by 850b70af2f47 ☠ ☠
authorIain Ireland <iireland@mozilla.com>
Fri, 11 Jan 2019 20:04:34 +0000
changeset 510933 627f1def8aeb7c4f38b4624aadf75050e339ee92
parent 510932 797e7094701deb120cf9ba0c4d8b8a8200003899
child 510934 9a76ebcfbe9d5d8ff5731e59aed195a2c9ffb8cd
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1480390
milestone66.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 1480390: Use TryNoteIter in HasLiveStackValueAtDepth r=tcampbell Differential Revision: https://phabricator.services.mozilla.com/D14785
js/src/jit-test/tests/debug/bug1480390.js
js/src/jit/BaselineBailouts.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1480390.js
@@ -0,0 +1,35 @@
+var g = newGlobal();
+g.parent = this;
+g.eval("new Debugger(parent).onExceptionUnwind = function () {};");
+
+function* wrapNoThrow() {
+    let iter = {
+	[Symbol.iterator]() {
+            return this;
+	},
+	next() {
+            return { value: 10, done: false };
+	},
+	return() { return "invalid return value" }
+    };
+    for (const i of iter)
+	yield i;
+}
+
+function foo() {
+    for (var i of [1,2,3]) {
+	for (var j of [4,5,6]) {
+	    try {
+		for (const i of wrapNoThrow()) break;
+	    } catch (e) {}
+	}
+	for (var j of [7,8,9]) {
+	}
+    }
+}
+
+for (var i = 0; i < 10; i++) {
+    try {
+	foo();
+    } catch(e) {}
+}
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -468,31 +468,36 @@ static inline jsbytecode* GetNextNonLoop
     if (op == JSOP_LOOPENTRY) {
       *skippedLoopEntry = pc;
     }
     return GetNextPc(pc);
   }
   return pc;
 }
 
-static bool HasLiveStackValueAtDepth(JSScript* script, jsbytecode* pc,
-                                     uint32_t stackDepth) {
+class NoOpTryNoteFilter {
+ public:
+  explicit NoOpTryNoteFilter() = default;
+  bool operator()(const JSTryNote*) { return true; }
+};
+
+class TryNoteIterAll : public TryNoteIter<NoOpTryNoteFilter> {
+ public:
+  TryNoteIterAll(JSContext* cx, JSScript* script, jsbytecode* pc)
+      : TryNoteIter(cx, script, pc, NoOpTryNoteFilter()) {}
+};
+
+static bool HasLiveStackValueAtDepth(JSContext* cx, HandleScript script,
+                                     jsbytecode* pc, uint32_t stackDepth) {
   if (!script->hasTrynotes()) {
     return false;
   }
 
-  uint32_t pcOffset = script->pcToOffset(pc);
-
-  for (const JSTryNote& tn : script->trynotes()) {
-    if (pcOffset < tn.start) {
-      continue;
-    }
-    if (pcOffset >= tn.start + tn.length) {
-      continue;
-    }
+  for (TryNoteIterAll tni(cx, script, pc); !tni.done(); ++tni) {
+    const JSTryNote& tn = **tni;
 
     switch (tn.kind) {
       case JSTRY_FOR_IN:
         // For-in loops have only the iterator on stack.
         if (stackDepth == tn.stackDepth) {
           return true;
         }
         break;
@@ -1007,17 +1012,18 @@ static bool InitFromBailout(JSContext* c
       // 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. We can't drop
       // iterators, however, so read them out. They will be closed by
       // HandleExceptionBaseline.
       MOZ_ASSERT(cx->realm()->isDebuggee());
-      if (iter.moreFrames() || HasLiveStackValueAtDepth(script, pc, i + 1)) {
+      if (iter.moreFrames() ||
+          HasLiveStackValueAtDepth(cx, script, pc, i + 1)) {
         v = iter.read();
       } else {
         iter.skip();
         v = MagicValue(JS_OPTIMIZED_OUT);
       }
     } else {
       v = iter.read();
     }