// |jit-test| --enable-symbols-as-weakmap-keys

// Test weak maps with symbols keys where the symbols are referenced in
// different zones. Currently we require all participating zones plus the
// atoms zone to be collected to collect such weakmap entries.

gczeal(0);
gczeal('CheckHeapAfterGC');

function makeSymbol(name) {
  return Symbol(name);
}

function mapSize(wm) {
  return nondeterministicGetWeakMapSize(wm);
}

// Test weak map entry with a symbol key is removed when the symbol dies.
printErr("Test 1");
let wm = new WeakMap;
assertEq(mapSize(wm), 0);
let k = makeSymbol('test1');
wm.set(k, {});
assertEq(mapSize(wm), 1);
gc();
assertEq(mapSize(wm), 1);
k = undefined;
gc();
assertEq(mapSize(wm), 0);
wm = undefined;
gc();

// Repeat the test with the key held alive from a different zone.
printErr("Test 2");
let keyZone = newGlobal({newCompartment: true});
keyZone.key = makeSymbol('test2');
let mapZone = newGlobal({newCompartment: true});
mapZone.map = undefined;
mapZone.eval(`map = new WeakMap;`);
mapZone.map.set(keyZone.key, {});
assertEq(mapSize(mapZone.map), 1);
gc();
assertEq(mapSize(mapZone.map), 1);
keyZone.key = undefined;
gc();
assertEq(mapSize(mapZone.map), 0);
keyZone = undefined;
mapZone = undefined;
gc();

// Repeat the previous test with per zone GC.
printErr("Test 3");
keyZone = newGlobal({newCompartment: true});
mapZone = newGlobal({newCompartment: true});
keyZone.eval('var key = Symbol("test2");');
mapZone.eval(`var map = new WeakMap;`);
mapZone.keyZone = keyZone;
mapZone.eval('map.set(keyZone.key, {});');
mapZone.keyZone = undefined;
gc();
assertEq(mapSize(mapZone.map), 1);

printErr("  3.1 Setup");
keyZone.key = undefined;

printErr("  3.2 Collect only main zone");
gc(this);
assertEq(mapSize(mapZone.map), 1);

printErr("  3.3 Collect only map zone");
gc(mapZone);
assertEq(mapSize(mapZone.map), 1);

printErr("  3.4 Collect only key zone");
gc(keyZone);
// Bug 1410123: Perhaps we could stop marking the key atom in the key zone at
// this point if we refine the atom bitmaps without requiring the atoms zone
// to be collected.
assertEq(mapSize(mapZone.map), 1);

printErr("  3.5 Collect map zone and atoms zone (entry not removed)");
schedulezone(mapZone);
schedulezone('atoms');
gc('zone');
assertEq(mapSize(mapZone.map), 1);

printErr("  3.6 Collect key zone and atoms zone (key no longer referenced)");
schedulezone(keyZone);
schedulezone('atoms');
gc('zone');
assertEq(mapSize(mapZone.map), 1);

printErr("  3.7 Collect only atoms zone (nothing collected)");
schedulezone('atoms');
gc('zone');
assertEq(mapSize(mapZone.map), 1);

printErr("  3.8 Collect only map zone (nothing collected)");
gc(mapZone);
assertEq(mapSize(mapZone.map), 1);

printErr("  3.9 Collect map zone and atoms zone (entry collected)");
schedulezone(mapZone);
schedulezone('atoms');
gc('zone');
assertEq(mapSize(mapZone.map), 0);

printErr("  3.10 Collect all zones (nothing more collected)");
gc();
assertEq(mapSize(mapZone.map), 0);
