diff options
Diffstat (limited to 'js/src/jit-test/tests/gc/weakRefs.js')
-rw-r--r-- | js/src/jit-test/tests/gc/weakRefs.js | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/gc/weakRefs.js b/js/src/jit-test/tests/gc/weakRefs.js new file mode 100644 index 0000000000..e052aa779b --- /dev/null +++ b/js/src/jit-test/tests/gc/weakRefs.js @@ -0,0 +1,122 @@ +// https://tc39.es/ecma262/#sec-addtokeptobjects +// When the abstract operation AddToKeptObjects is called with a target object +// reference, it adds the target to an identity Set that will point strongly at +// the target until the end of the current Job. +// +// https://tc39.es/proposal-weakrefs/#sec-weakref-invariants +// When WeakRef.prototype.deref is called, the referent (if it's not already +// dead) is kept alive so that subsequent, synchronous accesses also return the +// object. + +function testSameCompartmentWeakRef( + targetReachable, + weakRefReachable) { + + let target = {}; + + let weakref = new WeakRef(target); + assertEq(weakref.deref(), target); + + if (!targetReachable) { + target = undefined; + } + + if (!weakRefReachable) { + weakRef = undefined; + } + + clearKeptObjects(); + gc(); + + if (weakRefReachable) { + if (targetReachable) { + assertEq(weakref.deref(), target); + } else { + assertEq(weakref.deref(), undefined); + } + } +} + +let serial = 0; + +function testCrossCompartmentWeakRef( + targetReachable, + weakRefReachable, + collectTargetZone, + collectWeakRefZone, + sameZone) { + + gc(); + + let id = serial++; + let global = newGlobal(sameZone ? {sameZoneAs: this} : {newCompartment: true}); + global.eval('var target = {};'); + global.target.id = id; + + let weakref = new WeakRef(global.target); + assertEq(weakref.deref(), global.target); + + if (!targetReachable) { + global.target = undefined; + } + + if (!weakRefReachable) { + weakRef = undefined; + } + + if (collectTargetZone || collectWeakRefZone) { + clearKeptObjects(); + + if (collectTargetZone) { + schedulezone(global); + } + if (collectWeakRefZone) { + schedulezone(this); + } + + // Incremental GC so we use sweep groups. Shrinking GC to test updating + // pointers. + startgc(1, 'shrinking'); + while (gcstate() !== 'NotActive') { + gcslice(1000, {dontStart: true}); + } + } + + if (!(collectWeakRefZone && !weakRefReachable)) { + if (collectTargetZone && !targetReachable) { + assertEq(weakref.deref(), undefined); + } else if (targetReachable) { + assertEq(weakref.deref(), global.target); + } else { + // Target is not strongly reachable but hasn't been collected yet. We + // can get it back through deref() but must check it based on properties. + assertEq(weakref.deref() !== undefined, true); + assertEq(weakref.deref().id, id); + } + } +} + +gczeal(0); + +for (let targetReachable of [true, false]) { + for (let weakRefReachable of [true, false]) { + testSameCompartmentWeakRef(targetReachable, weakRefReachable); + } +} + +for (let targetReachable of [true, false]) { + for (let weakRefReachable of [true, false]) { + for (let collectTargetZone of [true, false]) { + for (let collectWeakRefZone of [true, false]) { + for (let sameZone of [true, false]) { + if (sameZone && (collectTargetZone != collectWeakRefZone)) { + continue; + } + + testCrossCompartmentWeakRef(targetReachable, weakRefReachable, + collectTargetZone, collectWeakRefZone, sameZone); + } + } + } + } +} |