diff options
Diffstat (limited to 'js/src/jit-test/tests/debug/job-queue-01.js')
-rw-r--r-- | js/src/jit-test/tests/debug/job-queue-01.js | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/debug/job-queue-01.js b/js/src/jit-test/tests/debug/job-queue-01.js new file mode 100644 index 0000000000..259d0c2baf --- /dev/null +++ b/js/src/jit-test/tests/debug/job-queue-01.js @@ -0,0 +1,122 @@ +// Debuggee promise reaction jobs should not run from debugger callbacks. +// This covers: +// - onDebuggerStatement +// - onStep +// - onEnterFrame +// - onPop +// - onExceptionUnwind +// - breakpoint handlers +// - uncaughtExceptionHook + +var g = newGlobal({ newCompartment: true }); +g.parent = this; +var dbg = new Debugger; +var gDO = dbg.addDebuggee(g); +var log = ''; + +// Exercise the promise machinery: resolve a promise and drain the job queue (or +// in HTML terms, perform a microtask checkpoint). When called from a debugger +// hook, the debuggee's microtasks should not run. +function exercise(name) { + log += `${name}-handler`; + Promise.resolve(42).then(v => { + assertEq(v, 42); + log += `${name}-react`; + }); + log += `(`; + drainJobQueue(); + log += `)`; + + // This should be run by the implicit microtask checkpoint after each Debugger + // hook call. + Promise.resolve(42).then(v => { + assertEq(v, 42); + log += `(${name}-tail)`; + }); +} + +dbg.onDebuggerStatement = function (frame) { + exercise('debugger'); + + frame.onStep = function () { + this.onStep = undefined; + exercise('step'); + }; + + dbg.onEnterFrame = function (frame) { + dbg.onEnterFrame = undefined; + frame.onPop = function(completion) { + assertEq(completion.return, 'recompense'); + exercise('pop'); + } + + exercise('enter'); + } + + dbg.onExceptionUnwind = function(frame, value) { + dbg.onExceptionUnwind = undefined; + assertEq(value, 'recidivism'); + exercise('exception'); + return { return: 'recompense' }; + }; + + // Set a breakpoint on entry to g.breakpoint_here. + const script = gDO.getOwnPropertyDescriptor('breakpoint_here').value.script; + const handler = { + hit(frame) { + script.clearAllBreakpoints(); + exercise('bp'); + } + }; + script.setBreakpoint(0, handler); + + dbg.uncaughtExceptionHook = function (ex) { + assertEq(ex, 'turncoat'); + exercise('uncaught'); + }; + + // Throw an uncaught exception from the Debugger handler. This should reach + // uncaughtExceptionHook, but shouldn't affect the debuggee. + throw 'turncoat'; +}; + +g.eval(` + function breakpoint_here() { + throw 'recidivism'; + } + + parent.log += 'eval('; + + // DebuggeeWouldRun detection may prevent this callback from running at all if + // bug 1145201 is present. SpiderMonkey will try to run the promise reaction + // job from the Debugger hook's microtask checkpoint, triggering + // DebuggeeWouldRun. This is a little difficult to observe, since the callback + // never even begins execution. But it should cause the 'then' promise to be + // rejected, which the shell will report (if the assertEq(log, ...) doesn't + // kill the test first). + + Promise.resolve(84).then(function(v) { + assertEq(v, 84); + parent.log += 'eval-react'; + }); + debugger; + parent.log += '...'; + breakpoint_here(); + parent.log += ')'; +`); + +log += 'main-drain(' +drainJobQueue(); +log += ')'; + +assertEq(log, `eval(\ +debugger-handler(debugger-react)\ +uncaught-handler((debugger-tail)uncaught-react)(uncaught-tail)\ +step-handler(step-react)(step-tail)\ +...\ +enter-handler(enter-react)(enter-tail)\ +bp-handler(bp-react)(bp-tail)\ +exception-handler(exception-react)(exception-tail)\ +pop-handler(pop-react)(pop-tail)\ +)\ +main-drain(eval-react)`); |