summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/debug/Frame-onStep-generators-gc-01.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/debug/Frame-onStep-generators-gc-01.js')
-rw-r--r--js/src/jit-test/tests/debug/Frame-onStep-generators-gc-01.js84
1 files changed, 84 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/debug/Frame-onStep-generators-gc-01.js b/js/src/jit-test/tests/debug/Frame-onStep-generators-gc-01.js
new file mode 100644
index 0000000000..54a77260f3
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-onStep-generators-gc-01.js
@@ -0,0 +1,84 @@
+// onStep hooks on suspended Frames can keep Debuggers alive, even chaining them.
+
+// The path through the heap we're building and testing here is:
+// gen0 (generator object) -> frame1 (suspended Frame with .onStep) -> dbg1 (Debugger object)
+// -> gen1 -> frame2 -> dbg2
+// where everything after `gen1` is otherwise unreachable, and the edges
+// `frame1 -> dbg1` and `frames2 -> dbg2` are due to the .onStep handlers, not
+// strong refrences.
+//
+// There is no easy way to thread an event through this whole path; when we
+// call gen0.next(), it will fire frame1.onStep(), but from there, making sure
+// gen1.next() is called requires some minor heroics (see the WeakMap below).
+
+var gen0;
+
+var hits2 = 0;
+var resuming2 = false;
+
+function onStep2() {
+ if (resuming2) {
+ hits2++;
+ resuming2 = false;
+ }
+}
+
+function setup() {
+ let g1 = newGlobal({newCompartment: true});
+ g1.eval(`
+ function* gf1() {
+ debugger;
+ yield 1;
+ return 'done';
+ }
+ `);
+ gen0 = g1.gf1();
+
+ let g2 = newGlobal({newCompartment: true});
+ g2.eval(`
+ function* gf2() { debugger; yield 1; return 'done'; }
+
+ var resuming1 = false;
+
+ function makeOnStepHook1(dbg1) {
+ // We use this WeakMap as a weak reference from frame1.onStep to dbg1.
+ var weak = new WeakMap();
+ weak.set(dbg1, {});
+ return () => {
+ if (resuming1) {
+ var dbg1Arr = nondeterministicGetWeakMapKeys(weak);
+ assertEq(dbg1Arr.length, 1);
+ dbg1Arr[0].gen1.next();
+ resuming1 = false;
+ }
+ };
+ }
+
+ function test(g1, gen0) {
+ let dbg1 = Debugger(g1);
+ dbg1.onDebuggerStatement = frame1 => {
+ frame1.onStep = makeOnStepHook1(dbg1);
+ dbg1.onDebuggerStatement = undefined;
+ };
+ gen0.next(); // run to yield point, creating frame1 and setting its onStep hook
+ resuming1 = true;
+ dbg1.gen1 = gf2();
+ return dbg1.gen1;
+ }
+ `);
+
+ let dbg2 = Debugger(g2);
+ dbg2.onDebuggerStatement = frame2 => {
+ frame2.onStep = onStep2;
+ dbg2.onDebuggerStatement = undefined;
+ };
+ var gen1 = g2.test(g1, gen0);
+ gen1.next(); // run to yield point, creating frame2 and setting its onStep hook
+ resuming2 = true;
+}
+
+setup();
+gc();
+assertEq(hits2, 0);
+gen0.next(); // fires frame1.onStep, which calls gen1.next(), which fires frame2.onStep
+assertEq(hits2, 1);