Bug 1480390: Use TryNoteIter in HasLiveStackValueAtDepth r=jandem
authorIain Ireland <iireland@mozilla.com>
Tue, 15 Jan 2019 15:34:06 +0000
changeset 511041 83d4a8e7b55138fed13f382c47f20fe760c05158
parent 511040 67ac015ae0802854815cc136baf520791588e754
child 511042 303b19a8b923889edcfe6dfccfab4f80d07b29b1
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)
reviewersjandem
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=jandem Differential Revision: https://phabricator.services.mozilla.com/D16566
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({newCompartment: true});
+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();
     }