Revert "[heap][test] Fix weakrefs tests for conservative stack scanning"
This reverts commit 20a954f4bc
.
Reason for revert: Alas, GC stress failures:
https://ci.chromium.org/ui/p/v8/builders/ci/V8%20Linux64%20GC%20Stress%20-%20custom%20snapshot/45646/overview
Original change's description:
> [heap][test] Fix weakrefs tests for conservative stack scanning
>
> 31 out of the 36 JS tests in test/mjsunit/harmony/weakrefs/ rely on
> precise GC with the following general pattern: they allocate some
> objects, clear all references to them, invoke a GC, then perform
> some test that assumes that the GC has reclaimed the objects.
> When conservative stack scanning is used, this may fail.
>
> This CL fixes the tests, ensuring that a precise GC will be invoked
> when necessary, without scanning the stack. To achieve this, the GC
> has to be invoked in asynchronous execution mode, which ensures that
> it will be invoked from the event loop without a stack. In some
> cases, this change requires a non-trivial change in the tests.
>
> In 5 tests, part of the test's objective was to verify that a weak
> reference is not cleared before the end of the turn. In those, it
> was not possible to invoke GC asynchronously, as this would
> immediately start a new turn. These tests still use synchronous GC
> and they have been modified, if necessary, to allow for CSS (i.e.,
> to not test that all possible garbage is reclaimed after a
> sequential GC). Because of CSS, these tests may not always test
> everything that they were intended to.
>
> Tests with trivial fix:
>
> - cleanup-from-different-realm
> - cleanup
> - cleanup-proxy-from-different-realm
> - cleanupsome-2
> - cleanupsome-after-unregister
> - cleanupsome
> - finalizationregistry-keeps-holdings-alive
> - multiple-dirty-finalization-groups
> - stress-finalizationregistry-dirty-enqueue
> - undefined-holdings
> - unregister-after-cleanup
> - unregister-before-cleanup
> - unregister-called-twice
> - unregister-inside-cleanup2
> - unregister-inside-cleanup3
> - unregister-inside-cleanup
> - unregister-many
> - unregister-when-cleanup-already-scheduled
> - weak-cell-basics
>
> Tests with non-trivial fixes; same logic but very restructured:
>
> - cleanup-is-not-a-microtask:
> - cleanup-on-detached-realm
> - finalizationregistry-scheduled-for-cleanup-multiple-times
> - finalizationregistry-independent-lifetime
> - finalizationregistry-independent-lifetime-multiple
> - reentrant-gc-from-cleanup
> - symbol-in-finalizationregistry
> (was 2nd part of former symbol-as-weakref-target-gc)
> - weak-unregistertoken
>
> Tests with non-trivial fixes; same logic, restructured, using
> synchronous GC:
>
> - finalizationregistry-and-weakref
> - symbol-as-weakref-target-gc
> (was 1st part of former symbol-as-weakref-target-gc)
> - two-weakrefs
> - weakref-creation-keeps-alive
> - weakref-deref-keeps-alive
>
> Bug: v8:13257
> Bug: v8:13662
> Change-Id: I53586bd16cdb98fa976e1fa798ef498bdf286238
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4191774
> Reviewed-by: Marja Hölttä <marja@chromium.org>
> Reviewed-by: Shu-yu Guo <syg@chromium.org>
> Commit-Queue: Nikolaos Papaspyrou <nikolaos@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#85477}
Bug: v8:13257
Bug: v8:13662
Change-Id: Icc7a907928ccac058f8acdf320c21b2df04c1b78
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4192256
Auto-Submit: Shu-yu Guo <syg@chromium.org>
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/heads/main@{#85479}
This commit is contained in:
parent
930b17be77
commit
95b79bf04b
@ -4,36 +4,31 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let r = Realm.create();
|
||||||
|
|
||||||
let r = Realm.create();
|
let cleanup = Realm.eval(r, "var stored_global; function cleanup() { stored_global = globalThis; } cleanup");
|
||||||
|
let realm_global_this = Realm.eval(r, "globalThis");
|
||||||
|
|
||||||
let cleanup = Realm.eval(r, "var stored_global; function cleanup() { stored_global = globalThis; } cleanup");
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
let realm_global_this = Realm.eval(r, "globalThis");
|
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
// Create an object and a register it in the FinalizationRegistry. The object needs
|
||||||
|
// to be inside a closure so that we can reliably kill them!
|
||||||
|
let weak_cell;
|
||||||
|
|
||||||
// Create an object and register it in the FinalizationRegistry. The object needs
|
(function() {
|
||||||
// to be inside a closure so that we can reliably kill them!
|
let object = {};
|
||||||
(function () {
|
fg.register(object, {});
|
||||||
let object = {};
|
|
||||||
fg.register(object, {});
|
|
||||||
// Object goes out of scope.
|
|
||||||
})();
|
|
||||||
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
// Assert that the cleanup function was called in its Realm.
|
|
||||||
let timeout_func = function () {
|
|
||||||
let stored_global = Realm.eval(r, "stored_global;");
|
|
||||||
assertNotEquals(stored_global, globalThis);
|
|
||||||
assertEquals(stored_global, realm_global_this);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// object goes out of scope.
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
gc();
|
||||||
|
|
||||||
|
// Assert that the cleanup function was called in its Realm.
|
||||||
|
let timeout_func = function() {
|
||||||
|
let stored_global = Realm.eval(r, "stored_global;");
|
||||||
|
assertNotEquals(stored_global, globalThis);
|
||||||
|
assertEquals(stored_global, realm_global_this);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -2,55 +2,60 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking --allow-natives-syntax
|
||||||
|
|
||||||
// This test asserts that the cleanup function call, scheduled by GC, is
|
// This test asserts that the cleanup function call, scheduled by GC, is a
|
||||||
// not a microtask but a normal task.
|
// microtask and not a normal task.
|
||||||
|
|
||||||
(async function () {
|
// Inside a microtask, cause GC (which should schedule the cleanup as
|
||||||
|
// microtask). lso schedule another microtask. Assert that the cleanup
|
||||||
|
// function ran before the other microtask.
|
||||||
|
|
||||||
let microtaskInvoked = false;
|
let cleanedUp = false;
|
||||||
const microtask = () => {
|
|
||||||
assertFalse(cleanedUp);
|
|
||||||
assertFalse(microtaskInvoked);
|
|
||||||
microtaskInvoked = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
let cleanedUp = false;
|
function scheduleMicrotask(func) {
|
||||||
const cleanup = (holdings) => {
|
Promise.resolve().then(func);
|
||||||
assertFalse(cleanedUp);
|
}
|
||||||
assertTrue(microtaskInvoked);
|
|
||||||
cleanedUp = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const fg = new FinalizationRegistry(cleanup);
|
let log = [];
|
||||||
|
|
||||||
(function() {
|
let cleanup = (holdings) => {
|
||||||
// Use a closure here to avoid other references to object which might keep
|
cleanedUp = true;
|
||||||
// it alive (e.g., stack frames pointing to it).
|
}
|
||||||
const object = {};
|
|
||||||
fg.register(object, {});
|
|
||||||
})();
|
|
||||||
|
|
||||||
// The GC will schedule the cleanup as a regular task.
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
let o = null;
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
assertFalse(cleanedUp);
|
|
||||||
|
|
||||||
// Schedule the microtask.
|
|
||||||
Promise.resolve().then(microtask);
|
|
||||||
|
|
||||||
// Nothing else hasn't been called yet, as we're still in synchronous
|
|
||||||
// execution.
|
|
||||||
assertFalse(microtaskInvoked);
|
|
||||||
assertFalse(cleanedUp);
|
|
||||||
|
|
||||||
// The microtask and the cleanup callbacks will verify that these two are
|
|
||||||
// invoked in the right order: microtask -> cleanup.
|
|
||||||
setTimeout(() => { assertTrue(cleanedUp); }, 0);
|
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
// Use a closure here to avoid other references to o which might keep it alive
|
||||||
|
// (e.g., stack frames pointing to it).
|
||||||
|
o = {};
|
||||||
|
fg.register(o, {});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
let microtask = function() {
|
||||||
|
log.push("first_microtask");
|
||||||
|
|
||||||
|
// cause GC during a microtask
|
||||||
|
o = null;
|
||||||
|
gc();
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFalse(cleanedUp);
|
||||||
|
|
||||||
|
// enqueue microtask that triggers GC
|
||||||
|
Promise.resolve().then(microtask);
|
||||||
|
|
||||||
|
// but cleanup callback hasn't been called yet, as we're still in
|
||||||
|
// synchronous execution
|
||||||
|
assertFalse(cleanedUp);
|
||||||
|
|
||||||
|
// flush the microtask queue to run the microtask that triggers GC
|
||||||
|
%PerformMicrotaskCheckpoint();
|
||||||
|
|
||||||
|
// still no cleanup callback, because it runs after as a separate task
|
||||||
|
assertFalse(cleanedUp);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
assertTrue(cleanedUp);
|
||||||
|
}, 0);
|
||||||
|
@ -4,66 +4,35 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanedUp = false;
|
||||||
|
let r = Realm.create();
|
||||||
const r = Realm.create();
|
let FG = Realm.eval(r, "FinalizationRegistry");
|
||||||
const FG = Realm.eval(r, "FinalizationRegistry");
|
Realm.detachGlobal(r);
|
||||||
Realm.detachGlobal(r);
|
|
||||||
|
|
||||||
const cleanup_not_run = function (holdings) {
|
|
||||||
assertUnreachable();
|
|
||||||
}
|
|
||||||
let fg_not_run = new FG(cleanup_not_run);
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
const object = {};
|
|
||||||
fg_not_run.register(object, "first");
|
|
||||||
// Object becomes unreachable.
|
|
||||||
})();
|
|
||||||
|
|
||||||
let cleanedUp = false;
|
|
||||||
let fg_run;
|
|
||||||
|
|
||||||
// Schedule a GC, which will schedule fg_not_run for cleanup.
|
|
||||||
// Here and below, we need to invoke GC asynchronously and wait for it to
|
|
||||||
// finish, so that it doesn't need to scan the stack. Otherwise, the objects
|
|
||||||
// may not be reclaimed because of conservative stack scanning and the test
|
|
||||||
// may not work as intended.
|
|
||||||
let task_1_gc = (async function () {
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
// Disposing the realm cancels the already scheduled fg_not_run's finalizer.
|
|
||||||
Realm.dispose(r);
|
|
||||||
|
|
||||||
const cleanup = function (holdings) {
|
|
||||||
assertEquals(holdings, "second");
|
|
||||||
assertFalse(cleanedUp);
|
|
||||||
cleanedUp = true;
|
|
||||||
}
|
|
||||||
fg_run = new FG(cleanup);
|
|
||||||
|
|
||||||
// FGs that are alive after disposal can still schedule tasks.
|
|
||||||
(function () {
|
|
||||||
const object = {};
|
|
||||||
fg_run.register(object, "second");
|
|
||||||
// Object becomes unreachable.
|
|
||||||
})();
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Schedule a second GC for execution after that, which will now schedule
|
|
||||||
// fg_run for cleanup.
|
|
||||||
let task_2_gc = (async function () {
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
// Check that the cleanup task has had the chance to run yet.
|
|
||||||
assertFalse(cleanedUp);
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Wait for the two GCs to be executed.
|
|
||||||
await task_1_gc;
|
|
||||||
await task_2_gc;
|
|
||||||
|
|
||||||
// Give the cleanup task a chance to run and check it worked correctly.
|
|
||||||
setTimeout(function () { assertTrue(cleanedUp); }, 0);
|
|
||||||
|
|
||||||
|
let fg_not_run = new FG(() => {
|
||||||
|
assertUnreachable();
|
||||||
|
});
|
||||||
|
(() => {
|
||||||
|
fg_not_run.register({});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
gc();
|
||||||
|
|
||||||
|
// Disposing the realm cancels the already scheduled fg_not_run's finalizer.
|
||||||
|
Realm.dispose(r);
|
||||||
|
|
||||||
|
let fg = new FG(()=> {
|
||||||
|
cleanedUp = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// FGs that are alive after disposal can still schedule tasks.
|
||||||
|
(() => {
|
||||||
|
let object = {};
|
||||||
|
fg.register(object, {});
|
||||||
|
|
||||||
|
// object becomes unreachable.
|
||||||
|
})();
|
||||||
|
|
||||||
|
gc();
|
||||||
|
|
||||||
|
setTimeout(function() { assertTrue(cleanedUp); }, 0);
|
||||||
|
@ -4,39 +4,31 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let r = Realm.create();
|
||||||
|
|
||||||
let r = Realm.create();
|
let cleanup = Realm.eval(r, "var stored_global; let cleanup = new Proxy(function() { stored_global = globalThis;}, {}); cleanup");
|
||||||
|
let realm_global_this = Realm.eval(r, "globalThis");
|
||||||
|
|
||||||
let cleanup = Realm.eval(r, "var stored_global; let cleanup = new Proxy(function() { stored_global = globalThis;}, {}); cleanup");
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
let realm_global_this = Realm.eval(r, "globalThis");
|
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
// Create an object and register it in the FinalizationRegistry. The object needs
|
||||||
|
// to be inside a closure so that we can reliably kill them!
|
||||||
|
let weak_cell;
|
||||||
|
|
||||||
// Create an object and register it in the FinalizationRegistry. The object needs
|
(function() {
|
||||||
// to be inside a closure so that we can reliably kill them!
|
let object = {};
|
||||||
let weak_cell;
|
fg.register(object, "holdings");
|
||||||
|
|
||||||
(function () {
|
|
||||||
let object = {};
|
|
||||||
fg.register(object, "holdings");
|
|
||||||
|
|
||||||
// object goes out of scope.
|
|
||||||
})();
|
|
||||||
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
// Assert that the cleanup function was called in its Realm.
|
|
||||||
let timeout_func = function () {
|
|
||||||
let stored_global = Realm.eval(r, "stored_global;");
|
|
||||||
assertNotEquals(stored_global, globalThis);
|
|
||||||
assertEquals(stored_global, realm_global_this);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// object goes out of scope.
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
gc();
|
||||||
|
|
||||||
|
// Assert that the cleanup function was called in its Realm.
|
||||||
|
let timeout_func = function() {
|
||||||
|
let stored_global = Realm.eval(r, "stored_global;");
|
||||||
|
assertNotEquals(stored_global, globalThis);
|
||||||
|
assertEquals(stored_global, realm_global_this);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,56 +4,48 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_called = 0;
|
||||||
|
let holdings_list = [];
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
holdings_list.push(holdings);
|
||||||
|
cleanup_called++;
|
||||||
|
}
|
||||||
|
|
||||||
let cleanup_called = 0;
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
let holdings_list = [];
|
let o1 = {};
|
||||||
let cleanup = function (holdings) {
|
let o2 = {};
|
||||||
holdings_list.push(holdings);
|
|
||||||
cleanup_called++;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
|
||||||
let o1 = {};
|
|
||||||
let o2 = {};
|
|
||||||
|
|
||||||
// Ignition holds references to objects in temporary registers. These will be
|
|
||||||
// released when the function exits. So only access o inside a function to
|
|
||||||
// prevent any references to objects in temporary registers when a gc is
|
|
||||||
(function () {
|
|
||||||
fg.register(o1, 1);
|
|
||||||
fg.register(o2, 2);
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Here and below, we need to invoke GC asynchronously and wait for it to
|
|
||||||
// finish, so that it doesn't need to scan the stack. Otherwise, the objects
|
|
||||||
// may not be reclaimed because of conservative stack scanning and the test
|
|
||||||
// may not work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(cleanup_called, 0);
|
|
||||||
|
|
||||||
// Drop the last references to o1 and o2.
|
|
||||||
(function () {
|
|
||||||
o1 = null;
|
|
||||||
o2 = null;
|
|
||||||
})();
|
|
||||||
|
|
||||||
// GC will reclaim the target objects; the cleanup function will be called the
|
|
||||||
// next time we enter the event loop.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(cleanup_called, 0);
|
|
||||||
|
|
||||||
let timeout_func = function () {
|
|
||||||
assertEquals(cleanup_called, 2);
|
|
||||||
assertEquals(holdings_list.length, 2);
|
|
||||||
if (holdings_list[0] == 1) {
|
|
||||||
assertEquals(holdings_list[1], 2);
|
|
||||||
} else {
|
|
||||||
assertEquals(holdings_list[0], 2);
|
|
||||||
assertEquals(holdings_list[1], 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// Ignition holds references to objects in temporary registers. These will be
|
||||||
|
// released when the function exits. So only access o inside a function to
|
||||||
|
// prevent any references to objects in temporary registers when a gc is
|
||||||
|
(function() {
|
||||||
|
fg.register(o1, 1);
|
||||||
|
fg.register(o2, 2);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
gc();
|
||||||
|
assertEquals(cleanup_called, 0);
|
||||||
|
|
||||||
|
// Drop the last references to o1 and o2.
|
||||||
|
(function() {
|
||||||
|
o1 = null;
|
||||||
|
o2 = null;
|
||||||
|
})();
|
||||||
|
|
||||||
|
// GC will reclaim the target objects; the cleanup function will be called the
|
||||||
|
// next time we enter the event loop.
|
||||||
|
gc();
|
||||||
|
assertEquals(cleanup_called, 0);
|
||||||
|
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertEquals(cleanup_called, 2);
|
||||||
|
assertEquals(holdings_list.length, 2);
|
||||||
|
if (holdings_list[0] == 1) {
|
||||||
|
assertEquals(holdings_list[1], 2);
|
||||||
|
} else {
|
||||||
|
assertEquals(holdings_list[0], 2);
|
||||||
|
assertEquals(holdings_list[1], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,34 +4,26 @@
|
|||||||
|
|
||||||
// Flags: --harmony-weak-refs-with-cleanup-some --expose-gc --noincremental-marking --allow-natives-syntax
|
// Flags: --harmony-weak-refs-with-cleanup-some --expose-gc --noincremental-marking --allow-natives-syntax
|
||||||
|
|
||||||
(async function () {
|
let cleanup_count = 0;
|
||||||
|
let cleanup_holdings = [];
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
cleanup_holdings.push(holdings);
|
||||||
|
++cleanup_count;
|
||||||
|
}
|
||||||
|
|
||||||
let cleanup_count = 0;
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
let cleanup_holdings = [];
|
(function() {
|
||||||
let cleanup = function (holdings) {
|
let o = {};
|
||||||
cleanup_holdings.push(holdings);
|
fg.register(o, "holdings");
|
||||||
++cleanup_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
|
||||||
(function () {
|
|
||||||
let o = {};
|
|
||||||
fg.register(o, "holdings");
|
|
||||||
|
|
||||||
assertEquals(0, cleanup_count);
|
|
||||||
})();
|
|
||||||
|
|
||||||
// GC will detect o as dead.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
// passing no callback, should trigger cleanup function
|
|
||||||
fg.cleanupSome();
|
|
||||||
assertEquals(1, cleanup_count);
|
|
||||||
assertEquals(1, cleanup_holdings.length);
|
|
||||||
assertEquals("holdings", cleanup_holdings[0]);
|
|
||||||
|
|
||||||
|
assertEquals(0, cleanup_count);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// GC will detect o as dead.
|
||||||
|
gc();
|
||||||
|
|
||||||
|
// passing no callback, should trigger cleanup function
|
||||||
|
fg.cleanupSome();
|
||||||
|
assertEquals(1, cleanup_count);
|
||||||
|
assertEquals(1, cleanup_holdings.length);
|
||||||
|
assertEquals("holdings", cleanup_holdings[0]);
|
||||||
|
@ -4,39 +4,31 @@
|
|||||||
|
|
||||||
// Flags: --harmony-weak-refs-with-cleanup-some --expose-gc --noincremental-marking
|
// Flags: --harmony-weak-refs-with-cleanup-some --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_count = 0;
|
||||||
|
let cleanup_holdings = [];
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
cleanup_holdings.push(holdings);
|
||||||
|
++cleanup_count;
|
||||||
|
}
|
||||||
|
|
||||||
let cleanup_count = 0;
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
let cleanup_holdings = [];
|
let key = {"k": "this is the key"};
|
||||||
let cleanup = function (holdings) {
|
(function() {
|
||||||
cleanup_holdings.push(holdings);
|
let o = {};
|
||||||
++cleanup_count;
|
weak_cell = fg.register(o, "holdings", key);
|
||||||
}
|
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
|
||||||
let key = { "k": "this is the key" };
|
|
||||||
(function () {
|
|
||||||
let o = {};
|
|
||||||
weak_cell = fg.register(o, "holdings", key);
|
|
||||||
|
|
||||||
// cleanupSome won't do anything since there are no reclaimed targets.
|
|
||||||
fg.cleanupSome();
|
|
||||||
assertEquals(0, cleanup_count);
|
|
||||||
return o;
|
|
||||||
})();
|
|
||||||
|
|
||||||
// GC will detect the WeakCell as dirty.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
// Unregister the tracked object just before calling cleanupSome.
|
|
||||||
fg.unregister(key);
|
|
||||||
|
|
||||||
|
// cleanupSome won't do anything since there are no reclaimed targets.
|
||||||
fg.cleanupSome();
|
fg.cleanupSome();
|
||||||
|
|
||||||
assertEquals(0, cleanup_count);
|
assertEquals(0, cleanup_count);
|
||||||
|
return o;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// GC will detect the WeakCell as dirty.
|
||||||
|
gc();
|
||||||
|
|
||||||
|
// Unregister the tracked object just before calling cleanupSome.
|
||||||
|
fg.unregister(key);
|
||||||
|
|
||||||
|
fg.cleanupSome();
|
||||||
|
|
||||||
|
assertEquals(0, cleanup_count);
|
||||||
|
@ -4,39 +4,31 @@
|
|||||||
|
|
||||||
// Flags: --harmony-weak-refs-with-cleanup-some --expose-gc --noincremental-marking --allow-natives-syntax
|
// Flags: --harmony-weak-refs-with-cleanup-some --expose-gc --noincremental-marking --allow-natives-syntax
|
||||||
|
|
||||||
(async function () {
|
let cleanup_count = 0;
|
||||||
|
let cleanup_holdings = [];
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
%AbortJS("shouldn't be called");
|
||||||
|
}
|
||||||
|
|
||||||
let cleanup_count = 0;
|
let cleanup2 = function(holdings) {
|
||||||
let cleanup_holdings = [];
|
cleanup_holdings.push(holdings);
|
||||||
let cleanup = function (holdings) {
|
++cleanup_count;
|
||||||
%AbortJS("shouldn't be called");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let cleanup2 = function (holdings) {
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
cleanup_holdings.push(holdings);
|
(function() {
|
||||||
++cleanup_count;
|
let o = {};
|
||||||
}
|
fg.register(o, "holdings");
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
|
||||||
(function () {
|
|
||||||
let o = {};
|
|
||||||
fg.register(o, "holdings");
|
|
||||||
|
|
||||||
// cleanupSome won't do anything since there are no reclaimed targets.
|
|
||||||
fg.cleanupSome(cleanup2);
|
|
||||||
assertEquals(0, cleanup_count);
|
|
||||||
})();
|
|
||||||
|
|
||||||
// GC will detect o as dead.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
|
// cleanupSome won't do anything since there are no reclaimed targets.
|
||||||
fg.cleanupSome(cleanup2);
|
fg.cleanupSome(cleanup2);
|
||||||
assertEquals(1, cleanup_count);
|
assertEquals(0, cleanup_count);
|
||||||
assertEquals(1, cleanup_holdings.length);
|
|
||||||
assertEquals("holdings", cleanup_holdings[0]);
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// GC will detect o as dead.
|
||||||
|
gc();
|
||||||
|
|
||||||
|
fg.cleanupSome(cleanup2);
|
||||||
|
assertEquals(1, cleanup_count);
|
||||||
|
assertEquals(1, cleanup_holdings.length);
|
||||||
|
assertEquals("holdings", cleanup_holdings[0]);
|
||||||
|
@ -4,46 +4,39 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_called = false;
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
assertFalse(cleanup_called);
|
||||||
|
let holdings_list = [];
|
||||||
|
holdings_list.push(holdings);
|
||||||
|
assertEquals(1, holdings_list.length);
|
||||||
|
assertEquals("holdings", holdings_list[0]);
|
||||||
|
cleanup_called = true;
|
||||||
|
}
|
||||||
|
|
||||||
let cleanup_called = false;
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
const cleanup = function(holdings) {
|
let weak_ref;
|
||||||
assertFalse(cleanup_called);
|
(function() {
|
||||||
assertEquals("holdings", holdings);
|
let o = {};
|
||||||
cleanup_called = true;
|
weak_ref = new WeakRef(o);
|
||||||
}
|
fg.register(o, "holdings");
|
||||||
|
})();
|
||||||
|
|
||||||
const fg = new FinalizationRegistry(cleanup);
|
// Since the WeakRef was created during this turn, it is not cleared by GC. The
|
||||||
let weak_ref;
|
// pointer inside the FinalizationRegistry is not cleared either, since the WeakRef
|
||||||
(function() {
|
// keeps the target object alive.
|
||||||
const o = {};
|
gc();
|
||||||
weak_ref = new WeakRef(o);
|
(function() {
|
||||||
fg.register(o, "holdings");
|
assertNotEquals(undefined, weak_ref.deref());
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// Since the WeakRef was created during this turn, it is not cleared by GC. The
|
// Trigger gc in next task
|
||||||
// pointer inside the FinalizationRegistry is not cleared either, since the WeakRef
|
setTimeout(() => {
|
||||||
// keeps the target object alive.
|
|
||||||
// Here we invoke GC synchronously and, with conservative stack scanning, there is
|
|
||||||
// a chance that the object is not reclaimed now. In any case, the WeakRef should
|
|
||||||
// not be cleared.
|
|
||||||
gc();
|
gc();
|
||||||
|
|
||||||
assertNotEquals(undefined, weak_ref.deref());
|
// Check that cleanup callback was called in a follow up task
|
||||||
assertFalse(cleanup_called);
|
setTimeout(() => {
|
||||||
|
assertTrue(cleanup_called);
|
||||||
// Trigger GC in next task. Now the WeakRef is cleared but the cleanup has
|
assertEquals(undefined, weak_ref.deref());
|
||||||
// not been called yet.
|
}, 0);
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
}, 0);
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
assertEquals(undefined, weak_ref.deref());
|
|
||||||
assertFalse(cleanup_called);
|
|
||||||
|
|
||||||
// Check that the cleanup callback was called in a follow up task.
|
|
||||||
setTimeout(() => { assertTrue(cleanup_called); }, 0);
|
|
||||||
|
|
||||||
})();
|
|
||||||
|
@ -4,49 +4,29 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking --no-concurrent-inlining
|
// Flags: --expose-gc --noincremental-marking --no-concurrent-inlining
|
||||||
|
|
||||||
(async function () {
|
let cleanup_called = false;
|
||||||
|
function cleanup(holdings) {
|
||||||
let cleanup_called = false;
|
cleanup_called = true;
|
||||||
function cleanup(holdings) {
|
};
|
||||||
cleanup_called = true;
|
let cleanup_called_2 = false;
|
||||||
};
|
function cleanup2(holdings) {
|
||||||
|
cleanup_called_2 = true;
|
||||||
let cleanup_called_2 = false;
|
};
|
||||||
function cleanup2(holdings) {
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
cleanup_called_2 = true;
|
(function() {
|
||||||
};
|
let fg2 = new FinalizationRegistry(cleanup2);
|
||||||
|
(function() {
|
||||||
const fg = new FinalizationRegistry(cleanup);
|
fg.register({}, {});
|
||||||
|
fg2.register({}, {});
|
||||||
let task_1_gc = (async function () {
|
|
||||||
const fg2 = new FinalizationRegistry(cleanup2);
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
fg.register({}, "holdings1");
|
|
||||||
fg2.register({}, "holdings2");
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Schedule fg and fg2 for cleanup.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertFalse(cleanup_called);
|
|
||||||
assertFalse(cleanup_called_2);
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Schedule a task to collect fg2, but fg is still alive.
|
|
||||||
let task_2_gc = (async function () {
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertFalse(cleanup_called);
|
|
||||||
assertFalse(cleanup_called_2);
|
|
||||||
})();
|
})();
|
||||||
|
// Schedule fg and fg2 for cleanup.
|
||||||
// Wait for the two GC tasks to be executed.
|
gc();
|
||||||
await task_1_gc;
|
|
||||||
await task_2_gc;
|
|
||||||
|
|
||||||
// Check that only the cleanup for fg will be called.
|
|
||||||
setTimeout(function() {
|
|
||||||
assertTrue(cleanup_called);
|
|
||||||
assertFalse(cleanup_called_2);
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// Collect fg2, but fg is still alive.
|
||||||
|
gc();
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
assertTrue(cleanup_called);
|
||||||
|
assertFalse(cleanup_called_2);
|
||||||
|
}, 0);
|
||||||
|
@ -4,38 +4,22 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking --no-concurrent-recompilation
|
// Flags: --expose-gc --noincremental-marking --no-concurrent-recompilation
|
||||||
|
|
||||||
(async function () {
|
let cleanup_called = false;
|
||||||
|
function cleanup(holdings) {
|
||||||
let cleanup_called = false;
|
cleanup_called = true;
|
||||||
function cleanup(holdings) {
|
};
|
||||||
cleanup_called = true;
|
(function() {
|
||||||
};
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
|
(function() {
|
||||||
let task_1_gc = (async function () {
|
let x = {};
|
||||||
const fg = new FinalizationRegistry(cleanup);
|
fg.register(x, {});
|
||||||
|
x = null;
|
||||||
(function () {
|
|
||||||
let x = {};
|
|
||||||
fg.register(x, "holdings");
|
|
||||||
x = null;
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Schedule fg for cleanup.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertFalse(cleanup_called);
|
|
||||||
})();
|
})();
|
||||||
|
// Schedule fg for cleanup.
|
||||||
// Schedule a task to collect fg, which should result in cleanup not called.
|
gc();
|
||||||
let task_2_gc = (async function () {
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertFalse(cleanup_called);
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Wait for the two GC tasks to be executed.
|
|
||||||
await task_1_gc;
|
|
||||||
await task_2_gc;
|
|
||||||
|
|
||||||
// Check that the cleanup will not be called.
|
|
||||||
setTimeout(function () { assertFalse(cleanup_called); }, 0);
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// Collect fg, which should result in cleanup not called.
|
||||||
|
gc();
|
||||||
|
|
||||||
|
setTimeout(function() { assertFalse(cleanup_called); }, 0);
|
||||||
|
@ -4,48 +4,40 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_called = false;
|
||||||
|
let holdings_list = [];
|
||||||
let cleanup_called = false;
|
let cleanup = function(holdings) {
|
||||||
let holdings_list = [];
|
|
||||||
let cleanup = function (holdings) {
|
|
||||||
assertFalse(cleanup_called);
|
|
||||||
holdings_list.push(holdings);
|
|
||||||
cleanup_called = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
|
||||||
let o1 = {};
|
|
||||||
let holdings = { 'a': 'this is the holdings object' };
|
|
||||||
|
|
||||||
// Ignition holds references to objects in temporary registers. These will be
|
|
||||||
// released when the function exits. So only access o inside a function to
|
|
||||||
// prevent any references to objects in temporary registers when a gc is
|
|
||||||
// triggered.
|
|
||||||
(() => { fg.register(o1, holdings); })()
|
|
||||||
|
|
||||||
// Here and below, we need to invoke GC asynchronously and wait for it to
|
|
||||||
// finish, so that it doesn't need to scan the stack. Otherwise, the objects
|
|
||||||
// may not be reclaimed because of conservative stack scanning and the test
|
|
||||||
// may not work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertFalse(cleanup_called);
|
assertFalse(cleanup_called);
|
||||||
|
holdings_list.push(holdings);
|
||||||
|
cleanup_called = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Drop the last references to o1.
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
(() => { o1 = null; })()
|
let o1 = {};
|
||||||
|
let holdings = {'a': 'this is the holdings object'};
|
||||||
|
|
||||||
// Drop the last reference to the holdings. The FinalizationRegistry keeps it
|
// Ignition holds references to objects in temporary registers. These will be
|
||||||
// alive, so the cleanup function will be called as normal.
|
// released when the function exits. So only access o inside a function to
|
||||||
holdings = null;
|
// prevent any references to objects in temporary registers when a gc is
|
||||||
await gc({ type: 'major', execution: 'async' });
|
// triggered.
|
||||||
assertFalse(cleanup_called);
|
(() => {fg.register(o1, holdings);})()
|
||||||
|
|
||||||
let timeout_func = function () {
|
gc();
|
||||||
assertTrue(cleanup_called);
|
assertFalse(cleanup_called);
|
||||||
assertEquals(holdings_list.length, 1);
|
|
||||||
assertEquals(holdings_list[0].a, "this is the holdings object");
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
// Drop the last references to o1.
|
||||||
|
(() => {o1 = null;})()
|
||||||
|
|
||||||
})();
|
// Drop the last reference to the holdings. The FinalizationRegistry keeps it
|
||||||
|
// alive, so the cleanup function will be called as normal.
|
||||||
|
holdings = null;
|
||||||
|
gc();
|
||||||
|
assertFalse(cleanup_called);
|
||||||
|
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertTrue(cleanup_called);
|
||||||
|
assertEquals(holdings_list.length, 1);
|
||||||
|
assertEquals(holdings_list[0].a, "this is the holdings object");
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -5,78 +5,63 @@
|
|||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
// Flags: --no-stress-flush-code
|
// Flags: --no-stress-flush-code
|
||||||
|
|
||||||
(async function () {
|
let cleanup0_call_count = 0;
|
||||||
|
let cleanup0_holdings_count = 0;
|
||||||
|
|
||||||
let cleanup0_call_count = 0;
|
let cleanup1_call_count = 0;
|
||||||
let cleanup1_call_count = 0;
|
let cleanup1_holdings_count = 0;
|
||||||
|
|
||||||
let cleanup0 = function (holdings) {
|
let cleanup0 = function(holdings) {
|
||||||
++cleanup0_call_count;
|
++cleanup0_holdings_count;
|
||||||
}
|
++cleanup0_call_count;
|
||||||
|
}
|
||||||
|
|
||||||
let cleanup1 = function (holdings) {
|
let cleanup1 = function(holdings) {
|
||||||
++cleanup1_call_count;
|
++cleanup1_holdings_count;
|
||||||
}
|
++cleanup1_call_count;
|
||||||
|
}
|
||||||
|
|
||||||
let fg0 = new FinalizationRegistry(cleanup0);
|
let fg0 = new FinalizationRegistry(cleanup0);
|
||||||
let fg1 = new FinalizationRegistry(cleanup1);
|
let fg1 = new FinalizationRegistry(cleanup1);
|
||||||
|
|
||||||
// Register 1 weak reference for each FinalizationRegistry and kill the
|
// Register 1 weak reference for each FinalizationRegistry and kill the objects they point to.
|
||||||
// objects they point to.
|
(function() {
|
||||||
(function () {
|
// The objects need to be inside a closure so that we can reliably kill them.
|
||||||
// The objects need to be inside a closure so that we can reliably kill
|
let objects = [];
|
||||||
// them.
|
objects[0] = {};
|
||||||
let objects = [];
|
objects[1] = {};
|
||||||
objects[0] = {};
|
|
||||||
objects[1] = {};
|
|
||||||
fg0.register(objects[0], "holdings0-0");
|
|
||||||
fg1.register(objects[1], "holdings1-0");
|
|
||||||
// Drop the references to the objects.
|
|
||||||
objects = [];
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Schedule a GC, which will schedule both fg0 and fg1 for cleanup.
|
fg0.register(objects[0], "holdings0-0");
|
||||||
// Here and below, we need to invoke GC asynchronously and wait for it to
|
fg1.register(objects[1], "holdings1-0");
|
||||||
// finish, so that it doesn't need to scan the stack. Otherwise, the objects
|
|
||||||
// may not be reclaimed because of conservative stack scanning and the test
|
|
||||||
// may not work as intended.
|
|
||||||
let task_1_gc = (async function () {
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
// Before the cleanup task has a chance to run, do the same thing again, so
|
|
||||||
// both FinalizationRegistries are (again) scheduled for cleanup. This has to
|
|
||||||
// be a IIFE function (so that we can reliably kill the objects) so we cannot
|
|
||||||
// use the same function as before.
|
|
||||||
(function () {
|
|
||||||
let objects = [];
|
|
||||||
objects[0] = {};
|
|
||||||
objects[1] = {};
|
|
||||||
fg0.register(objects[0], "holdings0-1");
|
|
||||||
fg1.register(objects[1], "holdings1-1");
|
|
||||||
objects = [];
|
|
||||||
})();
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Schedule a second GC for execution after that, which will again schedule
|
|
||||||
// both fg0 and fg1 for cleanup.
|
|
||||||
let task_2_gc = (async function () {
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
// Check that no cleanup task has had the chance to run yet.
|
|
||||||
assertEquals(0, cleanup0_call_count);
|
|
||||||
assertEquals(0, cleanup1_call_count);
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Wait for the two GCs to be executed.
|
|
||||||
await task_1_gc;
|
|
||||||
await task_2_gc;
|
|
||||||
|
|
||||||
let timeout_func = function () {
|
|
||||||
assertEquals(2, cleanup0_call_count);
|
|
||||||
assertEquals(2, cleanup1_call_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Give the cleanup task a chance to run and check it worked correctly.
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// Drop the references to the objects.
|
||||||
|
objects = [];
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// Will schedule both fg0 and fg1 for cleanup.
|
||||||
|
gc();
|
||||||
|
|
||||||
|
// Before the cleanup task has a chance to run, do the same thing again, so both
|
||||||
|
// FinalizationRegistries are (again) scheduled for cleanup. This has to be a IIFE function
|
||||||
|
// (so that we can reliably kill the objects) so we cannot use the same function
|
||||||
|
// as before.
|
||||||
|
(function() {
|
||||||
|
let objects = [];
|
||||||
|
objects[0] = {};
|
||||||
|
objects[1] = {};
|
||||||
|
fg0.register(objects[0], "holdings0-1");
|
||||||
|
fg1.register(objects[1], "holdings1-1");
|
||||||
|
objects = [];
|
||||||
|
})();
|
||||||
|
|
||||||
|
gc();
|
||||||
|
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertEquals(2, cleanup0_call_count);
|
||||||
|
assertEquals(2, cleanup0_holdings_count);
|
||||||
|
assertEquals(2, cleanup1_call_count);
|
||||||
|
assertEquals(2, cleanup1_holdings_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give the cleanup task a chance to run.
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,42 +4,37 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_call_count = 0;
|
||||||
|
let cleanup_holdings_count = 0;
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
++cleanup_holdings_count;
|
||||||
|
++cleanup_call_count;
|
||||||
|
}
|
||||||
|
|
||||||
let cleanup_call_count = 0;
|
let fg1 = new FinalizationRegistry(cleanup);
|
||||||
let cleanup = function (holdings) {
|
let fg2 = new FinalizationRegistry(cleanup);
|
||||||
++cleanup_call_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fg1 = new FinalizationRegistry(cleanup);
|
// Create two objects and register them in FinalizationRegistries. The objects need
|
||||||
let fg2 = new FinalizationRegistry(cleanup);
|
// to be inside a closure so that we can reliably kill them!
|
||||||
|
|
||||||
// Create two objects and register them in FinalizationRegistries. The objects need
|
(function() {
|
||||||
// to be inside a closure so that we can reliably kill them!
|
let object1 = {};
|
||||||
|
fg1.register(object1, "holdings1");
|
||||||
|
|
||||||
(function () {
|
let object2 = {};
|
||||||
let object1 = {};
|
fg2.register(object2, "holdings2");
|
||||||
fg1.register(object1, "holdings1");
|
|
||||||
|
|
||||||
let object2 = {};
|
|
||||||
fg2.register(object2, "holdings2");
|
|
||||||
|
|
||||||
// object1 and object2 go out of scope.
|
|
||||||
})();
|
|
||||||
|
|
||||||
// This GC will discover dirty WeakCells and schedule cleanup.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(0, cleanup_call_count);
|
|
||||||
|
|
||||||
// Assert that the cleanup function was called.
|
|
||||||
let timeout_func = function () {
|
|
||||||
assertEquals(2, cleanup_call_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// object1 and object2 go out of scope.
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// This GC will discover dirty WeakCells and schedule cleanup.
|
||||||
|
gc();
|
||||||
|
assertEquals(0, cleanup_call_count);
|
||||||
|
|
||||||
|
// Assert that the cleanup function was called.
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertEquals(2, cleanup_call_count);
|
||||||
|
assertEquals(2, cleanup_holdings_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,27 +4,20 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let call_count = 0;
|
||||||
|
let reentrant_gc = function(holdings) {
|
||||||
|
gc();
|
||||||
|
call_count++;
|
||||||
|
}
|
||||||
|
|
||||||
let call_count = 0;
|
let fg = new FinalizationRegistry(reentrant_gc);
|
||||||
const reentrant_gc = function (holdings) {
|
|
||||||
gc();
|
|
||||||
call_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fg = new FinalizationRegistry(reentrant_gc);
|
(function() {
|
||||||
|
fg.register({}, 42);
|
||||||
|
})();
|
||||||
|
|
||||||
(function () {
|
gc();
|
||||||
fg.register({}, 42);
|
|
||||||
})();
|
|
||||||
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
setTimeout(function() {
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
assertEquals(1, call_count);
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
}, 0);
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(0, call_count);
|
|
||||||
|
|
||||||
setTimeout(function () { assertEquals(1, call_count); }, 0);
|
|
||||||
|
|
||||||
})();
|
|
||||||
|
@ -4,41 +4,33 @@
|
|||||||
|
|
||||||
// Flags: --stress-compaction --expose-gc
|
// Flags: --stress-compaction --expose-gc
|
||||||
|
|
||||||
(async function () {
|
// Test that the dirty FinalizationRegistries that are enqueued during GC have
|
||||||
|
// their slots correctly recorded by the GC.
|
||||||
|
|
||||||
// Test that the dirty FinalizationRegistries that are enqueued during GC have
|
// 1) Create many JSFinalizationRegistry objects so that they span several pages
|
||||||
// their slots correctly recorded by the GC.
|
// (page size is 256kb).
|
||||||
|
let registries = [];
|
||||||
|
for (let i = 0; i < 1024 * 8; i++) {
|
||||||
|
registries.push(new FinalizationRegistry(() => {}));
|
||||||
|
}
|
||||||
|
|
||||||
// 1) Create many JSFinalizationRegistry objects so that they span several pages
|
// 2) Force two GCs to ensure that JSFinalizatonRegistry objects are tenured.
|
||||||
// (page size is 256kb).
|
gc();
|
||||||
let registries = [];
|
gc();
|
||||||
for (let i = 0; i < 1024 * 8; i++) {
|
|
||||||
registries.push(new FinalizationRegistry(() => { }));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2) Force two GCs to ensure that JSFinalizatonRegistry objects are tenured.
|
|
||||||
// Here and below, we need to invoke GC asynchronously and wait for it to
|
|
||||||
// finish, so that it doesn't need to scan the stack. Otherwise, the objects
|
|
||||||
// may not be reclaimed because of conservative stack scanning and the test
|
|
||||||
// may not work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
// 3) In a function: create a dummy target and register it in all
|
|
||||||
// JSFinalizatonRegistry objects.
|
|
||||||
(function () {
|
|
||||||
let garbage = {};
|
|
||||||
registries.forEach((fr) => {
|
|
||||||
fr.register(garbage, 42);
|
|
||||||
});
|
|
||||||
garbage = null;
|
|
||||||
})();
|
|
||||||
|
|
||||||
// 4) Outside the function where the target is unreachable: force GC to collect
|
|
||||||
// the object.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
// 5) Force another GC to test that the slot was correctly updated.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
|
// 3) In a function: create a dummy target and register it in all
|
||||||
|
// JSFinalizatonRegistry objects.
|
||||||
|
(function() {
|
||||||
|
let garbage = {};
|
||||||
|
registries.forEach((fr) => {
|
||||||
|
fr.register(garbage, 42);
|
||||||
|
});
|
||||||
|
garbage = null;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// 4) Outside the function where the target is unreachable: force GC to collect
|
||||||
|
// the object.
|
||||||
|
gc();
|
||||||
|
|
||||||
|
// 5) Force another GC to test that the slot was correctly updated.
|
||||||
|
gc();
|
||||||
|
@ -4,29 +4,36 @@
|
|||||||
|
|
||||||
// Flags: --harmony-symbol-as-weakmap-key --expose-gc --noincremental-marking
|
// Flags: --harmony-symbol-as-weakmap-key --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
(function TestWeakRefWithSymbolGC() {
|
||||||
|
|
||||||
let weakRef;
|
let weakRef;
|
||||||
(function () {
|
{
|
||||||
const innerKey = Symbol('123');
|
const innerKey = Symbol('123');
|
||||||
weakRef = new WeakRef(innerKey);
|
weakRef = new WeakRef(innerKey);
|
||||||
})();
|
}
|
||||||
|
|
||||||
// Since the WeakRef was created during this turn, it is not cleared by GC.
|
// Since the WeakRef was created during this turn, it is not cleared by GC.
|
||||||
// Here we invoke GC synchronously and, with conservative stack scanning, there is
|
|
||||||
// a chance that the object is not reclaimed now. In any case, the WeakRef should
|
|
||||||
// not be cleared.
|
|
||||||
gc();
|
gc();
|
||||||
|
|
||||||
assertNotEquals(undefined, weakRef.deref());
|
assertNotEquals(undefined, weakRef.deref());
|
||||||
|
// Next task.
|
||||||
// Trigger GC again in next task. Now the WeakRef is cleared.
|
setTimeout(() => {
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
gc();
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
assertEquals(undefined, weakRef.deref());
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
}, 0);
|
||||||
// work as intended.
|
})();
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
(function TestFinalizationRegistryWithSymbolGC() {
|
||||||
assertEquals(undefined, weakRef.deref());
|
let cleanUpCalled = false;
|
||||||
|
const fg = new FinalizationRegistry((target) => {
|
||||||
|
assertEquals('123', target);
|
||||||
|
cleanUpCalled = true;
|
||||||
|
});
|
||||||
|
(function () {
|
||||||
|
const innerKey = Symbol('123');
|
||||||
|
fg.register(innerKey, '123');
|
||||||
|
})();
|
||||||
|
gc();
|
||||||
|
assertFalse(cleanUpCalled);
|
||||||
|
// Check that cleanup callback was called in a follow up task.
|
||||||
|
setTimeout(() => {
|
||||||
|
assertTrue(cleanUpCalled);
|
||||||
|
}, 0);
|
||||||
})();
|
})();
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
// Copyright 2023 the V8 project authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
// Flags: --harmony-symbol-as-weakmap-key --expose-gc --noincremental-marking
|
|
||||||
|
|
||||||
(async function () {
|
|
||||||
|
|
||||||
let cleanUpCalled = false;
|
|
||||||
const fg = new FinalizationRegistry((target) => {
|
|
||||||
assertEquals('123', target);
|
|
||||||
cleanUpCalled = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
const innerKey = Symbol('123');
|
|
||||||
fg.register(innerKey, '123');
|
|
||||||
})();
|
|
||||||
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertFalse(cleanUpCalled);
|
|
||||||
|
|
||||||
// Check that cleanup callback was called in a follow up task.
|
|
||||||
setTimeout(() => { assertTrue(cleanUpCalled); }, 0);
|
|
||||||
|
|
||||||
})();
|
|
@ -14,9 +14,6 @@ let wr2;
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
// Since the WeakRefs were created during this turn, they're not cleared by GC.
|
// Since the WeakRefs were created during this turn, they're not cleared by GC.
|
||||||
// Here and below, we invoke GC synchronously and, with conservative stack
|
|
||||||
// scanning, there is a chance that the object is not reclaimed now. In any
|
|
||||||
// case, the WeakRef should not be cleared.
|
|
||||||
gc();
|
gc();
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
@ -26,29 +23,25 @@ gc();
|
|||||||
|
|
||||||
// New task
|
// New task
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
(function () { wr1.deref(); })();
|
wr1.deref();
|
||||||
o1 = null;
|
o1 = null;
|
||||||
gc(); // deref makes sure we don't clean up wr1
|
gc(); // deref makes sure we don't clean up wr1
|
||||||
(function () { assertNotEquals(undefined, wr1.deref()); })();
|
|
||||||
|
|
||||||
// New task
|
// New task
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
(function () { wr2.deref(); })();
|
wr2.deref();
|
||||||
o2 = null;
|
o2 = null;
|
||||||
gc(); // deref makes sure we don't clean up wr2
|
gc(); // deref makes sure we don't clean up wr2
|
||||||
(function () { assertNotEquals(undefined, wr2.deref()); })();
|
|
||||||
|
|
||||||
// New task
|
// New task
|
||||||
(async function () {
|
setTimeout(function() {
|
||||||
// Trigger GC again to make sure the two WeakRefs are cleared.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
assertEquals(undefined, wr1.deref());
|
assertEquals(undefined, wr1.deref());
|
||||||
assertEquals(undefined, wr2.deref());
|
gc();
|
||||||
})();
|
|
||||||
|
// New task
|
||||||
|
setTimeout(function() {
|
||||||
|
assertEquals(undefined, wr2.deref());
|
||||||
|
}, 0);
|
||||||
|
}, 0);
|
||||||
}, 0);
|
}, 0);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
@ -4,39 +4,34 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_call_count = 0;
|
||||||
|
let cleanup_holdings_count = 0;
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
assertEquals(holdings, undefined);
|
||||||
|
++cleanup_holdings_count;
|
||||||
|
++cleanup_call_count;
|
||||||
|
}
|
||||||
|
|
||||||
let cleanup_call_count = 0;
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
let cleanup = function (holdings) {
|
|
||||||
assertEquals(holdings, undefined);
|
|
||||||
++cleanup_call_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
// Create an object and register it in the FinalizationRegistry. The object needs to be inside
|
||||||
|
// a closure so that we can reliably kill them!
|
||||||
|
|
||||||
// Create an object and register it in the FinalizationRegistry. The object needs to be inside
|
(function() {
|
||||||
// a closure so that we can reliably kill them!
|
let object = {};
|
||||||
|
fg.register(object);
|
||||||
(function () {
|
|
||||||
let object = {};
|
|
||||||
fg.register(object);
|
|
||||||
|
|
||||||
// object goes out of scope.
|
|
||||||
})();
|
|
||||||
|
|
||||||
// This GC will reclaim the target object and schedule cleanup.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(0, cleanup_call_count);
|
|
||||||
|
|
||||||
// Assert that the cleanup function was called.
|
|
||||||
let timeout_func = function () {
|
|
||||||
assertEquals(1, cleanup_call_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// object goes out of scope.
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// This GC will reclaim the target object and schedule cleanup.
|
||||||
|
gc();
|
||||||
|
assertEquals(0, cleanup_call_count);
|
||||||
|
|
||||||
|
// Assert that the cleanup function was called.
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertEquals(1, cleanup_call_count);
|
||||||
|
assertEquals(1, cleanup_holdings_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,46 +4,42 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_call_count = 0;
|
||||||
|
let cleanup_holdings_count = 0;
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
assertEquals("holdings", holdings);
|
||||||
|
++cleanup_holdings_count;
|
||||||
|
++cleanup_call_count;
|
||||||
|
}
|
||||||
|
|
||||||
let cleanup_call_count = 0;
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
let cleanup = function (holdings) {
|
let key = {"k": "this is the key"};
|
||||||
assertEquals("holdings", holdings);
|
// Create an object and register it in the FinalizationRegistry. The object needs
|
||||||
++cleanup_call_count;
|
// to be inside a closure so that we can reliably kill them!
|
||||||
}
|
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
(function() {
|
||||||
let key = { "k": "this is the key" };
|
let object = {};
|
||||||
// Create an object and register it in the FinalizationRegistry. The object needs
|
fg.register(object, "holdings", key);
|
||||||
// to be inside a closure so that we can reliably kill them!
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
let object = {};
|
|
||||||
fg.register(object, "holdings", key);
|
|
||||||
|
|
||||||
// object goes out of scope.
|
|
||||||
})();
|
|
||||||
|
|
||||||
// This GC will reclaim the target object and schedule cleanup.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(0, cleanup_call_count);
|
|
||||||
|
|
||||||
// Assert that the cleanup function was called.
|
|
||||||
let timeout_func = function () {
|
|
||||||
assertEquals(1, cleanup_call_count);
|
|
||||||
|
|
||||||
// Unregister an already cleaned-up weak reference.
|
|
||||||
let success = fg.unregister(key);
|
|
||||||
assertFalse(success);
|
|
||||||
|
|
||||||
// Assert that it didn't do anything.
|
|
||||||
setTimeout(() => { assertEquals(1, cleanup_call_count); }, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// object goes out of scope.
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// This GC will reclaim the target object and schedule cleanup.
|
||||||
|
gc();
|
||||||
|
assertEquals(0, cleanup_call_count);
|
||||||
|
|
||||||
|
// Assert that the cleanup function was called.
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertEquals(1, cleanup_call_count);
|
||||||
|
assertEquals(1, cleanup_holdings_count);
|
||||||
|
|
||||||
|
// Unregister an already cleaned-up weak reference.
|
||||||
|
let success = fg.unregister(key);
|
||||||
|
assertFalse(success);
|
||||||
|
|
||||||
|
// Assert that it didn't do anything.
|
||||||
|
setTimeout(() => { assertEquals(1, cleanup_call_count); }, 0);
|
||||||
|
setTimeout(() => { assertEquals(1, cleanup_holdings_count); }, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,42 +4,34 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_call_count = 0;
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
++cleanup_call_count;
|
||||||
|
}
|
||||||
|
|
||||||
let cleanup_call_count = 0;
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
let cleanup = function (holdings) {
|
let key = {"k": "this is the key"};
|
||||||
++cleanup_call_count;
|
// Create an object and register it in the FinalizationRegistry. The object needs
|
||||||
}
|
// to be inside a closure so that we can reliably kill them!
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
(function() {
|
||||||
let key = { "k": "this is the key" };
|
let object = {};
|
||||||
// Create an object and register it in the FinalizationRegistry. The object needs
|
fg.register(object, "my holdings", key);
|
||||||
// to be inside a closure so that we can reliably kill them!
|
|
||||||
|
|
||||||
(function () {
|
// Clear the WeakCell before the GC has a chance to discover it.
|
||||||
let object = {};
|
let success = fg.unregister(key);
|
||||||
fg.register(object, "my holdings", key);
|
assertTrue(success);
|
||||||
|
|
||||||
// Clear the WeakCell before the GC has a chance to discover it.
|
|
||||||
let success = fg.unregister(key);
|
|
||||||
assertTrue(success);
|
|
||||||
|
|
||||||
// object goes out of scope.
|
|
||||||
})();
|
|
||||||
|
|
||||||
// This GC will reclaim the target object.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(0, cleanup_call_count);
|
|
||||||
|
|
||||||
// Assert that the cleanup function won't be called, since we called unregister.
|
|
||||||
let timeout_func = function () {
|
|
||||||
assertEquals(0, cleanup_call_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// object goes out of scope.
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// This GC will reclaim the target object.
|
||||||
|
gc();
|
||||||
|
assertEquals(0, cleanup_call_count);
|
||||||
|
|
||||||
|
// Assert that the cleanup function won't be called, since we called unregister.
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertEquals(0, cleanup_call_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,47 +4,39 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_call_count = 0;
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
++cleanup_call_count;
|
||||||
|
}
|
||||||
|
|
||||||
let cleanup_call_count = 0;
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
let cleanup = function (holdings) {
|
let key = {"k": "this is the key"};
|
||||||
++cleanup_call_count;
|
// Create an object and register it in the FinalizationRegistry. The object needs
|
||||||
}
|
// to be inside a closure so that we can reliably kill them!
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
(function() {
|
||||||
let key = { "k": "this is the key" };
|
let object = {};
|
||||||
// Create an object and register it in the FinalizationRegistry. The object needs
|
fg.register(object, "holdings", key);
|
||||||
// to be inside a closure so that we can reliably kill them!
|
|
||||||
|
|
||||||
(function () {
|
// Unregister before the GC has a chance to discover the object.
|
||||||
let object = {};
|
let success = fg.unregister(key);
|
||||||
fg.register(object, "holdings", key);
|
assertTrue(success);
|
||||||
|
|
||||||
// Unregister before the GC has a chance to discover the object.
|
// Call unregister again (just to assert we handle this gracefully).
|
||||||
let success = fg.unregister(key);
|
success = fg.unregister(key);
|
||||||
assertTrue(success);
|
assertFalse(success);
|
||||||
|
|
||||||
// Call unregister again (just to assert we handle this gracefully).
|
|
||||||
success = fg.unregister(key);
|
|
||||||
assertFalse(success);
|
|
||||||
|
|
||||||
// object goes out of scope.
|
|
||||||
})();
|
|
||||||
|
|
||||||
// This GC will reclaim the target object.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(0, cleanup_call_count);
|
|
||||||
|
|
||||||
// Assert that the cleanup function won't be called, since the weak reference
|
|
||||||
// was unregistered.
|
|
||||||
let timeout_func = function () {
|
|
||||||
assertEquals(0, cleanup_call_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// object goes out of scope.
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// This GC will reclaim the target object.
|
||||||
|
gc();
|
||||||
|
assertEquals(0, cleanup_call_count);
|
||||||
|
|
||||||
|
// Assert that the cleanup function won't be called, since the weak reference
|
||||||
|
// was unregistered.
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertEquals(0, cleanup_call_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,42 +4,37 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_call_count = 0;
|
||||||
|
let cleanup_holdings_count = 0;
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
assertEquals(holdings, "holdings");
|
||||||
|
let success = fg.unregister(key);
|
||||||
|
assertFalse(success);
|
||||||
|
|
||||||
let cleanup_call_count = 0;
|
++cleanup_holdings_count;
|
||||||
let cleanup = function (holdings) {
|
++cleanup_call_count;
|
||||||
assertEquals(holdings, "holdings");
|
}
|
||||||
let success = fg.unregister(key);
|
|
||||||
assertFalse(success);
|
|
||||||
|
|
||||||
++cleanup_call_count;
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
}
|
// Create an object and register it in the FinalizationRegistry. The object needs to be inside
|
||||||
|
// a closure so that we can reliably kill them!
|
||||||
|
let key = {"k": "this is the key"};
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
(function() {
|
||||||
// Create an object and register it in the FinalizationRegistry. The object needs to be inside
|
let object = {};
|
||||||
// a closure so that we can reliably kill them!
|
fg.register(object, "holdings", key);
|
||||||
let key = { "k": "this is the key" };
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
let object = {};
|
|
||||||
fg.register(object, "holdings", key);
|
|
||||||
|
|
||||||
// object goes out of scope.
|
|
||||||
})();
|
|
||||||
|
|
||||||
// This GC will discover dirty WeakCells and schedule cleanup.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(0, cleanup_call_count);
|
|
||||||
|
|
||||||
// Assert that the cleanup function was called.
|
|
||||||
let timeout_func = function () {
|
|
||||||
assertEquals(1, cleanup_call_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// object goes out of scope.
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// This GC will discover dirty WeakCells and schedule cleanup.
|
||||||
|
gc();
|
||||||
|
assertEquals(0, cleanup_call_count);
|
||||||
|
|
||||||
|
// Assert that the cleanup function was called.
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertEquals(1, cleanup_call_count);
|
||||||
|
assertEquals(1, cleanup_holdings_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,50 +4,45 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_call_count = 0;
|
||||||
|
let cleanup_holdings_count = 0;
|
||||||
let cleanup_call_count = 0;
|
let cleanup = function(holdings) {
|
||||||
let cleanup = function(holdings) {
|
// See which target we're cleaning up and unregister the other one.
|
||||||
// See which target we're cleaning up and unregister the other one.
|
if (holdings == 1) {
|
||||||
if (holdings == 1) {
|
let success = fg.unregister(key2);
|
||||||
let success = fg.unregister(key2);
|
assertTrue(success);
|
||||||
assertTrue(success);
|
} else {
|
||||||
} else {
|
assertSame(holdings, 2);
|
||||||
assertSame(holdings, 2);
|
let success = fg.unregister(key1);
|
||||||
let success = fg.unregister(key1);
|
assertTrue(success);
|
||||||
assertTrue(success);
|
|
||||||
}
|
|
||||||
++cleanup_call_count;
|
|
||||||
}
|
}
|
||||||
|
++cleanup_holdings_count;
|
||||||
|
++cleanup_call_count;
|
||||||
|
}
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
let key1 = {"k": "first key"};
|
let key1 = {"k": "first key"};
|
||||||
let key2 = {"k": "second key"};
|
let key2 = {"k": "second key"};
|
||||||
// Create two objects and register them in the FinalizationRegistry. The objects
|
// Create two objects and register them in the FinalizationRegistry. The objects
|
||||||
// need to be inside a closure so that we can reliably kill them!
|
// need to be inside a closure so that we can reliably kill them!
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
let object1 = {};
|
let object1 = {};
|
||||||
fg.register(object1, 1, key1);
|
fg.register(object1, 1, key1);
|
||||||
let object2 = {};
|
let object2 = {};
|
||||||
fg.register(object2, 2, key2);
|
fg.register(object2, 2, key2);
|
||||||
|
|
||||||
// object1 and object2 go out of scope.
|
|
||||||
})();
|
|
||||||
|
|
||||||
// This GC will reclaim target objects and schedule cleanup.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(0, cleanup_call_count);
|
|
||||||
|
|
||||||
// Assert that the cleanup function was called and cleaned up one holdings (but not the other one).
|
|
||||||
let timeout_func = function() {
|
|
||||||
assertEquals(1, cleanup_call_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// object1 and object2 go out of scope.
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// This GC will reclaim target objects and schedule cleanup.
|
||||||
|
gc();
|
||||||
|
assertEquals(0, cleanup_call_count);
|
||||||
|
|
||||||
|
// Assert that the cleanup function was called and cleaned up one holdings (but not the other one).
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertEquals(1, cleanup_call_count);
|
||||||
|
assertEquals(1, cleanup_holdings_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,48 +4,44 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_call_count = 0;
|
||||||
|
let cleanup_holdings_count = 0;
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
assertEquals(holdings, "holdings");
|
||||||
|
|
||||||
let cleanup_call_count = 0;
|
// There's one more object with the same key that we haven't
|
||||||
let cleanup = function(holdings) {
|
// cleaned up yet so we should be able to unregister the
|
||||||
assertEquals(holdings, "holdings");
|
// callback for that one.
|
||||||
|
let success = fg.unregister(key);
|
||||||
|
|
||||||
// There's one more object with the same key that we haven't
|
assertTrue(success);
|
||||||
// cleaned up yet so we should be able to unregister the
|
|
||||||
// callback for that one.
|
|
||||||
let success = fg.unregister(key);
|
|
||||||
assertTrue(success);
|
|
||||||
|
|
||||||
++cleanup_call_count;
|
++cleanup_holdings_count;
|
||||||
}
|
++cleanup_call_count;
|
||||||
|
}
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
// Create an object and register it in the FinalizationRegistry. The object needs to be inside
|
// Create an object and register it in the FinalizationRegistry. The object needs to be inside
|
||||||
// a closure so that we can reliably kill them!
|
// a closure so that we can reliably kill them!
|
||||||
let key = {"k": "this is the key"};
|
let key = {"k": "this is the key"};
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
let object = {};
|
let object = {};
|
||||||
let object2 = {};
|
let object2 = {};
|
||||||
fg.register(object, "holdings", key);
|
fg.register(object, "holdings", key);
|
||||||
fg.register(object2, "holdings", key);
|
fg.register(object2, "holdings", key);
|
||||||
|
|
||||||
// object goes out of scope.
|
|
||||||
})();
|
|
||||||
|
|
||||||
// This GC will discover dirty WeakCells and schedule cleanup.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(0, cleanup_call_count);
|
|
||||||
|
|
||||||
// Assert that the cleanup function was called.
|
|
||||||
let timeout_func = function() {
|
|
||||||
assertEquals(1, cleanup_call_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// object goes out of scope.
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// This GC will discover dirty WeakCells and schedule cleanup.
|
||||||
|
gc();
|
||||||
|
assertEquals(0, cleanup_call_count);
|
||||||
|
|
||||||
|
// Assert that the cleanup function was called.
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertEquals(1, cleanup_call_count);
|
||||||
|
assertEquals(1, cleanup_holdings_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,51 +4,46 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_call_count = 0;
|
||||||
|
let cleanup_holdings_count = 0;
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
assertEquals("holdings2", holdings);
|
||||||
|
++cleanup_holdings_count;
|
||||||
|
++cleanup_call_count;
|
||||||
|
}
|
||||||
|
|
||||||
let cleanup_call_count = 0;
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
let cleanup = function(holdings) {
|
let key1 = {"k": "key1"};
|
||||||
assertEquals("holdings2", holdings);
|
let key2 = {"k": "key2"};
|
||||||
++cleanup_call_count;
|
// Create three objects and register them in the FinalizationRegistry. The objects
|
||||||
}
|
// need to be inside a closure so that we can reliably kill them!
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
(function() {
|
||||||
let key1 = {"k": "key1"};
|
let object1a = {};
|
||||||
let key2 = {"k": "key2"};
|
fg.register(object1a, "holdings1a", key1);
|
||||||
// Create three objects and register them in the FinalizationRegistry. The objects
|
|
||||||
// need to be inside a closure so that we can reliably kill them!
|
|
||||||
|
|
||||||
(function() {
|
let object1b = {};
|
||||||
let object1a = {};
|
fg.register(object1b, "holdings1b", key1);
|
||||||
fg.register(object1a, "holdings1a", key1);
|
|
||||||
|
|
||||||
let object1b = {};
|
let object2 = {};
|
||||||
fg.register(object1b, "holdings1b", key1);
|
fg.register(object2, "holdings2", key2);
|
||||||
|
|
||||||
let object2 = {};
|
// Unregister before the GC has a chance to discover the objects.
|
||||||
fg.register(object2, "holdings2", key2);
|
let success = fg.unregister(key1);
|
||||||
|
assertTrue(success);
|
||||||
// Unregister before the GC has a chance to discover the objects.
|
|
||||||
let success = fg.unregister(key1);
|
|
||||||
assertTrue(success);
|
|
||||||
|
|
||||||
// objects go out of scope.
|
|
||||||
})();
|
|
||||||
|
|
||||||
// This GC will reclaim the target objects.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(0, cleanup_call_count);
|
|
||||||
|
|
||||||
// Assert that the cleanup function will be called only for the reference which
|
|
||||||
// was not unregistered.
|
|
||||||
let timeout_func = function() {
|
|
||||||
assertEquals(1, cleanup_call_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// objects go out of scope.
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// This GC will reclaim the target objects.
|
||||||
|
gc();
|
||||||
|
assertEquals(0, cleanup_call_count);
|
||||||
|
|
||||||
|
// Assert that the cleanup function will be called only for the reference which
|
||||||
|
// was not unregistered.
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertEquals(1, cleanup_call_count);
|
||||||
|
assertEquals(1, cleanup_holdings_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,42 +4,34 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_call_count = 0;
|
||||||
|
let cleanup = function(holdings) {
|
||||||
|
++cleanup_call_count;
|
||||||
|
}
|
||||||
|
|
||||||
let cleanup_call_count = 0;
|
let key = {"k": "this is my key"};
|
||||||
let cleanup = function(holdings) {
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
++cleanup_call_count;
|
// Create an object and register it in the FinalizationRegistry. The object needs to be inside
|
||||||
}
|
// a closure so that we can reliably kill them!
|
||||||
|
|
||||||
let key = {"k": "this is my key"};
|
(function() {
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
let object = {};
|
||||||
// Create an object and register it in the FinalizationRegistry. The object needs to be inside
|
fg.register(object, {}, key);
|
||||||
// a closure so that we can reliably kill them!
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
let object = {};
|
|
||||||
fg.register(object, {}, key);
|
|
||||||
|
|
||||||
// object goes out of scope.
|
|
||||||
})();
|
|
||||||
|
|
||||||
// This GC will discover dirty WeakCells and schedule cleanup.
|
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(0, cleanup_call_count);
|
|
||||||
|
|
||||||
// Unregister the object from the FinalizationRegistry before cleanup has ran.
|
|
||||||
let success = fg.unregister(key);
|
|
||||||
assertTrue(success);
|
|
||||||
|
|
||||||
// Assert that the cleanup function won't be called.
|
|
||||||
let timeout_func = function() {
|
|
||||||
assertEquals(0, cleanup_call_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
|
||||||
|
|
||||||
|
// object goes out of scope.
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// This GC will discover dirty WeakCells and schedule cleanup.
|
||||||
|
gc();
|
||||||
|
assertEquals(0, cleanup_call_count);
|
||||||
|
|
||||||
|
// Unregister the object from the FinalizationRegistry before cleanup has ran.
|
||||||
|
let success = fg.unregister(key);
|
||||||
|
assertTrue(success);
|
||||||
|
|
||||||
|
// Assert that the cleanup function won't be called.
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertEquals(0, cleanup_call_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,44 +4,36 @@
|
|||||||
|
|
||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
(async function () {
|
let cleanup_called = false;
|
||||||
|
let cleanup = function(holdings_arg) {
|
||||||
let cleanup_called = false;
|
|
||||||
let cleanup = function(holdings_arg) {
|
|
||||||
assertFalse(cleanup_called);
|
|
||||||
assertEquals(holdings_arg, holdings);
|
|
||||||
cleanup_called = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fg = new FinalizationRegistry(cleanup);
|
|
||||||
let o = {};
|
|
||||||
let holdings = {'h': 55};
|
|
||||||
|
|
||||||
// Ignition holds references to objects in temporary registers. These will be
|
|
||||||
// released when the function exits. So only access o inside a function to
|
|
||||||
// prevent any references to objects in temporary registers when a gc is
|
|
||||||
// triggered.
|
|
||||||
(() => { fg.register(o, holdings); })()
|
|
||||||
|
|
||||||
// Here and below, we need to invoke GC asynchronously and wait for it to
|
|
||||||
// finish, so that it doesn't need to scan the stack. Otherwise, the objects
|
|
||||||
// may not be reclaimed because of conservative stack scanning and the test
|
|
||||||
// may not work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertFalse(cleanup_called);
|
assertFalse(cleanup_called);
|
||||||
|
assertEquals(holdings_arg, holdings);
|
||||||
|
cleanup_called = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Drop the last reference to o.
|
let fg = new FinalizationRegistry(cleanup);
|
||||||
(() => { o = null; })()
|
let o = {};
|
||||||
|
let holdings = {'h': 55};
|
||||||
|
|
||||||
// GC will clear the WeakCell; the cleanup function will be called the next time
|
// Ignition holds references to objects in temporary registers. These will be
|
||||||
// we enter the event loop.
|
// released when the function exits. So only access o inside a function to
|
||||||
await gc({ type: 'major', execution: 'async' });
|
// prevent any references to objects in temporary registers when a gc is
|
||||||
assertFalse(cleanup_called);
|
// triggered.
|
||||||
|
(() => { fg.register(o, holdings); })()
|
||||||
|
|
||||||
let timeout_func = function() {
|
gc();
|
||||||
assertTrue(cleanup_called);
|
assertFalse(cleanup_called);
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(timeout_func, 0);
|
// Drop the last reference to o.
|
||||||
|
(() => { o = null; })()
|
||||||
|
|
||||||
})();
|
// GC will clear the WeakCell; the cleanup function will be called the next time
|
||||||
|
// we enter the event loop.
|
||||||
|
gc();
|
||||||
|
assertFalse(cleanup_called);
|
||||||
|
|
||||||
|
let timeout_func = function() {
|
||||||
|
assertTrue(cleanup_called);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(timeout_func, 0);
|
||||||
|
@ -4,30 +4,19 @@
|
|||||||
|
|
||||||
// Flags: --harmony-weak-refs-with-cleanup-some --expose-gc --noincremental-marking
|
// Flags: --harmony-weak-refs-with-cleanup-some --expose-gc --noincremental-marking
|
||||||
|
|
||||||
const cleanup = function (holdings) { globalThis.FRRan = true; };
|
var FR = new FinalizationRegistry (function (holdings) { globalThis.FRRan = true; });
|
||||||
const FR = new FinalizationRegistry(cleanup);
|
{
|
||||||
|
|
||||||
(function () {
|
|
||||||
let obj = {};
|
let obj = {};
|
||||||
// obj is its own unregister token and becomes unreachable after this
|
// obj is its own unregister token and becomes unreachable after this
|
||||||
// block. If the unregister token is held strongly this test will not
|
// block. If the unregister token is held strongly this test will not
|
||||||
// terminate.
|
// terminate.
|
||||||
FR.register(obj, 42, obj);
|
FR.register(obj, 42, obj);
|
||||||
})();
|
}
|
||||||
|
|
||||||
function tryAgain() {
|
function tryAgain() {
|
||||||
(async function () {
|
gc();
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
if (globalThis.FRRan || FR.cleanupSome()) {
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
return;
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
}
|
||||||
// work as intended.
|
setTimeout(tryAgain, 0);
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
if (globalThis.FRRan || FR.cleanupSome()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(tryAgain, 0);
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
tryAgain();
|
tryAgain();
|
||||||
|
@ -5,29 +5,22 @@
|
|||||||
// Flags: --expose-gc --noincremental-marking
|
// Flags: --expose-gc --noincremental-marking
|
||||||
|
|
||||||
let wr;
|
let wr;
|
||||||
(function () {
|
(function() {
|
||||||
let o = {};
|
let o = {};
|
||||||
wr = new WeakRef(o);
|
wr = new WeakRef(o);
|
||||||
// Don't deref here, we want to test that the creation is enough to keep the
|
// Don't deref here, we want to test that the creation is enough to keep the
|
||||||
// WeakRef alive until the end of the turn.
|
// WeakRef alive until the end of the turn.
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// Here we invoke GC synchronously and, with conservative stack scanning,
|
|
||||||
// there is a chance that the object is not reclaimed now. In any case,
|
|
||||||
// the WeakRef should not be cleared.
|
|
||||||
gc();
|
gc();
|
||||||
|
|
||||||
// Since the WeakRef was created during this turn, it is not cleared by GC.
|
// Since the WeakRef was created during this turn, it is not cleared by GC.
|
||||||
assertNotEquals(undefined, wr.deref());
|
(function() {
|
||||||
|
assertNotEquals(undefined, wr.deref());
|
||||||
|
})();
|
||||||
|
|
||||||
// Next task.
|
// Next task.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
(async function () {
|
gc();
|
||||||
// Trigger GC again to make sure the two WeakRefs are cleared.
|
assertEquals(undefined, wr.deref());
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
assertEquals(undefined, wr.deref());
|
|
||||||
})();
|
|
||||||
}, 0);
|
}, 0);
|
||||||
|
@ -6,43 +6,40 @@
|
|||||||
|
|
||||||
let wr;
|
let wr;
|
||||||
let wr_control; // control WeakRef for testing what happens without deref
|
let wr_control; // control WeakRef for testing what happens without deref
|
||||||
(function () {
|
(function() {
|
||||||
let o1 = {};
|
let o1 = {};
|
||||||
wr = new WeakRef(o1);
|
wr = new WeakRef(o1);
|
||||||
let o2 = {};
|
let o2 = {};
|
||||||
wr_control = new WeakRef(o2);
|
wr_control = new WeakRef(o2);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
let strong = { a: wr.deref(), b: wr_control.deref() };
|
let strong = {a: wr.deref(), b: wr_control.deref()};
|
||||||
|
|
||||||
// Here and below, we invoke GC synchronously and, with conservative stack
|
|
||||||
// scanning, there is a chance that the object is not reclaimed now. In any
|
|
||||||
// case, the WeakRefs should not be cleared.
|
|
||||||
gc();
|
gc();
|
||||||
|
|
||||||
// Next task.
|
// Next task.
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
// Call deref inside a closure, trying to avoid accidentally storing a strong
|
// Call deref inside a closure, trying to avoid accidentally storing a strong
|
||||||
// reference into the object in the stack frame.
|
// reference into the object in the stack frame.
|
||||||
(function () { wr.deref(); })();
|
(function() {
|
||||||
|
wr.deref();
|
||||||
|
})();
|
||||||
|
|
||||||
strong = null;
|
strong = null;
|
||||||
|
|
||||||
// This GC should clear wr_control (modulo CSS), since nothing was keeping it
|
// This GC will clear wr_control.
|
||||||
// alive, but it should not clear wr.
|
|
||||||
gc();
|
gc();
|
||||||
(function () { assertNotEquals(undefined, wr.deref()); })();
|
|
||||||
|
|
||||||
// Next task.
|
(function() {
|
||||||
(async function () {
|
assertNotEquals(undefined, wr.deref());
|
||||||
// Trigger GC again to make sure the two WeakRefs are cleared.
|
// Now the control WeakRef got cleared, since nothing was keeping it alive.
|
||||||
// We need to invoke GC asynchronously and wait for it to finish, so that
|
|
||||||
// it doesn't need to scan the stack. Otherwise, the objects may not be
|
|
||||||
// reclaimed because of conservative stack scanning and the test may not
|
|
||||||
// work as intended.
|
|
||||||
await gc({ type: 'major', execution: 'async' });
|
|
||||||
|
|
||||||
assertEquals(undefined, wr.deref());
|
|
||||||
assertEquals(undefined, wr_control.deref());
|
assertEquals(undefined, wr_control.deref());
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// Next task.
|
||||||
|
setTimeout(function() {
|
||||||
|
gc();
|
||||||
|
|
||||||
|
assertEquals(undefined, wr.deref());
|
||||||
|
}, 0);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
Loading…
Reference in New Issue
Block a user