Backed out 3 changesets (bug 1475417) for failing docker configuration ona CLOSED TREE
authorAndreea Pavel <apavel@mozilla.com>
Wed, 22 Aug 2018 01:31:39 +0300
changeset 487824 84eb90b730f0fa8b4073d4fb9ba29d28ff4eabed
parent 487823 e9abc7d4a76b8c53ba4f2f7aedeecddfe6f36984
child 487825 d064a4d17800f65d691c7ce8ac0e5c73d7f0b20f
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1475417
milestone63.0a1
backs out972ad5dc9a842911479edf3737c0e2aee7fad35d
13020b58f0fa64366592dbaf3dd9e99059a06108
50ed38c98cc08b2bcf3d3f1d37d551b944658aef
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
Backed out 3 changesets (bug 1475417) for failing docker configuration ona CLOSED TREE Backed out changeset 972ad5dc9a84 (bug 1475417) Backed out changeset 13020b58f0fa (bug 1475417) Backed out changeset 50ed38c98cc0 (bug 1475417)
js/src/jit-test/tests/debug/Debugger-onEnterFrame-resumption-03.js
js/src/jit-test/tests/debug/Frame-live-06.js
js/src/jit-test/tests/debug/Frame-live-07.js
js/src/jit-test/tests/debug/Frame-onPop-generators-04.js
js/src/jit-test/tests/debug/Frame-onPop-star-generators-01.js
js/src/jit-test/tests/debug/Frame-onPop-star-generators-02.js
js/src/jit-test/tests/debug/Frame-onStep-generators-01.js
js/src/jit-test/tests/debug/Frame-onStep-generators-02.js
js/src/jit-test/tests/debug/Frame-onStep-generators-03.js
js/src/jit-test/tests/debug/Frame-onStep-generators-defaults.js
js/src/jit-test/tests/debug/breakpoint-oom-01.js
js/src/jit-test/tests/debug/onDebuggerStatement-async-generator-resumption-01.js
js/src/jit-test/tests/debug/onDebuggerStatement-async-resumption-01.js
js/src/jit-test/tests/debug/onEnterFrame-async-resumption-01.js
js/src/jit-test/tests/debug/onEnterFrame-async-resumption-02.js
js/src/jit-test/tests/debug/onEnterFrame-async-resumption-03.js
js/src/jit-test/tests/debug/onEnterFrame-generator-01.js
js/src/jit-test/tests/debug/onEnterFrame-generator-02.js
js/src/jit-test/tests/debug/onEnterFrame-generator-03.js
js/src/jit-test/tests/debug/onEnterFrame-generator-resumption-01.js
js/src/jit-test/tests/debug/onEnterFrame-generator-resumption-02.js
js/src/jit-test/tests/debug/onEnterFrame-generator-resumption-03.js
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineDebugModeOSR.cpp
js/src/jit/SharedIC.h
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
js/src/vm/Debugger.cpp
js/src/vm/GeneratorObject.cpp
js/src/vm/GeneratorObject.h
js/src/vm/Interpreter.cpp
js/src/vm/Stack.h
--- a/js/src/jit-test/tests/debug/Debugger-onEnterFrame-resumption-03.js
+++ b/js/src/jit-test/tests/debug/Debugger-onEnterFrame-resumption-03.js
@@ -1,24 +1,24 @@
-// If debugger.onEnterFrame returns null, the debuggee is terminated immediately.
+// If debugger.onEnterFrame returns {return:val}, the frame returns immediately.
 
 load(libdir + "asserts.js");
 
 var g = newGlobal();
 g.set = false;
 
 var dbg = Debugger(g);
 var savedFrame;
 dbg.onDebuggerStatement = function (frame) {
     var innerSavedFrame;
     dbg.onEnterFrame = function (frame) {
         innerSavedFrame = frame;
         return null;
     };
-    // Using frame.eval lets us catch termination.
+    // Using frame.eval lets us catch termination.  
     assertEq(frame.eval("set = true;"), null);
     assertEq(innerSavedFrame.live, false);
     savedFrame = frame;
     return { return: "pass" };
 };
 
 savedFrame = undefined;
 assertEq(g.eval("debugger;"), "pass");
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/Frame-live-06.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// frame.live is false for generator frames after they return.
-
-let g = newGlobal();
-g.eval("function* f() { debugger; }");
-
-let dbg = Debugger(g);
-let savedFrame;
-
-dbg.onDebuggerStatement = frame => {
-    savedFrame = frame;
-    assertEq(frame.callee.name, "f");
-    assertEq(frame.live, true);
-    frame.onPop = function() {
-        assertEq(frame.live, true);
-    };
-};
-g.f().next();
-
-assertEq(savedFrame.live, false);
-try {
-    savedFrame.older;
-    throw new Error("expected exception, none thrown");
-} catch (exc) {
-    assertEq(exc.message, "Debugger.Frame is not live");
-}
-
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/Frame-live-07.js
+++ /dev/null
@@ -1,53 +0,0 @@
-// frame.live is false for generator frames popped due to exception or termination.
-
-load(libdir + "/asserts.js");
-
-function test(when, what) {
-    let g = newGlobal();
-    g.eval("function* f(x) { yield x; }");
-
-    let dbg = new Debugger;
-    let gw = dbg.addDebuggee(g);
-    let fw = gw.getOwnPropertyDescriptor("f").value;
-
-    let t = 0;
-    let poppedFrame;
-
-    function tick(frame) {
-        if (frame.callee == fw) {
-            if (t == when) {
-                poppedFrame = frame;
-                dbg.onEnterFrame = undefined;
-                frame.onPop = undefined;
-                return what;
-            }
-            t++;
-        }
-        return undefined;
-    }
-
-    dbg.onDebuggerStatement = frame => {
-        dbg.onEnterFrame = frame => {
-            frame.onPop = function() {
-                return tick(this);
-            };
-            return tick(frame);
-        };
-        let result = frame.eval("for (let _ of f(0)) {}");
-        assertDeepEq(result, what);
-    };
-    g.eval("debugger;");
-
-    assertEq(t, when);
-    assertEq(poppedFrame.live, false);
-    assertErrorMessage(() => poppedFrame.older,
-                       Error,
-                       "Debugger.Frame is not live");
-}
-
-for (let when = 0; when < 6; when++) {
-    for (let what of [null, {throw: "fit"}]) {
-        test(when, what);
-    }
-}
-
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/Frame-onPop-generators-04.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// Terminating a generator from the onPop callback for its initial yield
-// leaves the Frame in a sane but inactive state.
-
-load(libdir + "asserts.js");
-
-let g = newGlobal();
-g.eval("function* f(x) { yield x; }");
-let dbg = new Debugger;
-let gw = dbg.addDebuggee(g);
-
-let genFrame = null;
-dbg.onDebuggerStatement = frame => {
-    dbg.onEnterFrame = frame => {
-        if (frame.callee == gw.getOwnPropertyDescriptor("f").value) {
-            genFrame = frame;
-            frame.onPop = completion => null;
-        }
-    };
-    assertEq(frame.eval("f(0);"), null);
-};
-
-g.eval("debugger;");
-
-assertEq(genFrame instanceof Debugger.Frame, true);
-assertEq(genFrame.live, false);
-assertThrowsInstanceOf(() => genFrame.callee, Error);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-star-generators-01.js
@@ -0,0 +1,20 @@
+// Returning {throw:} from an onPop handler when yielding works and
+// closes the generator-iterator.
+
+load(libdir + "iteration.js");
+
+var g = newGlobal();
+var dbg = new Debugger;
+var gw = dbg.addDebuggee(g);
+dbg.onDebuggerStatement = function handleDebugger(frame) {
+    frame.onPop = function (c) {
+        return {throw: "fit"};
+    };
+};
+g.eval("function* g() { for (var i = 0; i < 10; i++) { debugger; yield i; } }");
+g.eval("var it = g();");
+var rv = gw.executeInGlobal("it.next();");
+assertEq(rv.throw, "fit");
+
+dbg.enabled = false;
+assertIteratorDone(g.it);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-star-generators-02.js
@@ -0,0 +1,21 @@
+// |jit-test| error: fit
+
+// Throwing an exception from an onPop handler when yielding terminates the debuggee
+// but does not close the generator-iterator.
+
+load(libdir + 'iteration.js')
+
+var g = newGlobal();
+var dbg = new Debugger;
+var gw = dbg.addDebuggee(g);
+dbg.onDebuggerStatement = function handleDebugger(frame) {
+    frame.onPop = function (c) {
+        throw "fit";
+    };
+};
+g.eval("function* g() { for (var i = 0; i < 10; i++) { debugger; yield i; } }");
+g.eval("var it = g();");
+assertEq(gw.executeInGlobal("it.next();"), null);
+
+dbg.enabled = false;
+assertIteratorNext(g.it, 1);
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/Frame-onStep-generators-01.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// Stepping into the `.next()` method of a generator works as expected.
-
-let g = newGlobal();
-g.eval(`\
-function* nums() {      // line 1
-    yield 1;            //  2
-    yield 2;            //  3
-}                       //  4
-function f() {          //  5
-    let gen = nums();   //  6
-    gen.next();         //  7
-    gen.next();         //  8
-    gen.next();         //  9
-}                       // 10
-`);
-
-let log = [];
-let previousLine = -1;
-let dbg = new Debugger(g);
-dbg.onEnterFrame = frame => {
-    frame.onStep = () => {
-        let line = frame.script.getOffsetLocation(frame.offset).lineNumber;
-        if (previousLine != line) { // We stepped to a new line.
-            log.push(line);
-            previousLine = line;
-        }
-    };
-};
-
-g.f();
-assertEq(log.join(" "), "5 6 1 6 7 1 2 7 8 2 3 8 9 3 9 10");
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/Frame-onStep-generators-02.js
+++ /dev/null
@@ -1,44 +0,0 @@
-// Stepping into the `.throw()` method of a generator with no relevant catch block.
-//
-// The debugger fires onEnterFrame and then frame.onPop for the generator frame when
-// `gen.throw()` is called.
-
-load(libdir + "asserts.js");
-
-let g = newGlobal();
-g.eval(`\
-function* z() {         // line 1
-    yield 1;            // 2
-    yield 2;            // 3
-}                       // 4
-function f() {          // 5
-    let gen = z();      // 6
-    gen.next();         // 7
-    gen.throw("fit");   // 8
-}                       // 9
-`);
-
-let log = "";
-let previousLine = -1;
-let dbg = new Debugger(g);
-dbg.onEnterFrame = frame => {
-    log += frame.callee.name + "{";
-    frame.onStep = () => {
-        let line = frame.script.getOffsetLocation(frame.offset).lineNumber;
-        if (previousLine != line) { // We stepped to a new line.
-            log += line;
-            previousLine = line;
-        }
-    };
-    frame.onPop = completion => {
-        if ("throw" in completion)
-            log += "!";
-        log += "}";
-    }
-};
-
-assertThrowsValue(() => g.f(), "fit");
-// z{1} is the initial generator setup.
-// z{12} is the first .next() call, running to `yield 1` on line 2
-// The final `z{!}` is for the .throw() call.
-assertEq(log, "f{56z{1}67z{12}78z{!}!}");
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/Frame-onStep-generators-03.js
+++ /dev/null
@@ -1,45 +0,0 @@
-// Stepping into the `.throw()` method of a generator with a relevant catch block.
-
-load(libdir + "asserts.js");
-
-let g = newGlobal();
-g.eval(`\
-function* z() {         // line 1
-    try {               // 2
-        yield 1;        // 3
-    } catch (exc) {     // 4
-        yield 2;        // 5
-    }                   // 6
-}                       // 7
-function f() {          // 8
-    let gen = z();      // 9
-    gen.next();         // 10
-    gen.throw("fit");   // 11
-}                       // 12
-`);
-
-let log = [];
-let previousLine = -1;
-let dbg = new Debugger(g);
-dbg.onEnterFrame = frame => {
-    log.push(frame.callee.name + " in");
-    frame.onStep = () => {
-        let line = frame.script.getOffsetLocation(frame.offset).lineNumber;
-        if (previousLine != line) { // We stepped to a new line.
-            log.push(line);
-            previousLine = line;
-        }
-    };
-    frame.onPop = completion => {
-        log.push(frame.callee.name + " out");
-    };
-};
-
-g.f();
-assertEq(
-    log.join(", "),
-    "f in, 8, 9, z in, 1, z out, " +
-    "9, 10, z in, 1, 2, 3, z out, " +
-    "10, 11, z in, 2, 4, 5, z out, " +  // not sure why we hit line 2 here, source notes bug maybe
-    "11, 12, f out"
-);
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/Frame-onStep-generators-defaults.js
+++ /dev/null
@@ -1,33 +0,0 @@
-// onStep works during the evaluation of default parameter values in generators.
-//
-// (They're evaluated at a weird time in the generator life cycle, before the
-// generator object is created.)
-
-let g = newGlobal();
-g.eval(`\
-    function f1() {}        // line 1
-    function f2() {}        //  2
-    function f3() {}        //  3
-                            //  4
-    function* gen(          //  5
-        name,               //  6
-        schema = f1(),      //  7
-        timeToLive = f2(),  //  8
-        lucidity = f3()     //  9
-    ) {                     // 10
-    }                       // 11
-`);
-
-let dbg = Debugger(g);
-let log = [];
-dbg.onEnterFrame = frame => {
-    frame.onStep = () => {
-        let line = frame.script.getOffsetLocation(frame.offset).lineNumber;
-        if (log.length == 0 || line != log[log.length - 1]) {
-            log.push(line);
-        }
-    };
-};
-
-g.gen(0);
-assertEq(log.toSource(), [5, 7, 1, 8, 2, 9, 3, 10].toSource());
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/breakpoint-oom-01.js
+++ /dev/null
@@ -1,39 +0,0 @@
-// Test for OOM hitting a breakpoint in a generator.
-//
-// (The purpose is to test OOM-handling in the code that creates the
-// Debugger.Frame object and associates it with the generator object.)
-
-let g = newGlobal();
-g.eval(`\
-    function* gen(x) {  // line 1
-        x++;            // 2
-        yield x;        // 3
-    }                   // 4
-`);
-
-let dbg = new Debugger;
-
-// On OOM in the debugger, propagate it to the debuggee.
-dbg.uncaughtExceptionHook = exc => exc === "out of memory" ? {throw: exc} : null;
-
-let gw = dbg.addDebuggee(g);
-let script = gw.makeDebuggeeValue(g.gen).script;
-let hits = 0;
-let handler = {
-    hit(frame) {
-        hits++;
-        print("x=", frame.environment.getVariable("x"));
-    }
-};
-for (let offset of script.getLineOffsets(2))
-    script.setBreakpoint(offset, handler);
-
-let result;
-oomTest(() => {
-    hits = 0;
-    result = g.gen(1).next();
-}, false);
-assertEq(hits, 1);
-assertEq(result.done, false);
-assertEq(result.value, 2);
-
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/onDebuggerStatement-async-generator-resumption-01.js
+++ /dev/null
@@ -1,60 +0,0 @@
-// A Debugger can {return:} from onDebuggerStatement in an async generator.
-// A resolved promise for a {value: _, done: true} object is returned.
-
-load(libdir + "asserts.js");
-
-let g = newGlobal();
-g.eval(`
-    async function* f(x) {
-        debugger;  // when==0 to force return here
-        await x;
-        yield 1;
-        debugger;  // when==1 to force return here
-    }
-`);
-
-let exc = null;
-let dbg = new Debugger;
-let gw = dbg.addDebuggee(g);
-function test(when) {
-    let hits = 0;
-    let outcome = "FAIL";
-    dbg.onDebuggerStatement = frame => {
-        if (hits++ == when)
-            return {return: "ponies"};
-    };
-
-    let iter = g.f(0);
-
-    // At the initial suspend.
-    assertEq(hits, 0);
-    iter.next().then(result => {
-        // At the yield point, unless we already force-returned from the first
-        // debugger statement.
-        assertEq(hits, 1);
-        if (when == 0)
-            return result;
-        assertEq(result.value, 1);
-        assertEq(result.done, false);
-        return iter.next();
-    }).then(result => {
-        // After forced return.
-        assertEq(hits, when + 1);
-        assertEq(result.value, "ponies");
-        assertEq(result.done, true);
-        outcome = "pass";
-    }).catch(e => {
-        // An assertion failed.
-        exc = e;
-    });
-
-    assertEq(hits, 1);
-    drainJobQueue();
-    if (exc !== null)
-        throw exc;
-    assertEq(outcome, "pass");
-}
-
-for (let i = 0; i < 2; i++) {
-    test(i);
-}
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/onDebuggerStatement-async-resumption-01.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// A Debugger can {return:} from onDebuggerStatement in an async function.
-// The async function's promise is resolved with the returned value.
-
-load(libdir + "asserts.js");
-
-let g = newGlobal();
-g.eval(`
-    async function f(x) {
-        debugger;  // when==0 to force return here
-        await x;
-        debugger;  // when==1 to force return here
-    }
-`);
-
-let dbg = new Debugger;
-let gw = dbg.addDebuggee(g);
-function test(when, what, expected) {
-    let hits = 0;
-    let result = "FAIL";
-    dbg.onDebuggerStatement = frame => {
-        if (hits++ == when)
-            return {return: gw.makeDebuggeeValue(what)};
-    };
-    g.f(0).then(x => { result = x; });
-    assertEq(hits, 1);
-    drainJobQueue();
-    assertEq(hits, when + 1);
-    assertEq(result, expected);
-}
-
-for (let i = 0; i < 2; i++) {
-    test(i, "ok", "ok");
-    test(i, g.Promise.resolve(37), 37);
-}
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/onEnterFrame-async-resumption-01.js
+++ /dev/null
@@ -1,33 +0,0 @@
-// A Debugger can {return:} from the first onEnterFrame for an async function.
-// (The exact behavior is undocumented; we're testing that it doesn't crash.)
-
-let g = newGlobal();
-g.hit2 = false;
-g.eval(`async function f(x) { await x; return "ponies"; }`);
-
-let dbg = new Debugger;
-let gw = dbg.addDebuggee(g);
-let hits = 0;
-let resumption = undefined;
-dbg.onEnterFrame = frame => {
-    if (frame.type == "call" && frame.callee.name === "f") {
-        frame.onPop = completion => {
-            assertEq(completion.return, resumption.return);
-            hits++;
-        };
-
-        // Don't tell anyone, but if we force-return a generator object here,
-        // the robots accept it as one of their own and plug it right into the
-        // async function machinery. This may be handy against Skynet someday.
-        resumption = frame.eval(`(function* f2() { hit2 = true; throw "fit"; })()`);
-        assertEq(resumption.return.class, "Generator");
-        return resumption;
-    }
-};
-
-let p = g.f(0);
-assertEq(hits, 1);
-let pw = gw.makeDebuggeeValue(p);
-assertEq(pw.isPromise, true);
-assertEq(pw.promiseState, "rejected");
-assertEq(pw.promiseReason, "fit");
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/onEnterFrame-async-resumption-02.js
+++ /dev/null
@@ -1,36 +0,0 @@
-// A Debugger can {throw:} from onEnterFrame in an async function.
-// The resulting promise (if any) is rejected with the thrown error value.
-
-load(libdir + "asserts.js");
-
-let g = newGlobal();
-g.eval(`
-    async function f() { await 1; }
-    var err = new TypeError("object too hairy");
-`);
-
-let dbg = new Debugger;
-let gw = dbg.addDebuggee(g);
-let errw = gw.makeDebuggeeValue(g.err);
-
-// Repeat the test for each onEnterFrame event.
-// It fires up to three times:
-// - when the async function g.f is called;
-// - when we enter it to run to `await 1`;
-// - when we resume after the await to run to the end.
-for (let when = 0; when < 3; when++) {
-    let hits = 0;
-    dbg.onEnterFrame = frame => {
-        return hits++ < when ? undefined : {throw: errw};
-    };
-
-    let result = undefined;
-    g.f()
-        .then(value => { result = {returned: value}; })
-        .catch(err => { result = {threw: err}; });
-
-    drainJobQueue();
-
-    assertEq(hits, when + 1);
-    assertDeepEq(result, {threw: g.err});
-}
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/onEnterFrame-async-resumption-03.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// A Debugger can {return:} from onEnterFrame at any resume point in an async function.
-// The async function's promise is resolved with the returned value.
-
-let g = newGlobal();
-g.eval(`async function f(x) { await x; }`);
-
-let dbg = new Debugger(g);
-function test(when) {
-    let hits = 0;
-    dbg.onEnterFrame = frame => {
-        if (frame.type == "call" && frame.callee.name === "f") {
-            if (hits++ == when) {
-                return {return: "exit"};
-            }
-        }
-    };
-
-    let result = undefined;
-    let finished = false;
-    g.f("hello").then(value => { result = value; finished = true; });
-    drainJobQueue();
-    assertEq(finished, true);
-    assertEq(hits, when + 1);
-    assertEq(result, "exit");
-}
-
-// onEnterFrame with hits==0 is not a resume point; {return:} behaves differently there
-// (see onEnterFrame-async-resumption-02.js).
-test(1);  // force return from first resume point, immediately after the initial suspend
-test(2);  // force return from second resume point, immediately after the await instruction
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/onEnterFrame-generator-01.js
+++ /dev/null
@@ -1,81 +0,0 @@
-// Frame properties and methods work in generator-resuming onEnterFrame events.
-// Also tests onPop events, for good measure.
-
-let g = newGlobal();
-g.eval(`\
-    function* gen(lo, hi) {
-        var a = 1/2;
-        yield a;
-        yield a * a;
-    }
-`);
-let dbg = new Debugger;
-let gw = dbg.addDebuggee(g);
-
-let hits = 0;
-let savedScript = null;
-let savedEnv = null;
-let savedOffsets = new Set;
-
-function check(frame) {
-    assertEq(frame.type, "call");
-    assertEq(frame.constructing, false);
-    assertEq(frame.callee, gw.makeDebuggeeValue(g.gen));
-
-    // `arguments` elements don't work in resumed generator frames,
-    // because generators don't keep the arguments around.
-    // The first onEnterFrame and onPop events can see them.
-    assertEq(frame.arguments.length, hits < 2 ? args.length : 0);
-    for (var i = 0; i < frame.arguments.length; i++) {
-        assertEq(frame.arguments.hasOwnProperty(i), true);
-
-        if (hits < 2)
-            assertEq(frame.arguments[i], gw.makeDebuggeeValue(args[i]), `arguments[${i}]`);
-        else
-            assertEq(frame.arguments[i], undefined);
-    }
-
-    if (savedEnv === null) {
-        savedEnv = frame.environment;
-        assertEq(savedScript, null);
-        savedScript = frame.script;
-    } else {
-        assertEq(frame.environment, savedEnv);
-        assertEq(frame.script, savedScript);
-    }
-    let a_expected = hits < 3 ? undefined : 1/2;
-    assertEq(savedEnv.getVariable("a"), a_expected);
-
-    assertEq(frame.generator, true);
-    assertEq(frame.live, true);
-
-    let pc = frame.offset;
-    assertEq(savedOffsets.has(pc), false);
-    savedOffsets.add(pc);
-
-    assertEq(frame.older, null);
-    assertEq(frame.this, gw);
-    assertEq(typeof frame.implementation, "string");
-
-    // And the moment of truth:
-    assertEq(frame.eval("2 + 2").return, 4);
-    assertEq(frame.eval("a").return, a_expected);
-    assertEq(frame.eval("if (a !== undefined) { assertEq(a < (lo + hi) / 2, true); } 7;").return, 7);
-}
-
-dbg.onEnterFrame = frame => {
-    if (frame.type === "eval")
-        return;
-    check(frame);
-    hits++;
-    frame.onPop = completion => {
-        check(frame);
-        hits++;
-    };
-};
-
-// g.gen ignores the arguments passed to it, but we use them to test
-// frame.arguments.
-let args = [0, 10, g, dbg];
-for (let v of g.gen(...args)) {}
-assertEq(hits, 8);
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/onEnterFrame-generator-02.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// onEnterFrame fires after the [[GeneratorState]] is set to "executing".
-//
-// This test checks that Debugger doesn't accidentally make it possible to
-// reenter a generator frame that's already on the stack. (Also tests a fun
-// corner case in baseline debug-mode OSR.)
-
-load(libdir + "asserts.js");
-
-let g = newGlobal();
-g.eval('function* f() { yield 1; yield 2; }');
-let dbg = Debugger(g);
-let genObj = null;
-let hits = 0;
-dbg.onEnterFrame = frame => {
-    // The first time onEnterFrame fires, there is no generator object, so
-    // there's nothing to test. The generator object doesn't exist until
-    // JSOP_GENERATOR is reached, right before the initial yield.
-    if (genObj !== null) {
-        dbg.removeDebuggee(g);  // avoid the DebuggeeWouldRun exception
-        assertThrowsInstanceOf(() => genObj.next(), g.TypeError);
-        dbg.addDebuggee(g);
-        hits++;
-    }
-};
-genObj = g.f();
-for (let x of genObj) {}
-assertEq(hits, 3);
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/onEnterFrame-generator-03.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// If onEnterFrame terminates a generator, the Frame is left in a sane but inactive state.
-
-load(libdir + "asserts.js");
-
-let g = newGlobal();
-g.eval("function* f(x) { yield x; }");
-let dbg = new Debugger;
-let gw = dbg.addDebuggee(g);
-
-let genFrame = null;
-dbg.onDebuggerStatement = frame => {
-    dbg.onEnterFrame = frame => {
-        if (frame.callee == gw.getOwnPropertyDescriptor("f").value) {
-            genFrame = frame;
-            return null;
-        }
-    };
-    assertEq(frame.eval("f(0);"), null);
-};
-
-g.eval("debugger;");
-
-assertEq(genFrame instanceof Debugger.Frame, true);
-assertEq(genFrame.live, false);
-assertThrowsInstanceOf(() => genFrame.callee, Error);
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/onEnterFrame-generator-resumption-01.js
+++ /dev/null
@@ -1,36 +0,0 @@
-// A debugger can {throw:} from onEnterFrame at any resume point in a generator.
-// It closes the generator.
-
-load(libdir + "asserts.js");
-
-let g = newGlobal();
-g.eval(`
-    function* f() { yield 1; }
-    var exn = new TypeError("object too hairy");
-`);
-
-let dbg = new Debugger;
-let gw = dbg.addDebuggee(g);
-
-// Repeat the test for each onEnterFrame event.
-// It fires up to three times:
-// - when the generator g.f is called;
-// - when we enter it to run to `yield 1`;
-// - when we resume after the yield to run to the end.
-for (let i = 0; i < 3; i++) {
-    let hits = 0;
-    dbg.onEnterFrame = frame => {
-        return hits++ < i ? undefined : {throw: gw.makeDebuggeeValue(g.exn)};
-    };
-    let genObj;
-    assertThrowsValue(
-        () => {
-            genObj = g.f();
-            for (let x of genObj) {}
-        },
-        g.exn
-    );
-    assertEq(hits, i + 1);
-    if (hits > 1)
-        assertEq(genObj.next().done, true);
-}
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/onEnterFrame-generator-resumption-02.js
+++ /dev/null
@@ -1,39 +0,0 @@
-// A Debugger can {return:} from onEnterFrame at any resume point in a generator.
-// Force-returning closes the generator.
-
-load(libdir + "asserts.js");
-
-let g = newGlobal();
-g.values = [1, 2, 3];
-g.eval(`function* f() { yield* values; }`);
-
-let dbg = Debugger(g);
-
-// onEnterFrame will fire up to 5 times.
-// - once for the initial call to g.f();
-// - four times at resume points:
-//   - initial resume at the top of the generator body
-//   - resume after yielding 1
-//   - resume after yielding 2
-//   - resume after yielding 3 (this resumption will run to the end).
-// This test ignores the initial call and focuses on resume points.
-for (let i = 1; i < 5; i++) {
-    let hits = 0;
-    dbg.onEnterFrame = frame => {
-        return hits++ < i ? undefined : {return: "we're done here"};
-    };
-
-    let genObj = g.f();
-    let actual = [];
-    while (true) {
-        let r = genObj.next();
-        if (r.done) {
-            assertDeepEq(r, {value: "we're done here", done: true});
-            break;
-        }
-        actual.push(r.value);
-    }
-    assertEq(hits, i + 1);
-    assertDeepEq(actual, g.values.slice(0, i - 1));
-    assertDeepEq(genObj.next(), {value: undefined, done: true});
-}
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/onEnterFrame-generator-resumption-03.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// Returning {throw:} from onEnterFrame when resuming inside a try block in a
-// generator causes control to jump to the catch block.
-
-let g = newGlobal();
-g.eval(`
-    function* gen() {
-        try {
-            yield 0;
-            return "fail";
-        } catch (exc) {
-            assertEq(exc, "fit");
-            return "ok";
-        }
-    }
-`)
-
-let dbg = new Debugger(g);
-let hits = 0;
-dbg.onEnterFrame = frame => {
-    assertEq(frame.callee.name, "gen");
-    if (++hits == 3) {
-        // First hit is when calling gen();
-        // second hit is resuming at the implicit initial yield;
-        // third hit is resuming inside the try block.
-        return {throw: "fit"};
-    }
-};
-
-let it = g.gen();
-let result = it.next();
-assertEq(result.done, false);
-assertEq(result.value, 0);
-result = it.next();
-assertEq(result.done, true);
-assertEq(result.value, "ok");
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -4642,44 +4642,31 @@ BaselineCompiler::emit_JSOP_YIELD()
 }
 
 bool
 BaselineCompiler::emit_JSOP_AWAIT()
 {
     return emit_JSOP_YIELD();
 }
 
