Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

View File

@ -0,0 +1,145 @@
// Copyright 2018 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.
(function TestConstructFinalizationRegistry() {
let fg = new FinalizationRegistry(() => {});
assertEquals(fg.toString(), "[object FinalizationRegistry]");
assertNotSame(fg.__proto__, Object.prototype);
assertSame(fg.__proto__.__proto__, Object.prototype);
})();
(function TestFinalizationRegistryConstructorCallAsFunction() {
let caught = false;
let message = "";
try {
let f = FinalizationRegistry(() => {});
} catch (e) {
message = e.message;
caught = true;
} finally {
assertTrue(caught);
assertEquals(message, "Constructor FinalizationRegistry requires 'new'");
}
})();
(function TestConstructFinalizationRegistryCleanupNotCallable() {
let message = "FinalizationRegistry: cleanup must be callable";
assertThrows(() => { let fg = new FinalizationRegistry(); }, TypeError, message);
assertThrows(() => { let fg = new FinalizationRegistry(1); }, TypeError, message);
assertThrows(() => { let fg = new FinalizationRegistry(null); }, TypeError, message);
})();
(function TestConstructFinalizationRegistryWithCallableProxyAsCleanup() {
let handler = {};
let obj = () => {};
let proxy = new Proxy(obj, handler);
let fg = new FinalizationRegistry(proxy);
})();
(function TestConstructFinalizationRegistryWithNonCallableProxyAsCleanup() {
let message = "FinalizationRegistry: cleanup must be callable";
let handler = {};
let obj = {};
let proxy = new Proxy(obj, handler);
assertThrows(() => { let fg = new FinalizationRegistry(proxy); }, TypeError, message);
})();
(function TestRegisterWithNonObjectTarget() {
let fg = new FinalizationRegistry(() => {});
let message = "FinalizationRegistry.prototype.register: invalid target";
assertThrows(() => fg.register(1, "holdings"), TypeError, message);
assertThrows(() => fg.register(false, "holdings"), TypeError, message);
assertThrows(() => fg.register("foo", "holdings"), TypeError, message);
assertThrows(() => fg.register(null, "holdings"), TypeError, message);
assertThrows(() => fg.register(undefined, "holdings"), TypeError, message);
})();
(function TestRegisterWithProxy() {
let handler = {};
let obj = {};
let proxy = new Proxy(obj, handler);
let fg = new FinalizationRegistry(() => {});
fg.register(proxy);
})();
(function TestRegisterTargetAndHoldingsSameValue() {
let fg = new FinalizationRegistry(() => {});
let obj = {a: 1};
// SameValue(target, holdings) not ok
assertThrows(() => fg.register(obj, obj), TypeError,
"FinalizationRegistry.prototype.register: target and holdings must not be same");
let holdings = {a: 1};
fg.register(obj, holdings);
})();
(function TestRegisterWithoutFinalizationRegistry() {
assertThrows(() => FinalizationRegistry.prototype.register.call({}, {}, "holdings"), TypeError);
// Does not throw:
let fg = new FinalizationRegistry(() => {});
FinalizationRegistry.prototype.register.call(fg, {}, "holdings");
})();
(function TestUnregisterWithNonExistentKey() {
let fg = new FinalizationRegistry(() => {});
let success = fg.unregister({"k": "whatever"});
assertFalse(success);
})();
(function TestUnregisterWithNonFinalizationRegistry() {
assertThrows(() => FinalizationRegistry.prototype.unregister.call({}, {}),
TypeError);
})();
(function TestUnregisterWithNonObjectUnregisterToken() {
let fg = new FinalizationRegistry(() => {});
assertThrows(() => fg.unregister(1), TypeError);
assertThrows(() => fg.unregister(1n), TypeError);
assertThrows(() => fg.unregister('one'), TypeError);
assertThrows(() => fg.unregister(true), TypeError);
assertThrows(() => fg.unregister(false), TypeError);
assertThrows(() => fg.unregister(undefined), TypeError);
assertThrows(() => fg.unregister(null), TypeError);
})();
(function TestWeakRefConstructor() {
let wr = new WeakRef({});
assertEquals(wr.toString(), "[object WeakRef]");
assertNotSame(wr.__proto__, Object.prototype);
let deref_desc = Object.getOwnPropertyDescriptor(wr.__proto__, "deref");
assertEquals(true, deref_desc.configurable);
assertEquals(false, deref_desc.enumerable);
assertEquals("function", typeof deref_desc.value);
})();
(function TestWeakRefConstructorWithNonObject() {
let message = "WeakRef: invalid target";
assertThrows(() => new WeakRef(), TypeError, message);
assertThrows(() => new WeakRef(1), TypeError, message);
assertThrows(() => new WeakRef(false), TypeError, message);
assertThrows(() => new WeakRef("foo"), TypeError, message);
assertThrows(() => new WeakRef(null), TypeError, message);
assertThrows(() => new WeakRef(undefined), TypeError, message);
})();
(function TestWeakRefConstructorCallAsFunction() {
let caught = false;
let message = "";
try {
let f = WeakRef({});
} catch (e) {
message = e.message;
caught = true;
} finally {
assertTrue(caught);
assertEquals(message, "Constructor WeakRef requires 'new'");
}
})();
(function TestWeakRefWithProxy() {
let handler = {};
let obj = {};
let proxy = new Proxy(obj, handler);
let wr = new WeakRef(proxy);
})();

