// Test main/entry/exit point instrumentation. load(libdir + 'eqArrayHelper.js'); ignoreUnhandledRejections(); var g = newGlobal({ newCompartment: true }); var dbg = Debugger(g); var gdbg = dbg.addDebuggee(g); var allScripts = []; function setScriptId(script) { script.setInstrumentationId(allScripts.length); allScripts.push(script); script.getChildScripts().forEach(setScriptId); } dbg.onNewScript = setScriptId; const executedPoints = []; function hitPoint(kind, scriptId) { const name = allScripts[scriptId].displayName; executedPoints.push(`${name}:${kind}`); } gdbg.setInstrumentation( gdbg.makeDebuggeeValue(hitPoint), ["main", "entry", "exit"] ); function testFunction(fn, expected) { for (var i = 0; i < 3; i++) { try { fn(); } catch (e) {} drainJobQueue(); } assertEq(executedPoints.length, 0); gdbg.setInstrumentationActive(true); for (var i = 0; i < 5; i++) { executedPoints.length = 0; try { fn(); } catch (e) {} drainJobQueue(); assertEqArray(executedPoints, expected); } executedPoints.length = 0; gdbg.setInstrumentationActive(false); } g.eval(` function basic() { var a = 0; a++; } `); testFunction(() => g.basic(), ["basic:main", "basic:exit"]); g.eval(` function thrower(v) { if (v) { throw new Error(); } } `); testFunction(() => g.thrower(0), ["thrower:main", "thrower:exit"]); testFunction(() => g.thrower(1), ["thrower:main"]); g.eval(` function* yielder() { yield 1; } function iterator() { for (var n of yielder()) {} } `); testFunction(() => g.iterator(), [ "iterator:main", "yielder:main", "yielder:exit", "yielder:entry", "yielder:exit", "yielder:entry", "yielder:exit", "iterator:exit" ]); g.eval(` function promiser(n) { return new Promise(function promiseInternal(resolve, reject) { if (n) { reject(new Error()); } else { resolve(); } }); } function f1() {} async function asyncer(n) { await promiser(n) } async function asyncerCatch(n) { try { await promiser(n) } catch (e) { f1() } } async function asyncerFinally(n) { try { await promiser(n) } finally { f1() } } `); testFunction(() => g.asyncer(0), [ "asyncer:main", "promiser:main", "promiseInternal:main", "promiseInternal:exit", "promiser:exit", "asyncer:exit", "asyncer:entry", "asyncer:exit" ]); testFunction(() => g.asyncer(1), [ "asyncer:main", "promiser:main", "promiseInternal:main", "promiseInternal:exit", "promiser:exit", "asyncer:exit", "asyncer:entry", // Note: no exit, GeneratorThrowOrReturn is called. "asyncer:entry", "asyncer:exit" ]); testFunction(() => g.asyncerCatch(1), [ "asyncerCatch:main", "promiser:main", "promiseInternal:main", "promiseInternal:exit", "promiser:exit", "asyncerCatch:exit", "asyncerCatch:entry", // Note: no exit, GeneratorThrowOrReturn is called. "asyncerCatch:entry", "f1:main", "f1:exit", "asyncerCatch:exit" ]); testFunction(() => g.asyncerFinally(1), [ "asyncerFinally:main", "promiser:main", "promiseInternal:main", "promiseInternal:exit", "promiser:exit", "asyncerFinally:exit", "asyncerFinally:entry", // Note: no exit, GeneratorThrowOrReturn is called. "asyncerFinally:entry", "f1:main", "f1:exit", "asyncerFinally:entry", "asyncerFinally:exit" ]);