tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Frame-onStep-generators-gc-01.js (2610B)


      1 // onStep hooks on suspended Frames can keep Debuggers alive, even chaining them.
      2 
      3 // The path through the heap we're building and testing here is:
      4 //     gen0 (generator object) -> frame1 (suspended Frame with .onStep) -> dbg1 (Debugger object)
      5 //       -> gen1 -> frame2 -> dbg2
      6 // where everything after `gen1` is otherwise unreachable, and the edges
      7 // `frame1 -> dbg1` and `frames2 -> dbg2` are due to the .onStep handlers, not
      8 // strong refrences.
      9 //
     10 // There is no easy way to thread an event through this whole path; when we
     11 // call gen0.next(), it will fire frame1.onStep(), but from there, making sure
     12 // gen1.next() is called requires some minor heroics (see the WeakMap below).
     13 
     14 var gen0;
     15 
     16 var hits2 = 0;
     17 var resuming2 = false;
     18 
     19 function onStep2() {
     20    if (resuming2) {
     21        hits2++;
     22        resuming2 = false;
     23    }
     24 }
     25 
     26 function setup() {
     27    let g1 = newGlobal({newCompartment: true});
     28    g1.eval(`
     29        function* gf1() {
     30             debugger;
     31             yield 1;
     32             return 'done';
     33        }
     34    `);
     35    gen0 = g1.gf1();
     36 
     37    let g2 = newGlobal({newCompartment: true});
     38    g2.eval(`
     39        function* gf2() { debugger; yield 1; return 'done'; }
     40 
     41        var resuming1 = false;
     42 
     43        function makeOnStepHook1(dbg1) {
     44            // We use this WeakMap as a weak reference from frame1.onStep to dbg1.
     45            var weak = new WeakMap();
     46            weak.set(dbg1, {});
     47            return () => {
     48                if (resuming1) {
     49                    var dbg1Arr = nondeterministicGetWeakMapKeys(weak);
     50                    assertEq(dbg1Arr.length, 1);
     51                    dbg1Arr[0].gen1.next();
     52                    resuming1 = false;
     53                }
     54            };
     55        }
     56 
     57        function test(g1, gen0) {
     58            let dbg1 = Debugger(g1);
     59            dbg1.onDebuggerStatement = frame1 => {
     60                frame1.onStep = makeOnStepHook1(dbg1);
     61                dbg1.onDebuggerStatement = undefined;
     62            };
     63            gen0.next();  // run to yield point, creating frame1 and setting its onStep hook
     64            resuming1 = true;
     65            dbg1.gen1 = gf2();
     66            return dbg1.gen1;
     67        }
     68    `);
     69 
     70    let dbg2 = Debugger(g2);
     71    dbg2.onDebuggerStatement = frame2 => {
     72        frame2.onStep = onStep2;
     73        dbg2.onDebuggerStatement = undefined;
     74    };
     75    var gen1 = g2.test(g1, gen0);
     76    gen1.next();  // run to yield point, creating frame2 and setting its onStep hook
     77    resuming2 = true;
     78 }
     79 
     80 setup();
     81 gc();
     82 assertEq(hits2, 0);
     83 gen0.next();  // fires frame1.onStep, which calls gen1.next(), which fires frame2.onStep
     84 assertEq(hits2, 1);