// These tests will be using object literals as keys, and we want some of them // to be dead after being inserted into a WeakMap. That means we must wrap // everything in functions because it seems like the toplevel script hangs onto // its object literals. // Cross-compartment WeakMap keys work by storing a cross-compartment wrapper // in the WeakMap, and the actual "delegate" object in the target compartment // is the thing whose liveness is checked. var g2 = newGlobal(); g2.eval('function genObj(name) { return {"name": name} }'); function basicSweeping() { var wm1 = new WeakMap(); wm1.set({'name': 'obj1'}, {'name': 'val1'}); var hold = g2.genObj('obj2'); wm1.set(hold, {'name': 'val2'}); wm1.set({'name': 'obj3'}, {'name': 'val3'}); var obj4 = g2.genObj('obj4'); wm1.set(obj4, {'name': 'val3'}); obj4 = undefined; startgc(100000, 'shrinking'); gcslice(); assertEq(wm1.get(hold).name, 'val2'); assertEq(nondeterministicGetWeakMapKeys(wm1).length, 1); } basicSweeping(); // Same, but behind an additional WM layer, to avoid ordering problems (not // that I've checked that basicSweeping even has any problems.) function basicSweeping2() { var wm1 = new WeakMap(); wm1.set({'name': 'obj1'}, {'name': 'val1'}); var hold = g2.genObj('obj2'); wm1.set(hold, {'name': 'val2'}); wm1.set({'name': 'obj3'}, {'name': 'val3'}); var obj4 = g2.genObj('obj4'); wm1.set(obj4, {'name': 'val3'}); obj4 = undefined; var base1 = {'name': 'base1'}; var base2 = {'name': 'base2'}; var wm_base1 = new WeakMap(); var wm_base2 = new WeakMap(); wm_base1.set(base1, wm_base2); wm_base2.set(base2, wm1); wm1 = wm_base2 = undefined; startgc(100000, 'shrinking'); gcslice(); assertEq(nondeterministicGetWeakMapKeys(wm_base1).length, 1); wm_base2 = wm_base1.get(base1); assertEq(nondeterministicGetWeakMapKeys(wm_base2).length, 1); assertEq(nondeterministicGetWeakMapKeys(wm_base1)[0], base1); assertEq(nondeterministicGetWeakMapKeys(wm_base2)[0], base2); wm_base2 = wm_base1.get(base1); wm1 = wm_base2.get(base2); assertEq(wm1.get(hold).name, 'val2'); assertEq(nondeterministicGetWeakMapKeys(wm1).length, 1); } basicSweeping2(); // Scatter the weakmap, the keys, and the values among different compartments. function tripleZoneMarking() { var g1 = newGlobal(); var g2 = newGlobal(); var g3 = newGlobal(); var wm = g1.eval("new WeakMap()"); var key = g2.eval("({'name': 'obj1'})"); var value = g3.eval("({'name': 'val1'})"); g1 = g2 = g3 = undefined; wm.set(key, value); // Make all of it only reachable via a weakmap in the main test compartment, // so that all of this happens during weak marking mode. Use the weakmap as // its own key, so we know that the weakmap will get traced before the key // and therefore will populate the weakKeys table and all of that jazz. var base_wm = new WeakMap(); base_wm.set(base_wm, [ wm, key ]); wm = key = value = undefined; startgc(100000, 'shrinking'); gcslice(); var keys = nondeterministicGetWeakMapKeys(base_wm); assertEq(keys.length, 1); var [ wm, key ] = base_wm.get(keys[0]); assertEq(key.name, "obj1"); value = wm.get(key); assertEq(value.name, "val1"); } tripleZoneMarking(); function enbugger() { var g = newGlobal(); var dbg = new Debugger; g.eval("function debuggee_f() { return 1; }"); g.eval("function debuggee_g() { return 1; }"); dbg.addDebuggee(g); var [ s ] = dbg.findScripts({global: g}).filter(s => s.displayName == "debuggee_f"); var [ s2 ] = dbg.findScripts({global: g}).filter(s => s.displayName == "debuggee_g"); g.eval("debuggee_f = null"); gc(); dbg.removeAllDebuggees(); gc(); assertEq(s.displayName, "debuggee_f"); var wm = new WeakMap; var obj = Object.create(null); var obj2 = Object.create(null); wm.set(obj, s); wm.set(obj2, obj); wm.set(s2, obj2); s = s2 = obj = obj2 = null; gc(); } enbugger();