View File

@ -0,0 +1,39 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
(async function () {
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 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!
(function () {
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);
})();

View File

@ -0,0 +1,56 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
// This test asserts that the cleanup function call, scheduled by GC, is
// not a microtask but a normal task.
(async function () {
let microtaskInvoked = false;
const microtask = () => {
assertFalse(cleanedUp);
assertFalse(microtaskInvoked);
microtaskInvoked = true;
};
let cleanedUp = false;
const cleanup = (holdings) => {
assertFalse(cleanedUp);
assertTrue(microtaskInvoked);
cleanedUp = true;
};
const fg = new FinalizationRegistry(cleanup);
(function() {
// Use a closure here to avoid other references to object which might keep
// it alive (e.g., stack frames pointing to it).
const object = {};
fg.register(object, {});
})();
// The GC will schedule the cleanup as a regular task.
// 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(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);
})();

View File

@ -0,0 +1,69 @@
// Copyright 2019 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: --expose-gc --noincremental-marking
(async function () {
const r = Realm.create();
const FG = Realm.eval(r, "FinalizationRegistry");
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);
})();

View File

@ -0,0 +1,42 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
(async function () {
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 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;
(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);
})();

View File

@ -0,0 +1,59 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
(async function () {
let cleanup_called = 0;
let holdings_list = [];
let cleanup = function (holdings) {
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);
})();

View File

@ -0,0 +1,11 @@
// Copyright 2020 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.
// A newly created WeakRef is kept alive until the end of the next microtask
// checkpoint. V8 asserts that the kept objects list is cleared at the end of
// microtask checkpoints when the microtask policy is auto. Test that d8, which
// uses the auto policy, upholds the assert when manually quitting.
let obj = {};
let wr = new WeakRef(obj);
testRunner.quit();

View File

@ -0,0 +1,49 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
(async function () {
let cleanup_called = false;
const cleanup = function(holdings) {
assertFalse(cleanup_called);
assertEquals("holdings", holdings);
cleanup_called = true;
}
const fg = new FinalizationRegistry(cleanup);
let weak_ref;
(function() {
const o = {};
weak_ref = new WeakRef(o);
fg.register(o, "holdings");
})();
// Since the WeakRef was created during this turn, it is not cleared by GC. The
// pointer inside the FinalizationRegistry is not cleared either, since the WeakRef
// 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();
assertNotEquals(undefined, weak_ref.deref());
assertFalse(cleanup_called);
// Trigger GC in next task. Now the WeakRef is cleared but the cleanup has
// not been called yet.
// 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, weak_ref.deref());
assertFalse(cleanup_called);
// Check that the cleanup callback was called in a follow up task.
setTimeout(() => { assertTrue(cleanup_called); }, 0);
})();

View File

