Bug 1475417 - Part 0: Add some passing tests. r=jimb
☠☠ backed out by 84eb90b730f0 ☠ ☠
authorJason Orendorff <jorendorff@mozilla.com>
Wed, 11 Jul 2018 17:07:16 -0500
changeset 490460 50ed38c98cc08b2bcf3d3f1d37d551b944658aef
parent 490459 d3ce115e1803ac4f85fef0568a7521e8ea2a87f7
child 490461 13020b58f0fa64366592dbaf3dd9e99059a06108
push id1815
push userffxbld-merge
push dateMon, 15 Oct 2018 10:40:45 +0000
treeherdermozilla-release@18d4c09e9378 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimb
bugs1475417
milestone63.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 1475417 - Part 0: Add some passing tests. r=jimb Also deletes two tests that are completely redundant ever since we removed legacy generators.
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-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-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
--- 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 {return:val}, the frame returns immediately.
+// If debugger.onEnterFrame returns null, the debuggee is terminated 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");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-live-06.js
@@ -0,0 +1,26 @@
+// 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");
+}
+
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onPop-generators-04.js
@@ -0,0 +1,26 @@
+// 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);
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/Frame-onPop-star-generators-01.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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);
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/Frame-onPop-star-generators-02.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// |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);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onStep-generators-defaults.js
@@ -0,0 +1,33 @@
+// 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());
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/breakpoint-oom-01.js
@@ -0,0 +1,39 @@
+// 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);
+
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/onDebuggerStatement-async-generator-resumption-01.js
@@ -0,0 +1,60 @@
+// 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);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/onDebuggerStatement-async-resumption-01.js
@@ -0,0 +1,34 @@
+// 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);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/onEnterFrame-async-resumption-01.js
@@ -0,0 +1,33 @@
+// 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");