Source code

Revision control

Copy as Markdown

Other Tools

gczeal(0);
const gC = newGlobal({newCompartment: true}); // zone C: transplantable targets (not collected)
const gZ = newGlobal({newCompartment: true}); // zone Z: dead weakrefs (collected)
const gD = newGlobal({newCompartment: true}); // zone D: transplant destination (not collected)
const NT = 64; // number of important weakref/target pairs
const NFILLER = 200000; // dead weakrefs in Z to stall foreground finalization
gC.evaluate(`
var pairs = [];
for (let i = 0; i < ${NT}; i++) pairs.push(transplantableObject());
`);
gZ.evaluate(`
function makeWeak(t) { new WeakRef(t); }
function filler(n) {
let keep = [];
for (let i = 0; i < n; i++) { let o = {i: i}; keep.push(o); new WeakRef(o); }
return keep;
}
`);
// Fillers first: their (dead) weakrefs are finalized first and stall
// foreground finalization across many slices. Targets stay alive via `keep`.
let keep = gZ.filler(NFILLER);
// Important weakrefs last: their arenas are finalized last.
for (let i = 0; i < NT; i++) {
gZ.makeWeak(gC.pairs[i].object);
}
// Clean nursery + store buffer before starting; tenure everything live.
minorgc();
// Incremental GC collecting ONLY zone Z.
schedulezone(gZ);
startgc(1);
let transplanted = 0;
let sliceCount = 0;
while (gcstate() !== "NotActive") {
gcslice(10000, {dontStart: true});
sliceCount++;
if (gcstate() === "Sweep" && transplanted < NT) {
for (let k = 0; k < 4 && transplanted < NT; k++) {
// Transplant target into zone D. The new identity proxy is
// nursery-allocated; relocateFinalizationObserverTarget writes it into
// the dead WeakRef's TargetSlot -> whole-cell entry for dead cell.
gC.pairs[transplanted].transplant(gD);
transplanted++;
}
}
if (sliceCount > 10000) { break; }
}
minorgc();