@ -0,0 +1,52 @@
// Copyright 2021 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: --expose-gc --noincremental-marking --no-concurrent-inlining
(async function () {
let cleanup_called = false;
function cleanup(holdings) {
cleanup_called = true;
};
let cleanup_called_2 = false;
function cleanup2(holdings) {
cleanup_called_2 = true;
};
const fg = new FinalizationRegistry(cleanup);
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);
})();
// Wait for the two GC tasks to be executed.
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);
})();

View File

@ -0,0 +1,41 @@
// Copyright 2020 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: --expose-gc --noincremental-marking --no-concurrent-recompilation
(async function () {
let cleanup_called = false;
function cleanup(holdings) {
cleanup_called = true;
};
let task_1_gc = (async function () {
const fg = new FinalizationRegistry(cleanup);
(function () {
let x = {};
fg.register(x, "holdings");
x = null;
})();
// Schedule fg for cleanup.
await gc({ type: 'major', execution: 'async' });
assertFalse(cleanup_called);
})();
// Schedule a task to collect fg, which should result in cleanup not called.
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);
})();

View File

@ -0,0 +1,51 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
(async function () {
let cleanup_called = false;
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);
// 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;
await gc({ type: 'major', execution: 'async' });
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);
})();

View File

@ -0,0 +1,82 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
// Flags: --no-stress-flush-code
(async function () {
let cleanup0_call_count = 0;
let cleanup1_call_count = 0;
let cleanup0 = function (holdings) {
++cleanup0_call_count;
}
let cleanup1 = function (holdings) {
++cleanup1_call_count;
}
let fg0 = new FinalizationRegistry(cleanup0);
let fg1 = new FinalizationRegistry(cleanup1);
// Register 1 weak reference for each FinalizationRegistry and kill the
// objects they point to.
(function () {
// The objects need to be inside a closure so that we can reliably kill
// them.
let objects = [];
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.
// 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' });
// 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;
// Wait two ticks, so that the finalization registry cleanup has an
// opportunity to both run and re-post itself.
await new Promise(resolve=>setTimeout(resolve, 0));
await new Promise(resolve=>setTimeout(resolve, 0));
assertEquals(2, cleanup0_call_count);
assertEquals(2, cleanup1_call_count);
})();

View File

@ -0,0 +1,45 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
(async function () {
let cleanup_call_count = 0;
let cleanup = function (holdings) {
++cleanup_call_count;
}
let fg1 = new FinalizationRegistry(cleanup);
let fg2 = new FinalizationRegistry(cleanup);
// Create two objects and register them in FinalizationRegistries. The objects need
// to be inside a closure so that we can reliably kill them!
(function () {
let object1 = {};
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);
// Wait two ticks, so that the finalization registry cleanup has an
// opportunity to both run and re-post itself.
await new Promise(resolve=>setTimeout(resolve, 0));
await new Promise(resolve=>setTimeout(resolve, 0));
// Assert that the cleanup function was called.
assertEquals(2, cleanup_call_count);
})();

View File

@ -0,0 +1,30 @@
// Copyright 2020 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: --expose-gc --noincremental-marking
(async function () {
let call_count = 0;
const reentrant_gc = function (holdings) {
gc();
call_count++;
}
const fg = new FinalizationRegistry(reentrant_gc);
(function () {
fg.register({}, 42);
})();
// 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, call_count);
setTimeout(function () { assertEquals(1, call_count); }, 0);
})();

View File

@ -0,0 +1,44 @@
// Copyright 2020 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: --stress-compaction --expose-gc
(async function () {
// Test that the dirty FinalizationRegistries that are enqueued during GC have
// their slots correctly recorded by the GC.
// 1) Create many JSFinalizationRegistry objects so that they span several pages
// (page size is 256kb).
let registries = [];
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' });
})();

View File

@ -0,0 +1,32 @@
// Copyright 2022 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: --expose-gc --noincremental-marking
(async function () {
let weakRef;
(function () {
const innerKey = Symbol('123');
weakRef = new WeakRef(innerKey);
})();
// 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();
assertNotEquals(undefined, weakRef.deref());
// Trigger GC again in next task. Now the WeakRef is 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, weakRef.deref());
})();

View File

@ -0,0 +1,39 @@
// Copyright 2022 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.
(function TestRegisterWithSymbolTarget() {
const fg = new FinalizationRegistry(() => { });
fg.register(Symbol('123'), 'holdings');
// Registered symbols cannot be the target.
assertThrows(() => fg.register(Symbol.for('123'), 'holdings'), TypeError);
})();
(function TestRegisterWithSymbolUnregisterToken() {
const fg = new FinalizationRegistry(() => { });
fg.register({}, 'holdings', Symbol('123'));
// Registered symbols cannot be the unregister token.
assertThrows(() => fg.register({}, 'holdings', Symbol.for('123')), TypeError);
})();
(function TestRegisterSymbolAndHoldingsSameValue() {
const fg = new FinalizationRegistry(() => {});
const obj = Symbol('123');
// SameValue(target, holdings) not ok.
assertThrows(() => fg.register(obj, obj), TypeError);
const holdings = {a: 1};
fg.register(obj, holdings);
})();
(function TestUnregisterWithSymbolUnregisterToken() {
const fg = new FinalizationRegistry(() => {});
fg.unregister(Symbol('123'));
// Registered symbols cannot be the unregister token.
assertThrows(() => fg.unregister(Symbol.for('123')), TypeError);
})();
(function TestWeakRefConstructorWithSymbol() {
new WeakRef(Symbol('123'));
// Registered symbols cannot be the WeakRef target.
assertThrows(() => new WeakRef(Symbol.for('123')), TypeError);
})();

View File

@ -0,0 +1,30 @@
// 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: --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);
})();

View File

@ -0,0 +1,54 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
let o1 = {};
let o2 = {};
let wr1;
let wr2;
(function() {
wr1 = new WeakRef(o1);
wr2 = new WeakRef(o2);
})();
// 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();
(function() {
assertNotEquals(undefined, wr1.deref());
assertNotEquals(undefined, wr2.deref());
})();
// New task
setTimeout(function() {
(function () { wr1.deref(); })();
o1 = null;
gc(); // deref makes sure we don't clean up wr1
(function () { assertNotEquals(undefined, wr1.deref()); })();
// New task
setTimeout(function() {
(function () { wr2.deref(); })();
o2 = null;
gc(); // deref makes sure we don't clean up wr2
(function () { assertNotEquals(undefined, wr2.deref()); })();
// New task
(async 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, wr2.deref());
})();
}, 0);
}, 0);

