Bug 1570178 - Part 4: Support setting onPop when the frame is not live. r=jimb

Since we're now allowing onStep when not live, it makes sense to do the same
for onPop, and since it does not have any implementation details preventing
setting it while the frame is dead, we might as well.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Logan Smyth 2019-10-28 08:27:54 +00:00
parent 5eb14d59ba
commit d9f546cf87
6 changed files with 119 additions and 33 deletions

View File

@ -1042,8 +1042,6 @@ OnPopHandler* DebuggerFrame::onPopHandler() const {
}
void DebuggerFrame::setOnPopHandler(JSContext* cx, OnPopHandler* handler) {
MOZ_ASSERT(isLive());
OnPopHandler* prior = onPopHandler();
if (handler == prior) {
return;
@ -1232,7 +1230,9 @@ bool DebuggerFrame::CallData::ToNative(JSContext* cx, unsigned argc,
// These methods do not require liveness.
bool checkLive = MyMethod != &CallData::liveGetter &&
MyMethod != &CallData::onStepGetter &&
MyMethod != &CallData::onStepSetter;
MyMethod != &CallData::onStepSetter &&
MyMethod != &CallData::onPopGetter &&
MyMethod != &CallData::onPopSetter;
RootedDebuggerFrame frame(cx,
DebuggerFrame::check(cx, args.thisv(), checkLive));

View File

@ -1,30 +0,0 @@
// Trying to set an onPop handler on a dead frame throws an exception.
var g = newGlobal({newCompartment: true});
g.eval("function f() { }");
g.eval("function g() { f(); }");
g.eval("function h() { g(); }");
g.eval("function i() { h(); }");
var dbg = new Debugger(g);
var log;
var frames = [];
dbg.onEnterFrame = function handleEnter(f) {
log += "(";
assertEq(f.live, true);
frames.push(f);
};
log = '';
g.i();
assertEq(log, "((((");
assertEq(frames.length, 4);
for (i = 0; i < frames.length; i++) {
assertEq(frames[i].live, false);
var set = false;
try {
frames[i].onPop = function unappreciated() { };
set = true; // don't assert in a 'try' block
} catch (x) {
assertEq(x instanceof Error, true);
}
assertEq(set, false);
}

View File

@ -0,0 +1,48 @@
// Changing onPop while the function is dead is allowed.
load(libdir + "asserts.js");
const g = newGlobal({ newCompartment: true });
const dbg = new Debugger(g);
let steps = new Set();
dbg.onDebuggerStatement = function(frame) {
// Setting 'onPop' while alive is allowed.
steps.add("debugger 1");
assertEq(frame.live, true);
frame.onPop = function() {
steps.add("onpop 1");
};
dbg.onDebuggerStatement = function() {
// Clear the 'onPop' while dead.
steps.add("debugger 2");
assertEq(frame.live, false);
// Clearing 'onPop' while dead is allowed.
frame.onPop = undefined;
// Setting 'onPop' while dead is allowed.
frame.onPop = function() {
steps.add("onpop 2");
};
};
};
g.eval(
`
function myGen() {
debugger;
}
const g = myGen();
debugger;
`
);
assertDeepEq(Array.from(steps), [
"debugger 1",
"onpop 1",
"debugger 2",
]);

View File

@ -0,0 +1,68 @@
// Changing onPop while the generator is suspended/dead is allowed.
load(libdir + "asserts.js");
const g = newGlobal({ newCompartment: true });
const dbg = new Debugger(g);
let steps = new Set();
dbg.onDebuggerStatement = function(frame) {
// Setting 'onStep' while alive is allowed.
steps.add("debugger 1");
assertEq(frame.live, true);
frame.onPop = function() {
steps.add("onpop 1");
};
dbg.onDebuggerStatement = function() {
// Clear the 'onPop' while suspended.
steps.add("debugger 2");
assertEq(frame.live, false);
// Clearing 'onPop' while suspended is allowed.
frame.onPop = undefined;
// Setting 'onPop' while suspended is allowed.
frame.onPop = function() {
steps.add("onpop 2");
};
dbg.onDebuggerStatement = function() {
steps.add("debugger 3");
assertEq(frame.live, false);
// Clearing 'onPop' while dead is allowed.
frame.onPop = undefined;
// Setting 'onPop' while dead is allowed.
frame.onPop = function() {
steps.add("onpop 3");
};
};
};
};
g.eval(
`
function* myGen() {
debugger;
yield;
}
const g = myGen();
g.next();
debugger;
g.next();
debugger;
`
);
assertDeepEq(Array.from(steps), [
"debugger 1",
"onpop 1",
"debugger 2",
"onpop 2",
"debugger 3",
]);