-typedef bool (*DebugAfterYieldFn)(JSContext*, BaselineFrame*, jsbytecode*, bool*);
+typedef bool (*DebugAfterYieldFn)(JSContext*, BaselineFrame*);
 static const VMFunction DebugAfterYieldInfo =
     FunctionInfo<DebugAfterYieldFn>(jit::DebugAfterYield, "DebugAfterYield");
 
 bool
 BaselineCompiler::emit_JSOP_DEBUGAFTERYIELD()
 {
     if (!compileDebugInstrumentation_)
         return true;
 
     frame.assertSyncedStack();
     masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
     prepareVMCall();
-    pushArg(ImmPtr(pc));
     pushArg(R0.scratchReg());
-    if (!callVM(DebugAfterYieldInfo))
-        return false;
-
-    icEntries_.back().setFakeKind(ICEntry::Kind_DebugAfterYield);
-
-    Label done;
-    masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &done);
-    {
-        masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
-        masm.jump(&return_);
-    }
-    masm.bind(&done);
-    return true;
+    return callVM(DebugAfterYieldInfo);
 }
 
 typedef bool (*FinalSuspendFn)(JSContext*, HandleObject, jsbytecode*);
 static const VMFunction FinalSuspendInfo =
     FunctionInfo<FinalSuspendFn>(jit::FinalSuspend, "FinalSuspend");
 
 bool
 BaselineCompiler::emit_JSOP_FINALYIELDRVAL()
