bug1644699-terminated-generator.js (2435B)
1 // |jit-test| exitstatus:6 2 // Ensure that a frame terminated due to an interrupt in the generator 3 // builtin will properly be treated as terminated. 4 5 const g = newGlobal({ newCompartment: true }); 6 const dbg = new Debugger(g); 7 g.eval(` 8 var done = false; 9 async function* f() { 10 await null; 11 await null; 12 await null; 13 await null; 14 done = true; 15 } 16 `); 17 18 dbg.onEnterFrame = f => { 19 frame = f; 20 dbg.onEnterFrame = undefined; 21 }; 22 23 setInterruptCallback(function() { 24 const stack = saveStack(); 25 26 // We want to explicitly terminate inside the AsyncGeneratorNext builtin 27 // when it tries to resume execution at the 'await' in the async generator. 28 // Terminating inside AsyncGeneratorNext causes the generator to be closed, 29 // and for this test case we specifically need that to happen without 30 // entering the async generator frame because we're aiming to trigger the 31 // case where DebugAPI::onLeaveFrame does not having the opportunity to 32 // clean up the generator information associated with the Debugger.Frame. 33 if ( 34 stack.parent && 35 stack.parent.source === "self-hosted" && 36 stack.parent.functionDisplayName === "AsyncGeneratorNext" && 37 stack.parent.parent && 38 stack.parent.parent.source === stack.source && 39 stack.parent.parent.line === DRAIN_QUEUE_LINE 40 ) { 41 return false; 42 } 43 44 // Keep interrupting until we find the right place. 45 interruptIf(true); 46 return true; 47 }); 48 49 // Run the async generator and suspend at the first await. 50 const it = g.f(); 51 let promise = it.next(); 52 53 // Queue the interrupt so that it will start trying to terminate inside the 54 // generator builtin. 55 interruptIf(true); 56 57 // Explicitly drain the queue to run the async generator to completion. 58 const DRAIN_QUEUE_LINE = saveStack().line + 1; 59 drainJobQueue(); 60 61 let threw = false; 62 try { 63 // In the original testcase for this bug, this call would cause 64 // an assertion failure because the generator was closed. 65 frame.environment; 66 } catch (err) { 67 threw = true; 68 } 69 assertEq(threw, true); 70 71 // The frame here still has a GeneratorInfo datastructure because the 72 // termination interrupt will cause the generator to be closed without 73 // clearing that data. The frame must still be treated as terminated in 74 // this case in order for the Debugger API to behave consistently. 75 assertEq(frame.terminated, true); 76 77 // We should never reach the end of the async generator because it will 78 // have been terminated. 79 assertEq(g.done, false);