summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/gc/weakRefs.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/gc/weakRefs.js')
-rw-r--r--js/src/jit-test/tests/gc/weakRefs.js122
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..cb7dcb829a
--- /dev/null
+++ b/js/src/jit-test/tests/gc/weakRefs.js
@@ -0,0 +1,122 @@
+// https://tc39.es/proposal-weakrefs/#sec-keepduringjob
+// When the abstract operation KeepDuringJob 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);
+ }
+ }
+ }
+ }
+}