@@ -4701,17 +4688,17 @@ BaselineCompiler::emit_JSOP_FINALYIELDRV
 
 typedef bool (*InterpretResumeFn)(JSContext*, HandleObject, HandleValue, HandlePropertyName,
                                   MutableHandleValue);
 static const VMFunction InterpretResumeInfo =
     FunctionInfo<InterpretResumeFn>(jit::InterpretResume, "InterpretResume");
 
 typedef bool (*GeneratorThrowFn)(JSContext*, BaselineFrame*, Handle<GeneratorObject*>,
                                  HandleValue, uint32_t);
-static const VMFunction GeneratorThrowOrReturnInfo =
+static const VMFunction GeneratorThrowInfo =
     FunctionInfo<GeneratorThrowFn>(jit::GeneratorThrowOrReturn, "GeneratorThrowOrReturn", TailCall);
 
 bool
 BaselineCompiler::emit_JSOP_RESUME()
 {
     GeneratorObject::ResumeKind resumeKind = GeneratorObject::getResumeKind(pc);
 
     frame.syncStack(0);
@@ -4886,17 +4873,17 @@ BaselineCompiler::emit_JSOP_RESUME()
         masm.loadBaselineFramePtr(BaselineFrameReg, scratch2);
 
         prepareVMCall();
         pushArg(Imm32(resumeKind));
         pushArg(retVal);
         pushArg(genObj);
         pushArg(scratch2);
 
-        TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(GeneratorThrowOrReturnInfo);
+        TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(GeneratorThrowInfo);
 
         // Create the frame descriptor.
         masm.subStackPtrFrom(scratch1);
         masm.makeFrameDescriptor(scratch1, JitFrame_BaselineJS, ExitFrameLayout::Size());
 
         // Push the frame descriptor and a dummy return address (it doesn't
         // matter what we push here, frame iterators will use the frame pc
         // set in jit::GeneratorThrowOrReturn).
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -98,17 +98,16 @@ struct DebugModeOSREntry
 
     bool needsRecompileInfo() const {
         return frameKind == ICEntry::Kind_CallVM ||
                frameKind == ICEntry::Kind_WarmupCounter ||
                frameKind == ICEntry::Kind_StackCheck ||
                frameKind == ICEntry::Kind_EarlyStackCheck ||
                frameKind == ICEntry::Kind_DebugTrap ||
                frameKind == ICEntry::Kind_DebugPrologue ||
-               frameKind == ICEntry::Kind_DebugAfterYield ||
                frameKind == ICEntry::Kind_DebugEpilogue;
     }
 
     bool recompiled() const {
         return oldBaselineScript != script->baselineScript();
     }
 
     BaselineDebugModeOSRInfo* takeRecompInfo() {
@@ -303,18 +302,16 @@ ICEntryKindToString(ICEntry::Kind kind)
       case ICEntry::Kind_StackCheck:
         return "stack check";
       case ICEntry::Kind_EarlyStackCheck:
         return "early stack check";
       case ICEntry::Kind_DebugTrap:
         return "debug trap";
       case ICEntry::Kind_DebugPrologue:
         return "debug prologue";
-      case ICEntry::Kind_DebugAfterYield:
-        return "debug after yield";
       case ICEntry::Kind_DebugEpilogue:
         return "debug epilogue";
       default:
         MOZ_CRASH("bad ICEntry kind");
     }
 }
 #endif // JS_JITSPEW
 