View File

@ -0,0 +1,42 @@
// Copyright 2019 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: --expose-gc --noincremental-marking
(async function () {
let cleanup_call_count = 0;
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!
(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);
})();

View File

@ -0,0 +1,49 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
(async function () {
let cleanup_call_count = 0;
let cleanup = function (holdings) {
assertEquals("holdings", holdings);
++cleanup_call_count;
}
let fg = new FinalizationRegistry(cleanup);
let key = { "k": "this is the key" };
// Create an object and register it in the FinalizationRegistry. The object needs
// 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);
})();

View File

@ -0,0 +1,45 @@
// Copyright 2018 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: --expose-gc --noincremental-marking --noincremental-marking
(async function () {
let cleanup_call_count = 0;
let cleanup = function (holdings) {
++cleanup_call_count;
}
let fg = new FinalizationRegistry(cleanup);
let key = { "k": "this is the key" };
// Create an object and register it in the FinalizationRegistry. The object needs
// to be inside a closure so that we can reliably kill them!
(function () {
let object = {};
fg.register(object, "my holdings", key);
// 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);
})();

View File

@ -0,0 +1,50 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
(async function () {
let cleanup_call_count = 0;
let cleanup = function (holdings) {
++cleanup_call_count;
}
let fg = new FinalizationRegistry(cleanup);
let key = { "k": "this is the key" };
// Create an object and register it in the FinalizationRegistry. The object needs
// to be inside a closure so that we can reliably kill them!
(function () {
let object = {};
fg.register(object, "holdings", key);
// Unregister before the GC has a chance to discover the object.
let success = fg.unregister(key);
assertTrue(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);
})();

View File

@ -0,0 +1,45 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
(async function () {
let cleanup_call_count = 0;
let cleanup = function (holdings) {
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" };
(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);
})();

View File

@ -0,0 +1,53 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
(async function () {
let cleanup_call_count = 0;
let cleanup = function(holdings) {
// See which target we're cleaning up and unregister the other one.
if (holdings == 1) {
let success = fg.unregister(key2);
assertTrue(success);
} else {
assertSame(holdings, 2);
let success = fg.unregister(key1);
assertTrue(success);
}
++cleanup_call_count;
}
let fg = new FinalizationRegistry(cleanup);
let key1 = {"k": "first key"};
let key2 = {"k": "second key"};
// Create two objects and register them in the FinalizationRegistry. The objects
// need to be inside a closure so that we can reliably kill them!
(function() {
let object1 = {};
fg.register(object1, 1, key1);
let object2 = {};
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);
})();

View File

@ -0,0 +1,51 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
(async function () {
let cleanup_call_count = 0;
let cleanup = function(holdings) {
assertEquals(holdings, "holdings");
// There's one more object with the same key that we haven't
// 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;
}
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"};
(function() {
let object = {};
let object2 = {};
fg.register(object, "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);
})();

View File

@ -0,0 +1,54 @@
// Copyright 2019 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: --expose-gc --noincremental-marking
(async function () {
let cleanup_call_count = 0;
let cleanup = function(holdings) {
assertEquals("holdings2", holdings);
++cleanup_call_count;
}
let fg = new FinalizationRegistry(cleanup);
let key1 = {"k": "key1"};
let key2 = {"k": "key2"};
// 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 object1a = {};
fg.register(object1a, "holdings1a", key1);
let object1b = {};
fg.register(object1b, "holdings1b", key1);
let object2 = {};
fg.register(object2, "holdings2", key2);
// 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);
})();

View File

@ -0,0 +1,45 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
(async function () {
let cleanup_call_count = 0;
let cleanup = function(holdings) {
++cleanup_call_count;
}
let key = {"k": "this is my key"};
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!
(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);
})();

View File

@ -0,0 +1,47 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
(async function () {
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);
// 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.
await gc({ type: 'major', execution: 'async' });
assertFalse(cleanup_called);
let timeout_func = function() {
assertTrue(cleanup_called);
}
setTimeout(timeout_func, 0);
})();

View File

@ -0,0 +1,33 @@
// Copyright 2019 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: --expose-gc --noincremental-marking
const cleanup = function (holdings) { globalThis.FRRan = true; };
const FR = new FinalizationRegistry(cleanup);
(function () {
let obj = {};
// obj is its own unregister token and becomes unreachable after this
// block. If the unregister token is held strongly this test will not
// terminate.
FR.register(obj, 42, obj);
})();
function tryAgain() {
(async function () {
// 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' });
if (globalThis.FRRan) {
return;
}
setTimeout(tryAgain, 0);
})();
}
tryAgain();

View File

@ -0,0 +1,33 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
let wr;
(function () {
let o = {};
wr = new WeakRef(o);
// Don't deref here, we want to test that the creation is enough to keep the
// 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();
// Since the WeakRef was created during this turn, it is not cleared by GC.
assertNotEquals(undefined, wr.deref());
// Next task.
setTimeout(() => {
(async 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, wr.deref());
})();
}, 0);

View File

@ -0,0 +1,48 @@
// Copyright 2018 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: --expose-gc --noincremental-marking
let wr;
let wr_control; // control WeakRef for testing what happens without deref
(function () {
let o1 = {};
wr = new WeakRef(o1);
let o2 = {};
wr_control = new WeakRef(o2);
})();
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();
// Next task.
setTimeout(function() {
// Call deref inside a closure, trying to avoid accidentally storing a strong
// reference into the object in the stack frame.
(function () { wr.deref(); })();
strong = null;
// This GC should clear wr_control (modulo CSS), since nothing was keeping it
// alive, but it should not clear wr.
gc();
(function () { assertNotEquals(undefined, wr.deref()); })();
// Next task.
(async 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, wr.deref());
assertEquals(undefined, wr_control.deref());
})();
}, 0);