Bug 1448880 - Part 1: Always close a generator on early forced return. r=jimb

The previous code failed to close the generator in the case where
JSOP_GENERATOR had run but JSOP_INITIAL_YIELD had not, a bit of sloppiness that
created yet another special case. Things will get more complicated when we
start keeping frames live while suspended; it's better to not have this special
case.

Differential Revision: https://phabricator.services.mozilla.com/D6982

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jason Orendorff 2018-10-23 23:21:01 +00:00
parent 8ae065a347
commit 165c31f88e
2 changed files with 53 additions and 9 deletions

View File

@ -0,0 +1,42 @@
// The debugger can force an early return from any instruction before the initial yield.
let g = newGlobal();
g.eval(`
function* f() {
yield 1;
}
`);
function test(ttl) {
let dbg = new Debugger(g);
let exiting = false; // we ran out of time-to-live and have forced return
let done = false; // we reached the initial yield without forced return
dbg.onEnterFrame = frame => {
assertEq(frame.callee.name, "f");
frame.onEnterFrame = undefined;
frame.onStep = () => {
if (ttl == 0) {
exiting = true;
// Forced return here causes the generator object, if any, not
// to be exposed.
return {return: "ponies"};
}
ttl--;
};
frame.onPop = completion => {
if (!exiting)
done = true;
};
};
let result = g.f();
if (done)
assertEq(result instanceof g.f, true);
else
assertEq(result, "ponies");
dbg.enabled = false;
return done;
}
for (let ttl = 0; !test(ttl); ttl++) {}

View File

@ -1543,18 +1543,20 @@ AdjustGeneratorResumptionValue(JSContext* cx, AbstractFramePtr frame,
// on that bytecode sequence existing in the debuggee, somehow jump to
// it, and then avoid re-entering the debugger from it.
Rooted<GeneratorObject*> genObj(cx, GetGeneratorObjectForFrame(cx, frame));
if (genObj && !genObj->isBeforeInitialYield()) {
if (genObj) {
// 1. `return <value>` creates and returns a new object,
// `{value: <value>, done: true}`.
JSObject *pair = CreateIterResultObject(cx, vp, true);
if (!pair) {
// Out of memory in debuggee code. Arrange for this to propagate.
MOZ_ALWAYS_TRUE(cx->getPendingException(vp));
cx->clearPendingException();
resumeMode = ResumeMode::Throw;
return;
if (!genObj->isBeforeInitialYield()) {
JSObject *pair = CreateIterResultObject(cx, vp, true);
if (!pair) {
// Out of memory in debuggee code. Arrange for this to propagate.
MOZ_ALWAYS_TRUE(cx->getPendingException(vp));
cx->clearPendingException();
resumeMode = ResumeMode::Throw;
return;
}
vp.setObject(*pair);
}
vp.setObject(*pair);
// 2. The generator must be closed.
genObj->setClosed();