mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 09:15:35 +00:00
Bug 1642685 - Add WeakRef and FinalizationRegistry tests involving DOM objects r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D77798
This commit is contained in:
parent
72b60beac6
commit
1fa83d8c9b
@ -5,43 +5,72 @@
|
||||
<title>Test FinalizationRegistry works in the browser</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript">
|
||||
let registry1, holdings1;
|
||||
let registry2, holdings2;
|
||||
let registry3, holdings3;
|
||||
let registry4, holdings4;
|
||||
let registry5, holdings5;
|
||||
let registry6, holdings6;
|
||||
let registry7, holdings7;
|
||||
let registry8, holdings8;
|
||||
let registry9, holdings9;
|
||||
|
||||
let object4 = {};
|
||||
|
||||
function go() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Registry with no registered objects.
|
||||
let holdings1 = [];
|
||||
let registry1 = new FinalizationRegistry(v => { holdings1.push(v); });
|
||||
holdings1 = [];
|
||||
registry1 = new FinalizationRegistry(v => { holdings1.push(v); });
|
||||
|
||||
// Registry with three registered objects.
|
||||
let holdings2 = [];
|
||||
let registry2 = new FinalizationRegistry(v => { holdings2.push(v); });
|
||||
holdings2 = [];
|
||||
registry2 = new FinalizationRegistry(v => { holdings2.push(v); });
|
||||
registry2.register({}, 1);
|
||||
registry2.register({}, 2);
|
||||
registry2.register({}, 3);
|
||||
|
||||
// Registry with registered object that is then unregistered.
|
||||
let holdings3 = [];
|
||||
let registry3 = new FinalizationRegistry(v => { holdings3.push(v); });
|
||||
holdings3 = [];
|
||||
registry3 = new FinalizationRegistry(v => { holdings3.push(v); });
|
||||
let token3 = {}
|
||||
registry3.register({}, 1, token3);
|
||||
registry3.unregister(token3);
|
||||
|
||||
// Registry with registered object that doesn't die.
|
||||
let holdings4 = [];
|
||||
let registry4 = new FinalizationRegistry(v => { holdings4.push(v); });
|
||||
holdings4 = [];
|
||||
registry4 = new FinalizationRegistry(v => { holdings4.push(v); });
|
||||
registry4.register(object4, 1);
|
||||
|
||||
// Registry observing cyclic JS data structure.
|
||||
let holdings5 = [];
|
||||
let registry5 = new FinalizationRegistry(v => { holdings5.push(v); });
|
||||
holdings5 = [];
|
||||
registry5 = new FinalizationRegistry(v => { holdings5.push(v); });
|
||||
registry5.register(makeJSCycle(4), 5);
|
||||
|
||||
// Registry observing DOM object without preserved wrappers.
|
||||
holdings6 = [];
|
||||
registry6 = new FinalizationRegistry(v => { holdings6.push(v); });
|
||||
registry6.register(document.createElement("div"), 6);
|
||||
|
||||
// Registry observing DOM object with preserved wrappers.
|
||||
holdings7 = [];
|
||||
registry7 = new FinalizationRegistry(v => { holdings7.push(v); });
|
||||
let object = document.createElement("div");
|
||||
object.someProperty = true;
|
||||
registry7.register(object, 7);
|
||||
object = null;
|
||||
|
||||
// Registry observing reachable DOM object without preserved wrappers.
|
||||
holdings8 = [];
|
||||
registry8 = new FinalizationRegistry(v => { holdings8.push(v); });
|
||||
document.body.appendChild(document.createElement("div"));
|
||||
registry8.register(document.body.lastChild, 8);
|
||||
|
||||
// Registry observing cyclic DOM/JS data structure.
|
||||
let holdings6 = [];
|
||||
let registry6 = new FinalizationRegistry(v => { holdings6.push(v); });
|
||||
registry6.register(makeDOMCycle(4), 6);
|
||||
holdings9 = [];
|
||||
registry9 = new FinalizationRegistry(v => { holdings9.push(v); });
|
||||
registry9.register(makeDOMCycle(4), 9);
|
||||
|
||||
// Need to run full GC/CC/GC cycle to collect cyclic garbage through DOM
|
||||
// and JS heaps.
|
||||
@ -57,29 +86,55 @@
|
||||
is(holdings4.length, 0);
|
||||
is(holdings5.length, 0);
|
||||
is(holdings6.length, 0);
|
||||
is(holdings7.length, 0);
|
||||
is(holdings8.length, 0);
|
||||
is(holdings9.length, 0);
|
||||
});
|
||||
|
||||
// setTimeout queues a task which will run after cleanup callbacks.
|
||||
setTimeout(() => {
|
||||
is(holdings1.length, 0);
|
||||
setTimeout(task2, 0);
|
||||
}
|
||||
|
||||
let result = holdings2.sort((a, b) => a - b);
|
||||
is(result.length, 3);
|
||||
is(result[0], 1);
|
||||
is(result[1], 2);
|
||||
is(result[2], 3);
|
||||
function task2() {
|
||||
is(holdings1.length, 0);
|
||||
|
||||
is(holdings3.length, 0);
|
||||
is(holdings4.length, 0);
|
||||
let result = holdings2.sort((a, b) => a - b);
|
||||
is(result.length, 3);
|
||||
is(result[0], 1);
|
||||
is(result[1], 2);
|
||||
is(result[2], 3);
|
||||
|
||||
is(holdings5.length, 1);
|
||||
is(holdings5[0], 5);
|
||||
is(holdings3.length, 0);
|
||||
is(holdings4.length, 0);
|
||||
|
||||
is(holdings6.length, 1);
|
||||
is(holdings6[0], 6);
|
||||
is(holdings5.length, 1);
|
||||
is(holdings5[0], 5);
|
||||
|
||||
SimpleTest.finish();
|
||||
}, 0);
|
||||
is(holdings6.length, 1);
|
||||
is(holdings6[0], 6);
|
||||
|
||||
is(holdings7.length, 1);
|
||||
is(holdings7[0], 7);
|
||||
|
||||
is(holdings8.length, 0);
|
||||
|
||||
is(holdings9.length, 1);
|
||||
is(holdings9[0], 9);
|
||||
|
||||
document.body.removeChild(document.body.lastChild);
|
||||
|
||||
SpecialPowers.DOMWindowUtils.garbageCollect();
|
||||
SpecialPowers.DOMWindowUtils.cycleCollect();
|
||||
SpecialPowers.DOMWindowUtils.garbageCollect();
|
||||
|
||||
setTimeout(task3, 0);
|
||||
}
|
||||
|
||||
function task3() {
|
||||
is(holdings8.length, 1);
|
||||
is(holdings8[0], 8);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function makeJSCycle(size) {
|
||||
|
@ -5,36 +5,74 @@
|
||||
<title>Test WeakRef works in the browser</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript">
|
||||
let wr1, wr2, wr3, wr4;
|
||||
|
||||
function go() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let wr;
|
||||
{
|
||||
let obj = {};
|
||||
wr = new WeakRef(obj);
|
||||
obj = null;
|
||||
}
|
||||
// 1. WeakRef with JS target.
|
||||
wr1 = new WeakRef({});
|
||||
|
||||
// 2. WeakRef with DOM object target (without preserved wrapper).
|
||||
wr2 = new WeakRef(document.createElement("div"));
|
||||
|
||||
// 3. WeakRef with DOM object target (with preserved wrapper).
|
||||
let object = document.createElement("div");
|
||||
object.someProperty = true;
|
||||
wr3 = new WeakRef(object);
|
||||
object = null
|
||||
|
||||
// 4. WeakRef with reachable DOM object target without preserved wrapper.
|
||||
document.body.appendChild(document.createElement("div"));
|
||||
wr4 = new WeakRef(document.body.lastChild);
|
||||
|
||||
// WeakRef should keep the target in the current task.
|
||||
isnot(wr.deref(), undefined, "deref() should return its target.");
|
||||
isnot(wr1.deref(), undefined, "deref() should return its target.");
|
||||
isnot(wr2.deref(), undefined, "deref() should return its target.");
|
||||
isnot(wr3.deref(), undefined, "deref() should return its target.");
|
||||
isnot(wr4.deref(), undefined, "deref() should return its target.");
|
||||
|
||||
// Weakref should keep the target until the end of current Job, that
|
||||
// includes microtask(Promise).
|
||||
// WeakRef should keep the target until the end of current task, which
|
||||
// includes promise microtasks.
|
||||
Promise.resolve().then(() => {
|
||||
isnot(wr.deref(), undefined,
|
||||
"deref() should return its target in promise");
|
||||
|
||||
isnot(wr1.deref(), undefined, "deref() should return its target.");
|
||||
isnot(wr2.deref(), undefined, "deref() should return its target.");
|
||||
isnot(wr3.deref(), undefined, "deref() should return its target.");
|
||||
isnot(wr4.deref(), undefined, "deref() should return its target.");
|
||||
});
|
||||
|
||||
// setTimeout will launch a new job and call ClearKeptObjects().
|
||||
setTimeout(() => {
|
||||
// Call gc() forcibly to clear the target of wr.
|
||||
SpecialPowers.DOMWindowUtils.garbageCollect();
|
||||
// setTimeout will call its callback in a new task.
|
||||
setTimeout(task2, 0);
|
||||
}
|
||||
|
||||
is(wr.deref(), undefined, "deref() should return undefined in the new job.");
|
||||
function task2() {
|
||||
// Trigger a full GC/CC/GC cycle to collect WeakRef targets.
|
||||
SpecialPowers.DOMWindowUtils.garbageCollect();
|
||||
SpecialPowers.DOMWindowUtils.cycleCollect();
|
||||
SpecialPowers.DOMWindowUtils.garbageCollect();
|
||||
|
||||
SimpleTest.finish();
|
||||
}, 0);
|
||||
is(wr1.deref(), undefined, "deref() should return undefined.");
|
||||
is(wr2.deref(), undefined, "deref() should return undefined.");
|
||||
is(wr3.deref(), undefined, "deref() should return undefined.");
|
||||
isnot(wr4.deref(), undefined, "deref() should return its target.");
|
||||
|
||||
// setTimeout will call its callback in a new task.
|
||||
setTimeout(task3, 0);
|
||||
}
|
||||
|
||||
function task3() {
|
||||
document.body.removeChild(document.body.lastChild);
|
||||
|
||||
SpecialPowers.DOMWindowUtils.garbageCollect();
|
||||
SpecialPowers.DOMWindowUtils.cycleCollect();
|
||||
SpecialPowers.DOMWindowUtils.garbageCollect();
|
||||
|
||||
is(wr1.deref(), undefined, "deref() should return undefined.");
|
||||
is(wr2.deref(), undefined, "deref() should return undefined.");
|
||||
is(wr3.deref(), undefined, "deref() should return undefined.");
|
||||
is(wr4.deref(), undefined, "deref() should return undefined.");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
Loading…
Reference in New Issue
Block a user