job-queue-03.js (4120B)
1 // Multiple debuggers get their job queues drained after each hook. 2 // This covers: 3 // - onDebuggerStatement 4 // - onStep 5 // - onEnterFrame 6 // - onPop 7 // - onExceptionUnwind 8 // - breakpoint handlers 9 // - uncaughtExceptionHook 10 11 const g = newGlobal({ newCompartment: true }); 12 g.parent = this; 13 14 var log = ''; 15 let expected_throws = 0; 16 17 function setup(global, label) { 18 const dbg = new Debugger; 19 dbg.gDO = dbg.addDebuggee(global); 20 dbg.log = ''; 21 22 dbg.onDebuggerStatement = function (frame) { 23 // Exercise the promise machinery: resolve a promise and perform a microtask 24 // checkpoint. When called from a debugger hook, the debuggee's microtasks 25 // should not run. 26 function exercise(name) { 27 dbg.log += name + ','; 28 log += `${label}-${name}-handler\n`; 29 Promise.resolve(42).then(v => { 30 assertEq(v, 42); 31 log += `${label}-${name}-tail\n`; 32 }); 33 } 34 35 exercise('debugger'); 36 37 frame.onStep = function () { 38 this.onStep = undefined; 39 exercise('step'); 40 }; 41 42 dbg.onEnterFrame = function (frame) { 43 dbg.onEnterFrame = undefined; 44 frame.onPop = function(completion) { 45 assertEq(completion.return, 'escutcheon'); 46 exercise('pop'); 47 } 48 49 exercise('enter'); 50 } 51 52 expected_throws++; 53 dbg.onExceptionUnwind = function(frame, value) { 54 dbg.onExceptionUnwind = undefined; 55 assertEq(value, 'myrmidon'); 56 exercise('exception'); 57 if (--expected_throws > 0) { 58 return undefined; 59 } else { 60 return { return: 'escutcheon' }; 61 } 62 }; 63 64 // Set a breakpoint on entry to g.breakpoint_here. 65 const script = dbg.gDO.getOwnPropertyDescriptor('breakpoint_here').value.script; 66 const handler = { 67 hit(frame) { 68 script.clearAllBreakpoints(); 69 exercise('bp'); 70 } 71 }; 72 script.setBreakpoint(0, handler); 73 74 dbg.uncaughtExceptionHook = function (ex) { 75 assertEq(ex, 'turncoat'); 76 exercise('uncaught'); 77 }; 78 79 // Throw an uncaught exception from the Debugger handler. This should reach 80 // uncaughtExceptionHook, but shouldn't affect the debuggee. 81 throw 'turncoat'; 82 }; 83 84 return dbg; 85 } 86 87 const dbg1 = setup(g, '1'); 88 const dbg2 = setup(g, '2'); 89 const dbg3 = setup(g, '3'); 90 91 g.eval(` 92 function breakpoint_here() { 93 throw 'myrmidon'; 94 } 95 96 parent.log += 'eval-start\\n'; 97 98 // DebuggeeWouldRun detection may prevent this callback from running at all if 99 // bug 1145201 is present. SpiderMonkey will try to run the promise reaction 100 // job from the Debugger hook's microtask checkpoint, triggering 101 // DebuggeeWouldRun. This is a little difficult to observe, since the callback 102 // never even begins execution. But it should cause the 'then' promise to be 103 // rejected, which the shell will report (if the assertEq(log, ...) doesn't 104 // kill the test first). 105 106 Promise.resolve(84).then(function(v) { 107 assertEq(v, 84); 108 parent.log += 'eval-react'; 109 }); 110 debugger; 111 parent.log += 'stuff to step over\\n'; 112 breakpoint_here(); 113 parent.log += 'eval-end\\n'; 114 `); 115 116 log += 'main-drain\n' 117 drainJobQueue(); 118 log += 'main-drain-done\n'; 119 120 const regex = new RegExp(`eval-start 121 .-debugger-handler 122 .-uncaught-handler 123 .-debugger-tail 124 .-uncaught-tail 125 .-debugger-handler 126 .-uncaught-handler 127 .-debugger-tail 128 .-uncaught-tail 129 .-debugger-handler 130 .-uncaught-handler 131 .-debugger-tail 132 .-uncaught-tail 133 .-step-handler 134 .-step-tail 135 .-step-handler 136 .-step-tail 137 .-step-handler 138 .-step-tail 139 stuff to step over 140 .-enter-handler 141 .-enter-tail 142 .-enter-handler 143 .-enter-tail 144 .-enter-handler 145 .-enter-tail 146 .-bp-handler 147 .-bp-tail 148 .-bp-handler 149 .-bp-tail 150 .-bp-handler 151 .-bp-tail 152 .-exception-handler 153 .-exception-tail 154 .-exception-handler 155 .-exception-tail 156 .-exception-handler 157 .-exception-tail 158 .-pop-handler 159 .-pop-tail 160 .-pop-handler 161 .-pop-tail 162 .-pop-handler 163 .-pop-tail 164 eval-end 165 main-drain 166 eval-reactmain-drain-done 167 `); 168 169 assertEq(!!log.match(regex), true) 170 171 assertEq(dbg1.log, 'debugger,uncaught,step,enter,bp,exception,pop,'); 172 assertEq(dbg2.log, 'debugger,uncaught,step,enter,bp,exception,pop,'); 173 assertEq(dbg3.log, 'debugger,uncaught,step,enter,bp,exception,pop,');