@@ -365,17 +362,16 @@ PatchBaselineFramesForDebugMode(JSContex
     //  H. From inside HandleExceptionBaseline.
     //  I. From inside the interrupt handler via the prologue stack check.
     //  J. From the warmup counter in the prologue.
     //
     // On to Off:
     //  - All the ways above.
     //  C. From the debug trap handler.
     //  D. From the debug prologue.
-    //  K. From a JSOP_DEBUGAFTERYIELD instruction.
     //  E. From the debug epilogue.
     //
     // Cycles (On to Off to On)+ or (Off to On to Off)+:
     //  F. Undo cases B, C, D, E, I or J above on previously patched yet unpopped
     //     frames.
     //
     // In general, we patch the return address from the VM call to return to a
     // "continuation fixer" to fix up machine state (registers and stack
@@ -469,17 +465,16 @@ PatchBaselineFramesForDebugMode(JSContex
                 MOZ_ASSERT(info->pc == pc);
                 MOZ_ASSERT(info->frameKind == kind);
                 MOZ_ASSERT(kind == ICEntry::Kind_CallVM ||
                            kind == ICEntry::Kind_WarmupCounter ||
                            kind == ICEntry::Kind_StackCheck ||
                            kind == ICEntry::Kind_EarlyStackCheck ||
                            kind == ICEntry::Kind_DebugTrap ||
                            kind == ICEntry::Kind_DebugPrologue ||
-                           kind == ICEntry::Kind_DebugAfterYield ||
                            kind == ICEntry::Kind_DebugEpilogue);
 
                 // We will have allocated a new recompile info, so delete the
                 // existing one.
                 frame.baselineFrame()->deleteDebugModeOSRInfo();
             }
 
             // The RecompileInfo must already be allocated so that this
@@ -546,27 +541,16 @@ PatchBaselineFramesForDebugMode(JSContex
                 // Case D above.
                 //
                 // We patch a jump directly to the right place in the prologue
                 // after popping the frame reg and checking for forced return.
                 recompInfo->resumeAddr = bl->postDebugPrologueAddr();
                 popFrameReg = true;
                 break;
 
-              case ICEntry::Kind_DebugAfterYield:
-                // Case K above.
-                //
-                // Resume at the next instruction.
-                MOZ_ASSERT(*pc == JSOP_DEBUGAFTERYIELD);
-                recompInfo->resumeAddr = bl->nativeCodeForPC(script,
-                                                             pc + JSOP_DEBUGAFTERYIELD_LENGTH,
-                                                             &recompInfo->slotInfo);
-                popFrameReg = true;
-                break;
-
               default:
                 // Case E above.
                 //
                 // We patch a jump directly to the epilogue after popping the
                 // frame reg and checking for forced return.
                 MOZ_ASSERT(kind == ICEntry::Kind_DebugEpilogue);
                 recompInfo->resumeAddr = bl->epilogueEntryAddr();
                 popFrameReg = true;
@@ -956,19 +940,19 @@ HasForcedReturn(BaselineDebugModeOSRInfo
 {
     ICEntry::Kind kind = info->frameKind;
 
     // The debug epilogue always checks its resumption value, so we don't need
     // to check rv.
     if (kind == ICEntry::Kind_DebugEpilogue)
         return true;
 
-    // |rv| is the value in ReturnReg. If true, in the case of the prologue or
-    // after yield, it means a forced return.
-    if (kind == ICEntry::Kind_DebugPrologue || kind == ICEntry::Kind_DebugAfterYield)
+    // |rv| is the value in ReturnReg. If true, in the case of the prologue,
+    // it means a forced return.
+    if (kind == ICEntry::Kind_DebugPrologue)
         return rv;
 
     // N.B. The debug trap handler handles its own forced return, so no
     // need to deal with it here.
     return false;
 }
 
 static inline bool
--- a/js/src/jit/SharedIC.h
+++ b/js/src/jit/SharedIC.h
@@ -251,19 +251,18 @@ class ICEntry
 
         // As above, but for the early check. See emitStackCheck.
         Kind_EarlyStackCheck,
 
         // A fake IC entry for returning from DebugTrapHandler.
         Kind_DebugTrap,
 
         // A fake IC entry for returning from a callVM to
-        // Debug{Prologue,AfterYield,Epilogue}.
+        // Debug{Prologue,Epilogue}.
         Kind_DebugPrologue,
-        Kind_DebugAfterYield,
         Kind_DebugEpilogue,
 
         Kind_Invalid
     };
 
   private:
     // What this IC is for.
     Kind kind_ : 4;
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -952,54 +952,37 @@ InterpretResume(JSContext* cx, HandleObj
     args[1].set(val);
     args[2].setString(kind);
 
     return CallSelfHostedFunction(cx, cx->names().InterpretGeneratorResume, UndefinedHandleValue,
                                   args, rval);
 }
 
 bool
-DebugAfterYield(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool* mustReturn)
+DebugAfterYield(JSContext* cx, BaselineFrame* frame)
 {
-    *mustReturn = false;
-
     // The BaselineFrame has just been constructed by JSOP_RESUME in the
     // caller. We need to set its debuggee flag as necessary.
-    //
-    // If a breakpoint is set on JSOP_DEBUGAFTERYIELD, or stepping is enabled,
-    // we may already have done this work. Don't fire onEnterFrame again.
-    if (frame->script()->isDebuggee() && !frame->isDebuggee()) {
+    if (frame->script()->isDebuggee())
         frame->setIsDebuggee();
-        return DebugPrologue(cx, frame, pc, mustReturn);
-    }
     return true;
 }
 
 bool
 GeneratorThrowOrReturn(JSContext* cx, BaselineFrame* frame, Handle<GeneratorObject*> genObj,
                        HandleValue arg, uint32_t resumeKind)
 {
     // Set the frame's pc to the current resume pc, so that frame iterators
     // work. This function always returns false, so we're guaranteed to enter
     // the exception handler where we will clear the pc.
     JSScript* script = frame->script();
     uint32_t offset = script->yieldAndAwaitOffsets()[genObj->yieldAndAwaitIndex()];
-    jsbytecode* pc = script->offsetToPC(offset);
-    frame->setOverridePc(pc);
-
-    // In the interpreter, GeneratorObject::resume marks the generator as running,
-    // so we do the same.
-    genObj->setRunning();
+    frame->setOverridePc(script->offsetToPC(offset));
 
-    bool mustReturn = false;
-    if (!DebugAfterYield(cx, frame, pc, &mustReturn))
-        return false;
-    if (mustReturn)
-        resumeKind = GeneratorObject::RETURN;
-
+    MOZ_ALWAYS_TRUE(DebugAfterYield(cx, frame));
     MOZ_ALWAYS_FALSE(js::GeneratorThrowOrReturn(cx, frame, genObj, arg, resumeKind));
     return false;
 }
 
 bool
 CheckGlobalOrEvalDeclarationConflicts(JSContext* cx, BaselineFrame* frame)
 {
     RootedScript script(cx, frame->script());
@@ -1099,25 +1082,21 @@ bool
 HandleDebugTrap(JSContext* cx, BaselineFrame* frame, uint8_t* retAddr, bool* mustReturn)
 {
     *mustReturn = false;
 
     RootedScript script(cx, frame->script());
     jsbytecode* pc = script->baselineScript()->icEntryFromReturnAddress(retAddr).pc(script);
 
     if (*pc == JSOP_DEBUGAFTERYIELD) {
-        // JSOP_DEBUGAFTERYIELD will set the frame's debuggee flag and call the
-        // onEnterFrame handler, but if we set a breakpoint there we have to do
-        // it now.
+        // JSOP_DEBUGAFTERYIELD will set the frame's debuggee flag, but if we
+        // set a breakpoint there we have to do it now.
         MOZ_ASSERT(!frame->isDebuggee());
-
-        if (!DebugAfterYield(cx, frame, pc, mustReturn))
+        if (!DebugAfterYield(cx, frame))
             return false;
-        if (*mustReturn)
-            return true;
     }
 
     MOZ_ASSERT(frame->isDebuggee());
     MOZ_ASSERT(script->stepModeEnabled() || script->hasBreakpointsAt(pc));
 
     RootedValue rval(cx);
     ResumeMode resumeMode = ResumeMode::Continue;
 
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -780,17 +780,17 @@ MOZ_MUST_USE bool
 NormalSuspend(JSContext* cx, HandleObject obj, BaselineFrame* frame, jsbytecode* pc,
               uint32_t stackDepth);
 MOZ_MUST_USE bool
 FinalSuspend(JSContext* cx, HandleObject obj, jsbytecode* pc);
 MOZ_MUST_USE bool
 InterpretResume(JSContext* cx, HandleObject obj, HandleValue val, HandlePropertyName kind,
                 MutableHandleValue rval);
 MOZ_MUST_USE bool
-DebugAfterYield(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool* mustReturn);
+DebugAfterYield(JSContext* cx, BaselineFrame* frame);
 MOZ_MUST_USE bool
 GeneratorThrowOrReturn(JSContext* cx, BaselineFrame* frame, Handle<GeneratorObject*> genObj,
                        HandleValue arg, uint32_t resumeKind);
 
 MOZ_MUST_USE bool
 GlobalNameConflictsCheckFromIon(JSContext* cx, HandleScript script);
 MOZ_MUST_USE bool
 CheckGlobalOrEvalDeclarationConflicts(JSContext* cx, BaselineFrame* frame);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1812,25 +1812,16 @@ Debugger::fireEnterFrame(JSContext* cx, 
     MOZ_ASSERT(hook->isCallable());
 
     Maybe<AutoRealm> ar;
     ar.emplace(cx, object);
 
     RootedValue scriptFrame(cx);
 
     FrameIter iter(cx);
-
-#if DEBUG
-    // Assert that the hook won't be able to re-enter the generator.
-    if (iter.hasScript() && *iter.pc() == JSOP_DEBUGAFTERYIELD) {
-        GeneratorObject* genObj = GetGeneratorObjectForFrame(cx, iter.abstractFramePtr());
-        MOZ_ASSERT(genObj->isRunning() || genObj->isClosing());
-    }
-#endif
-
     if (!getFrame(cx, iter, &scriptFrame))
         return reportUncaughtException(ar);
 
     RootedValue fval(cx, ObjectValue(*hook));
     RootedValue rv(cx);
     bool ok = js::Call(cx, fval, object, scriptFrame, &rv);
 
     return processHandlerResult(ar, ok, rv, iter.abstractFramePtr(), iter.pc(), vp);
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -129,33 +129,35 @@ js::SetGeneratorClosed(JSContext* cx, Ab
 }
 
 bool
 js::GeneratorThrowOrReturn(JSContext* cx, AbstractFramePtr frame, Handle<GeneratorObject*> genObj,
                            HandleValue arg, uint32_t resumeKind)
 {
     if (resumeKind == GeneratorObject::THROW) {
         cx->setPendingException(arg);
+        genObj->setRunning();
     } else {
         MOZ_ASSERT(resumeKind == GeneratorObject::RETURN);
 
         MOZ_ASSERT(arg.isObject());
         frame.setReturnValue(arg);
 
         RootedValue closing(cx, MagicValue(JS_GENERATOR_CLOSING));
         cx->setPendingException(closing);
         genObj->setClosing();
     }
     return false;
 }
 
 bool
 GeneratorObject::resume(JSContext* cx, InterpreterActivation& activation,
-                        Handle<GeneratorObject*> genObj, HandleValue arg)
+                        HandleObject obj, HandleValue arg, GeneratorObject::ResumeKind resumeKind)
 {
+    Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
     MOZ_ASSERT(genObj->isSuspended());
 
     RootedFunction callee(cx, &genObj->callee());
     RootedObject envChain(cx, &genObj->environmentChain());
     if (!activation.resumeGeneratorFrame(callee, envChain))
         return false;
     activation.regs().fp()->setResumedGenerator();
 
@@ -177,18 +179,28 @@ GeneratorObject::resume(JSContext* cx, I
 
     // Always push on a value, even if we are raising an exception. In the
     // exception case, the stack needs to have something on it so that exception
     // handling doesn't skip the catch blocks. See TryNoteIter::settle.
     activation.regs().sp++;
     MOZ_ASSERT(activation.regs().spForStackDepth(activation.regs().stackDepth()));
     activation.regs().sp[-1] = arg;
 
-    genObj->setRunning();
-    return true;
+    switch (resumeKind) {
+      case NEXT:
+        genObj->setRunning();
+        return true;
+
+      case THROW:
+      case RETURN:
+        return GeneratorThrowOrReturn(cx, activation.regs().fp(), genObj, arg, resumeKind);
+
+      default:
+        MOZ_CRASH("bad resumeKind");
+    }
 }
 
 const Class GeneratorObject::class_ = {
     "Generator",
     JSCLASS_HAS_RESERVED_SLOTS(GeneratorObject::RESERVED_SLOTS)
 };
 
 static const JSFunctionSpec generator_methods[] = {
--- a/js/src/vm/GeneratorObject.h
+++ b/js/src/vm/GeneratorObject.h
@@ -55,17 +55,17 @@ class GeneratorObject : public NativeObj
             return THROW;
         MOZ_ASSERT(atom == cx->names().return_);
         return RETURN;
     }
 
     static JSObject* create(JSContext* cx, AbstractFramePtr frame);
 
     static bool resume(JSContext* cx, InterpreterActivation& activation,
-                       Handle<GeneratorObject*> genObj, HandleValue arg);
+                       HandleObject obj, HandleValue arg, ResumeKind resumeKind);
 
     static bool initialSuspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc) {
         return suspend(cx, obj, frame, pc, nullptr, 0);
     }
 
     static bool normalSuspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
                               Value* vp, unsigned nvalues) {
         return suspend(cx, obj, frame, pc, vp, nvalues);
@@ -142,27 +142,23 @@ class GeneratorObject : public NativeObj
                       "test below should return false for YIELD_AND_AWAIT_INDEX_RUNNING");
         return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() < YIELD_AND_AWAIT_INDEX_CLOSING;
     }
     void setRunning() {
         MOZ_ASSERT(isSuspended());
         setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(YIELD_AND_AWAIT_INDEX_RUNNING));
     }
     void setClosing() {
-        MOZ_ASSERT(isRunning());
+        MOZ_ASSERT(isSuspended());
         setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(YIELD_AND_AWAIT_INDEX_CLOSING));
     }
     void setYieldAndAwaitIndex(uint32_t yieldAndAwaitIndex) {
         MOZ_ASSERT_IF(yieldAndAwaitIndex == 0,
                       getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).isUndefined());
         MOZ_ASSERT_IF(yieldAndAwaitIndex != 0, isRunning() || isClosing());
-        setYieldAndAwaitIndexNoAssert(yieldAndAwaitIndex);
-    }
-    // Debugger has to flout the state machine rules a bit.
-    void setYieldAndAwaitIndexNoAssert(uint32_t yieldAndAwaitIndex) {
         MOZ_ASSERT(yieldAndAwaitIndex < uint32_t(YIELD_AND_AWAIT_INDEX_CLOSING));
         setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(yieldAndAwaitIndex));
         MOZ_ASSERT(isSuspended());
     }
     uint32_t yieldAndAwaitIndex() const {
         MOZ_ASSERT(isSuspended());
         return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32();
     }
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -4262,60 +4262,36 @@ CASE(JSOP_AWAIT)
     POP_RETURN_VALUE();
 
     goto successful_return_continuation;
 }
 
 CASE(JSOP_RESUME)
 {
     {
-        Rooted<GeneratorObject*> gen(cx, &REGS.sp[-2].toObject().as<GeneratorObject>());
+        ReservedRooted<JSObject*> gen(&rootObject0, &REGS.sp[-2].toObject());
         ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
         // popInlineFrame expects there to be an additional value on the stack
         // to pop off, so leave "gen" on the stack.
 
         GeneratorObject::ResumeKind resumeKind = GeneratorObject::getResumeKind(REGS.pc);
-        if (!GeneratorObject::resume(cx, activation, gen, val))
-            goto error;
+        bool ok = GeneratorObject::resume(cx, activation, gen, val, resumeKind);
 
         JSScript* generatorScript = REGS.fp()->script();
         if (cx->realm() != generatorScript->realm())
             cx->enterRealmOf(generatorScript);
         SET_SCRIPT(generatorScript);
 
         TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
         TraceLoggerEvent scriptEvent(TraceLogger_Scripts, script);
         TraceLogStartEvent(logger, scriptEvent);
         TraceLogStartEvent(logger, TraceLogger_Interpreter);
 
-        switch (Debugger::onEnterFrame(cx, REGS.fp())) {
-          case ResumeMode::Continue:
-            break;
-          case ResumeMode::Throw:
-          case ResumeMode::Terminate:
+        if (!ok)
             goto error;
-          case ResumeMode::Return:
-            MOZ_ASSERT_IF(REGS.fp()->callee().isGenerator(),  // as opposed to an async function
-                          gen->isClosed());
-            if (!ForcedReturn(cx, REGS))
-                goto error;
-            goto successful_return_continuation;
-        }
-
-        switch (resumeKind) {
-          case GeneratorObject::NEXT:
-            break;
-          case GeneratorObject::THROW:
-          case GeneratorObject::RETURN:
-            MOZ_ALWAYS_FALSE(GeneratorThrowOrReturn(cx, activation.regs().fp(), gen, val,
-                                                    resumeKind));
-            goto error;
-          default:
-            MOZ_CRASH("bad resumeKind");
-        }
     }
     ADVANCE_AND_DISPATCH(0);
 }
 
 CASE(JSOP_DEBUGAFTERYIELD)
 {
     // No-op in the interpreter, as GeneratorObject::resume takes care of
     // fixing up InterpreterFrames.
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -2154,17 +2154,17 @@ class FrameIter
     size_t      numFrameSlots() const;
     Value       frameSlotValue(size_t index) const;
 
     // Ensures that we have rematerialized the top frame and its associated
     // inline frames. Can only be called when isIon().
     bool ensureHasRematerializedFrame(JSContext* cx);
 
     // True when isInterp() or isBaseline(). True when isIon() if it
-    // has a rematerialized frame. False otherwise.
+    // has a rematerialized frame. False otherwise false otherwise.
     bool hasUsableAbstractFramePtr() const;
 
     // -----------------------------------------------------------
     // The following functions can only be called when isInterp(),
     // isBaseline(), isWasm() or isIon(). Further, abstractFramePtr() can
     // only be called when hasUsableAbstractFramePtr().
     // -----------------------------------------------------------