Migrate FinalizationRegistry tests to per-item callback API

This commit is contained in:
Shu-yu Guo 2020-03-13 16:43:25 -07:00 committed by Rick Waldron
parent 4199a3b34b
commit 966fc11862
19 changed files with 50 additions and 987 deletions

View File

@ -21,10 +21,10 @@ function asyncGC(...targets) {
targets = null;
return Promise.resolve('tick').then(() => asyncGCDeref()).then(() => {
var names;
var names = [];
// consume iterator to capture names
finalizationRegistry.cleanupSome(iter => { names = [...iter]; });
finalizationRegistry.cleanupSome(name => { names.push(name); });
if (!names || names.length != length) {
throw asyncGC.notCollected;

View File

@ -1,64 +0,0 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-properties-of-the-finalization-registry-constructor
description: >
FinalizationRegistryCleanupIteratorPrototype @@toStringTag
info: |
FinalizationRegistry.prototype.cleanupSome ( [ callback ] )
1. Let finalizationRegistry be the this value.
...
5. Perform ! CleanupFinalizationRegistry(finalizationRegistry, callback).
...
CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] )
...
3. Let iterator be ! CreateFinalizationRegistryCleanupIterator(finalizationRegistry).
...
6. Let result be Call(callback, undefined, « iterator »).
...
%FinalizationRegistryCleanupIteratorPrototype% [ @@toStringTag ]
The initial value of the @@toStringTag property is the String value "FinalizationRegistry Cleanup Iterator".
This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
features: [FinalizationRegistry, host-gc-required, Symbol, Symbol.toStringTag]
includes: [async-gc.js, propertyHelper.js]
flags: [async, non-deterministic]
---*/
var FinalizationRegistryCleanupIteratorPrototype;
var called = 0;
var finalizationRegistry = new FinalizationRegistry(function() {});
function callback(iterator) {
called += 1;
FinalizationRegistryCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
function emptyCells() {
var target = {};
finalizationRegistry.register(target);
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
finalizationRegistry.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful');
verifyProperty(FinalizationRegistryCleanupIteratorPrototype, Symbol.toStringTag, {
value: 'FinalizationRegistry Cleanup Iterator',
writable: false,
enumerable: false,
configurable: true
});
}).then($DONE, resolveAsyncGC);

View File

@ -1,69 +0,0 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-properties-of-the-finalization-registry-constructor
description: >
Throws a TypeError if [[IsFinalizationRegistryCleanupJobActive]] is false
info: |
FinalizationRegistry.prototype.cleanupSome ( [ callback ] )
1. Let finalizationRegistry be the this value.
...
5. Perform ! CleanupFinalizationRegistry(finalizationRegistry, callback).
...
CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] )
...
3. Let iterator be ! CreateFinalizationRegistryCleanupIterator(finalizationRegistry).
...
5. Set finalizationRegistry.[[IsFinalizationRegistryCleanupJobActive]] to true.
6. Let result be Call(callback, undefined, « iterator »).
7. Set finalizationRegistry.[[IsFinalizationRegistryCleanupJobActive]] to false.
...
%FinalizationRegistryCleanupIteratorPrototype%.next ( )
1. Let iterator be the this value.
2. If Type(iterator) is not Object, throw a TypeError exception.
3. If iterator does not have a [[FinalizationRegistry]] internal slot, throw a TypeError exception.
features: [FinalizationRegistry, WeakRef, host-gc-required, Symbol]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var iter;
var FinalizationRegistryCleanupIteratorPrototype;
var called = 0;
var finalizationRegistry = new FinalizationRegistry(function() {});
function callback(iterator) {
called += 1;
iter = iterator;
FinalizationRegistryCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
function emptyCells() {
var target = {};
finalizationRegistry.register(target, 'target');
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
finalizationRegistry.cleanupSome(callback);
// Make sure everything is set
assert.sameValue(called, 1, 'cleanup successful');
assert.sameValue(typeof iter, 'object');
assert.sameValue(Object.getPrototypeOf(iter), FinalizationRegistryCleanupIteratorPrototype);
// To the actual assertion
assert.throws(TypeError, function() {
iter.next();
}, 'Iter should fail if not called during the cleanupSome call');
}).then($DONE, resolveAsyncGC);

View File

@ -1,74 +0,0 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-properties-of-the-finalization-registry-constructor
description: >
FinalizationRegistryCleanupIteratorPrototype.next.length property descriptor
info: |
FinalizationRegistry.prototype.cleanupSome ( [ callback ] )
1. Let finalizationRegistry be the this value.
...
5. Perform ! CleanupFinalizationRegistry(finalizationRegistry, callback).
...
CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] )
...
3. Let iterator be ! CreateFinalizationRegistryCleanupIterator(finalizationRegistry).
...
6. Let result be Call(callback, undefined, « iterator »).
...
17 ECMAScript Standard Built-in Objects
Every built-in function object, including constructors, has a length
property whose value is an integer. Unless otherwise specified, this
value is equal to the largest number of named arguments shown in the
subclause headings for the function description. Optional parameters
(which are indicated with brackets: [ ]) or rest parameters (which
are shown using the form «...name») are not included in the default
argument count.
Unless otherwise specified, the length property of a built-in
function object has the attributes { [[Writable]]: false,
[[Enumerable]]: false, [[Configurable]]: true }.
includes: [async-gc.js, propertyHelper.js]
flags: [async, non-deterministic]
features: [FinalizationRegistry, host-gc-required, Symbol]
---*/
var FinalizationRegistryCleanupIteratorPrototype;
var called = 0;
var finalizationRegistry = new FinalizationRegistry(function() {});
function callback(iterator) {
called += 1;
FinalizationRegistryCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
function emptyCells() {
var target = {};
finalizationRegistry.register(target);
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
finalizationRegistry.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful');
assert.sameValue(typeof FinalizationRegistryCleanupIteratorPrototype.next, 'function');
verifyProperty(FinalizationRegistryCleanupIteratorPrototype.next, 'length', {
value: 0,
enumerable: false,
writable: false,
configurable: true,
});
}).then($DONE, resolveAsyncGC);

View File

@ -1,90 +0,0 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-properties-of-the-finalization-registry-constructor
description: >
If iterator does not have a [[FinalizationRegistry]] internal slot, throw a TypeError exception.
info: |
FinalizationRegistry.prototype.cleanupSome ( [ callback ] )
1. Let finalizationRegistry be the this value.
...
5. Perform ! CleanupFinalizationRegistry(finalizationRegistry, callback).
...
CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] )
...
3. Let iterator be ! CreateFinalizationRegistryCleanupIterator(finalizationRegistry).
...
6. Let result be Call(callback, undefined, « iterator »).
...
%FinalizationRegistryCleanupIteratorPrototype%.next ( )
1. Let iterator be the this value.
2. If Type(iterator) is not Object, throw a TypeError exception.
3. If iterator does not have a [[FinalizationRegistry]] internal slot, throw a TypeError exception.
features: [FinalizationRegistry, WeakRef, host-gc-required, Symbol]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var FinalizationRegistryCleanupIteratorPrototype;
var called = 0;
var endOfCall = 0;
var finalizationRegistry = new FinalizationRegistry(function() {});
function callback(iterator) {
called += 1;
// Only the iterator itself will have a [[FinalizationRegistry]] internal
FinalizationRegistryCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
// It's sensitive the assertions remain inside this function in order to secure
// [[IsFinalizationRegistryCleanupJobActive]] is true
assert.sameValue(typeof FinalizationRegistryCleanupIteratorPrototype.next, 'function');
var next = FinalizationRegistryCleanupIteratorPrototype.next;
assert.throws(TypeError, function() {
next.call({});
}, '{}');
assert.throws(TypeError, function() {
next.call(FinalizationRegistry);
}, 'FinalizationRegistry');
assert.throws(TypeError, function() {
next.call(FinalizationRegistryCleanupIteratorPrototype);
}, 'FinalizationRegistryCleanupIteratorPrototype');
assert.throws(TypeError, function() {
next.call(finalizationRegistry);
}, 'FinalizationRegistry instance');
var wr = new WeakRef({});
assert.throws(TypeError, function() {
next.call(wr);
}, 'WeakRef instance');
// Abrupt completions are not directly returned.
endOfCall += 1;
}
function emptyCells() {
var target = {};
finalizationRegistry.register(target);
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
finalizationRegistry.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful');
assert.sameValue(endOfCall, 1, 'Abrupt completions are not directly returned.');
}).then($DONE, resolveAsyncGC);

View File

@ -1,75 +0,0 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-properties-of-the-finalization-registry-constructor
description: >
FinalizationRegistryCleanupIteratorPrototype.next.name property descriptor
info: |
FinalizationRegistry.prototype.cleanupSome ( [ callback ] )
1. Let finalizationRegistry be the this value.
...
5. Perform ! CleanupFinalizationRegistry(finalizationRegistry, callback).
...
CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] )
...
3. Let iterator be ! CreateFinalizationRegistryCleanupIterator(finalizationRegistry).
...
6. Let result be Call(callback, undefined, « iterator »).
...
17 ECMAScript Standard Built-in Objects
Every built-in function object, including constructors, that is not
identified as an anonymous function has a name property whose value
is a String. Unless otherwise specified, this value is the name that
is given to the function in this specification. For functions that
are specified as properties of objects, the name value is the
property name string used to access the function. [...]
Unless otherwise specified, the name property of a built-in function
object, if it exists, has the attributes { [[Writable]]: false,
[[Enumerable]]: false, [[Configurable]]: true }.
includes: [async-gc.js, propertyHelper.js]
flags: [async, non-deterministic]
features: [FinalizationRegistry, host-gc-required, Symbol]
---*/
var FinalizationRegistryCleanupIteratorPrototype;
var called = 0;
var finalizationRegistry = new FinalizationRegistry(function() {});
function callback(iterator) {
called += 1;
FinalizationRegistryCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
function emptyCells() {
var target = {};
finalizationRegistry.register(target);
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
finalizationRegistry.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful');
assert.sameValue(typeof FinalizationRegistryCleanupIteratorPrototype.next, 'function');
var next = FinalizationRegistryCleanupIteratorPrototype.next;
verifyProperty(next, 'name', {
value: 'next',
enumerable: false,
writable: false,
configurable: true,
});
}).then($DONE, resolveAsyncGC);

View File

@ -1,89 +0,0 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-properties-of-the-finalization-registry-constructor
description: >
FinalizationRegistryCleanupIteratorPrototype.next() throws if this is not Object
info: |
FinalizationRegistry.prototype.cleanupSome ( [ callback ] )
1. Let finalizationRegistry be the this value.
...
5. Perform ! CleanupFinalizationRegistry(finalizationRegistry, callback).
...
CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] )
...
3. Let iterator be ! CreateFinalizationRegistryCleanupIterator(finalizationRegistry).
...
6. Let result be Call(callback, undefined, « iterator »).
...
%FinalizationRegistryCleanupIteratorPrototype%.next ( )
1. Let iterator be the this value.
2. If Type(iterator) is not Object, throw a TypeError exception.
features: [FinalizationRegistry, host-gc-required, Symbol]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var FinalizationRegistryCleanupIteratorPrototype;
var called = 0;
var finalizationRegistry = new FinalizationRegistry(function() {});
function callback(iterator) {
called += 1;
FinalizationRegistryCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
function emptyCells() {
var target = {};
finalizationRegistry.register(target);
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
finalizationRegistry.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful');
assert.sameValue(typeof FinalizationRegistryCleanupIteratorPrototype.next, 'function');
var next = FinalizationRegistryCleanupIteratorPrototype.next;
assert.throws(TypeError, function() {
next.call(undefined);
}, 'undefined');
assert.throws(TypeError, function() {
next.call(null);
}, 'null');
assert.throws(TypeError, function() {
next.call(true);
}, 'true');
assert.throws(TypeError, function() {
next.call(false);
}, 'false');
assert.throws(TypeError, function() {
next.call(1);
}, '1');
assert.throws(TypeError, function() {
next.call('string');
}, 'string');
var symbol = Symbol();
assert.throws(TypeError, function() {
next.call(symbol);
}, 'symbol');
}).then($DONE, resolveAsyncGC);

View File

@ -1,67 +0,0 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-properties-of-the-finalization-registry-constructor
description: >
Prop descriptor for FinalizationRegistryCleanupIteratorPrototype.next
info: |
FinalizationRegistry.prototype.cleanupSome ( [ callback ] )
1. Let finalizationRegistry be the this value.
...
5. Perform ! CleanupFinalizationRegistry(finalizationRegistry, callback).
...
CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] )
...
3. Let iterator be ! CreateFinalizationRegistryCleanupIterator(finalizationRegistry).
...
6. Let result be Call(callback, undefined, « iterator »).
...
17 ECMAScript Standard Built-in Objects:
Every other data property described in clauses 18 through 26 and in Annex B.2
has the attributes { [[Writable]]: true, [[Enumerable]]: false,
[[Configurable]]: true } unless otherwise specified.
includes: [propertyHelper.js, async-gc.js]
flags: [async, non-deterministic]
features: [FinalizationRegistry, host-gc-required, Symbol]
---*/
var FinalizationRegistryCleanupIteratorPrototype;
var called = 0;
var finalizationRegistry = new FinalizationRegistry(function() {});
function callback(iterator) {
called += 1;
FinalizationRegistryCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
function emptyCells() {
var target = {};
finalizationRegistry.register(target);
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
finalizationRegistry.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful');
assert.sameValue(typeof FinalizationRegistryCleanupIteratorPrototype.next, 'function');
var next = FinalizationRegistryCleanupIteratorPrototype.next;
verifyProperty(FinalizationRegistryCleanupIteratorPrototype, 'next', {
enumerable: false,
writable: true,
configurable: true,
});
}).then($DONE, resolveAsyncGC);

View File

@ -1,91 +0,0 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-properties-of-the-finalization-registry-constructor
description: >
FinalizationRegistryCleanupIterator has a [[Prototype]] internal slot whose value is the intrinsic
object %IteratorPrototype%.
info: |
The %FinalizationRegistryCleanupIteratorPrototype% Object
- has properties that are inherited by all FinalizationRegistry Cleanup Iterator Objects.
- is an ordinary object.
- has a [[Prototype]] internal slot whose value is the intrinsic object %IteratorPrototype%.
...
FinalizationRegistry.prototype.cleanupSome ( [ callback ] )
1. Let finalizationRegistry be the this value.
2. If Type(finalizationRegistry) is not Object, throw a TypeError exception.
3. If finalizationRegistry does not have a [[Cells]] internal slot, throw a TypeError exception.
4. If callback is not undefined and IsCallable(callback) is false, throw a TypeError exception.
5. Perform ! CleanupFinalizationRegistry(finalizationRegistry, callback).
6. Return undefined.
CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] )
...
2. If CheckForEmptyCells(finalizationRegistry) is false, return.
3. Let iterator be ! CreateFinalizationRegistryCleanupIterator(finalizationRegistry).
4. If callback is undefined, set callback to finalizationRegistry.[[CleanupCallback]].
5. Set finalizationRegistry.[[IsFinalizationRegistryCleanupJobActive]] to true.
6. Let result be Call(callback, undefined, « iterator »).
...
CheckForEmptyCells ( finalizationRegistry )
...
2. For each cell in finalizationRegistry.[[Cells]], do
a. If cell.[[Target]] is empty, then
i. Return true.
3. Return false.
CreateFinalizationRegistryCleanupIterator ( finalizationRegistry )
...
4. Let prototype be finalizationRegistry.[[Realm]].[[Intrinsics]].[[%FinalizationRegistryCleanupIteratorPrototype%]].
5. Let iterator be ObjectCreate(prototype, « [[FinalizationRegistry]] »).
6. Set iterator.[[FinalizationRegistry]] to finalizationRegistry.
7. Return iterator.
features: [FinalizationRegistry, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
var FinalizationRegistryCleanupIteratorPrototype;
var called = 0;
var cleanupCallbackCalled = 0;
function callback(iterator) {
called += 1;
FinalizationRegistryCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
var finalizationRegistry = new FinalizationRegistry(function() {});
function emptyCells() {
var target = {};
finalizationRegistry.register(target);
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
finalizationRegistry.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful');
var proto = Object.getPrototypeOf(FinalizationRegistryCleanupIteratorPrototype);
assert.sameValue(
proto, IteratorPrototype,
'[[Prototype]] internal slot whose value is the intrinsic object %IteratorPrototype%'
);
assert.sameValue(cleanupCallbackCalled, 0, 'if a callback is given, do not call cleanupCallback');
}).then($DONE, resolveAsyncGC);

View File

@ -33,10 +33,8 @@ includes: [async-gc.js]
var cleanupCallback = 0;
var called = 0;
// both this cb and the finalizationRegistry callback are not exhausting the iterator to prevent
// the target cell from being removed from the finalizationRegistry.[[Cells]].
// More info at %FinalizationRegistryCleanupIteratorPrototype%.next ( )
function cb() {
function cb(holding) {
assert.sameValue(holding, 'a');
called += 1;
}
@ -54,14 +52,17 @@ function emptyCells() {
return prom;
}
// Let's add some async ticks, as the cleanupCallback is not meant to interrupt
// synchronous operations.
async function fn() {
emptyCells()
.then(async function() {
await Promise.resolve(1);
finalizationRegistry.cleanupSome(cb);
// cleanupSome will be invoked if there are empty cells left. If the
// cleanupCallback already ran, then cb won't be called.
let expectedCalled = cleanupCallback === 1 ? 0 : 1;
// This asserts the registered object was emptied in the previous GC.
assert.sameValue(called, 1, 'cleanupSome callback for the first time');
assert.sameValue(called, expectedCalled, 'cleanupSome callback for the first time');
// At this point, we can't assert if cleanupCallback was called, because it's
// optional. Although, we can finally assert it's not gonna be called anymore
@ -71,8 +72,8 @@ async function fn() {
assert(cleanupCallback >= 0, 'cleanupCallback might be 0');
assert(cleanupCallback <= 1, 'cleanupCallback might be 1');
// Restoring the cleanupCallback variable to 0 will help us asserting the finalizationRegistry
// callback is not called again.
// Restoring the cleanupCallback variable to 0 will help us asserting the
// finalizationRegistry callback is not called again.
cleanupCallback = 0;
await $262.gc();
@ -80,9 +81,7 @@ async function fn() {
finalizationRegistry.cleanupSome(cb);
// This cb is called again because finalizationRegistry still holds an emptied cell, but it's
// not yet removed from the
assert.sameValue(called, 2, 'cleanupSome callback for the second time');
assert.sameValue(called, expectedCalled, 'cleanupSome callback is not called anymore, no empty cells');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #1');
await $262.gc();
@ -90,46 +89,9 @@ async function fn() {
finalizationRegistry.cleanupSome(cb);
assert.sameValue(called, 3, 'cleanupSome callback for the third time');
assert.sameValue(called, expectedCalled, 'cleanupSome callback is not called again #2');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #2');
await $262.gc();
}
emptyCells()
.then(async function() {
await fn();// tick
await Promise.resolve(4); // tick
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #3');
finalizationRegistry.cleanupSome(cb);
assert.sameValue(called, 4, 'cleanupSome callback for the fourth time');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #4');
await $262.gc();
// Now we are exhausting the iterator, so cleanupSome callback will also not be called.
finalizationRegistry.cleanupSome(iterator => {
var exhausted = [...iterator];
assert.sameValue(exhausted.length, 1);
assert.sameValue(exhausted[0], 'a');
called += 1;
});
assert.sameValue(called, 5, 'cleanupSome callback for the fifth time');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #4');
await $262.gc();
await Promise.resolve(5); // tick
await await Promise.resolve(6); // more ticks
await await await Promise.resolve(7); // even more ticks
finalizationRegistry.cleanupSome(cb);
assert.sameValue(called, 5, 'cleanupSome callback is not called anymore, no empty cells');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #5');
})
.then($DONE, resolveAsyncGC);

View File

@ -1,98 +0,0 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-properties-of-the-finalization-registry-constructor
description: >
The callback function is called with a FinalizationRegistryCleanupIterator
info: |
The %FinalizationRegistryCleanupIteratorPrototype% Object
- has properties that are inherited by all FinalizationRegistry Cleanup Iterator Objects.
- is an ordinary object.
- has a [[Prototype]] internal slot whose value is the intrinsic object %IteratorPrototype%.
...
FinalizationRegistry.prototype.cleanupSome ( [ callback ] )
1. Let finalizationRegistry be the this value.
2. If Type(finalizationRegistry) is not Object, throw a TypeError exception.
3. If finalizationRegistry does not have a [[Cells]] internal slot, throw a TypeError exception.
4. If callback is not undefined and IsCallable(callback) is false, throw a TypeError exception.
5. Perform ! CleanupFinalizationRegistry(finalizationRegistry, callback).
6. Return undefined.
CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] )
...
2. If CheckForEmptyCells(finalizationRegistry) is false, return.
3. Let iterator be ! CreateFinalizationRegistryCleanupIterator(finalizationRegistry).
4. If callback is undefined, set callback to finalizationRegistry.[[CleanupCallback]].
5. Set finalizationRegistry.[[IsFinalizationRegistryCleanupJobActive]] to true.
6. Let result be Call(callback, undefined, « iterator »).
...
CheckForEmptyCells ( finalizationRegistry )
...
2. For each cell in finalizationRegistry.[[Cells]], do
a. If cell.[[Target]] is empty, then
i. Return true.
3. Return false.
CreateFinalizationRegistryCleanupIterator ( finalizationRegistry )
...
4. Let prototype be finalizationRegistry.[[Realm]].[[Intrinsics]].[[%FinalizationRegistryCleanupIteratorPrototype%]].
5. Let iterator be ObjectCreate(prototype, « [[FinalizationRegistry]] »).
6. Set iterator.[[FinalizationRegistry]] to finalizationRegistry.
7. Return iterator.
features: [FinalizationRegistry, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
var FinalizationRegistryCleanupIteratorPrototype;
var called = 0;
var cleanupCallbackCalled = 0;
function callback(iterator) {
called += 1;
FinalizationRegistryCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
var finalizationRegistry = new FinalizationRegistry(function() {
cleanupCallbackCalled += 1;
});
async function register() {
var target = {};
finalizationRegistry.register(target);
var prom = asyncGC(target);
target = null;
assert.sameValue(called, 0); // never called in sync execution
return prom;
}
register()
.then(function() {
// We can't observe if the cleanupCallback was called, but we can make sure cleanupSome won't call it.
cleanupCallbackCalled = 0;
finalizationRegistry.cleanupSome(callback);
assert.sameValue(called, 1);
var proto = Object.getPrototypeOf(FinalizationRegistryCleanupIteratorPrototype);
assert.sameValue(
proto, IteratorPrototype,
'[[Prototype]] internal slot whose value is the intrinsic object %IteratorPrototype%'
);
assert.sameValue(cleanupCallbackCalled, 0, 'if a callback is given, do not call cleanupCallback');
})
.then($DONE, resolveAsyncGC);

View File

@ -18,9 +18,9 @@ includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var holdingsList;
function cb(iterator) {
holdingsList = [...iterator];
var holdingsList = [];
function cb(holding) {
holdingsList.push(holding);
};
var finalizationRegistry = new FinalizationRegistry(function() {});

View File

@ -46,7 +46,7 @@ emptyCells().then(function() {
var res = finalizationRegistry.unregister(token);
assert.sameValue(res, true, 'unregister target before iterating over it in cleanup');
finalizationRegistry.cleanupSome(function cb(iterator) {
finalizationRegistry.cleanupSome(function cb(holding) {
called += 1;
});

View File

@ -1,86 +0,0 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-properties-of-the-finalization-registry-constructor
description: >
The cleanup callback function is called with a FinalizationRegistryCleanupIterator
info: |
The %FinalizationRegistryCleanupIteratorPrototype% Object
- has properties that are inherited by all FinalizationRegistry Cleanup Iterator Objects.
- is an ordinary object.
- has a [[Prototype]] internal slot whose value is the intrinsic object %IteratorPrototype%.
...
FinalizationRegistry.prototype.cleanupSome ( [ callback ] )
1. Let finalizationRegistry be the this value.
2. If Type(finalizationRegistry) is not Object, throw a TypeError exception.
3. If finalizationRegistry does not have a [[Cells]] internal slot, throw a TypeError exception.
4. If callback is not undefined and IsCallable(callback) is false, throw a TypeError exception.
5. Perform ! CleanupFinalizationRegistry(finalizationRegistry, callback).
6. Return undefined.
CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] )
...
2. If CheckForEmptyCells(finalizationRegistry) is false, return.
3. Let iterator be ! CreateFinalizationRegistryCleanupIterator(finalizationRegistry).
4. If callback is undefined, set callback to finalizationRegistry.[[CleanupCallback]].
5. Set finalizationRegistry.[[IsFinalizationRegistryCleanupJobActive]] to true.
6. Let result be Call(callback, undefined, « iterator »).
...
CheckForEmptyCells ( finalizationRegistry )
...
2. For each cell in finalizationRegistry.[[Cells]], do
a. If cell.[[Target]] is empty, then
i. Return true.
3. Return false.
CreateFinalizationRegistryCleanupIterator ( finalizationRegistry )
...
4. Let prototype be finalizationRegistry.[[Realm]].[[Intrinsics]].[[%FinalizationRegistryCleanupIteratorPrototype%]].
5. Let iterator be ObjectCreate(prototype, « [[FinalizationRegistry]] »).
6. Set iterator.[[FinalizationRegistry]] to finalizationRegistry.
7. Return iterator.
features: [FinalizationRegistry, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
var FinalizationRegistryCleanupIteratorPrototype;
var called = 0;
function callback(iterator) {
called += 1;
FinalizationRegistryCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
var finalizationRegistry = new FinalizationRegistry(function() {});
function emptyCells() {
var target = {};
finalizationRegistry.register(target);
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
finalizationRegistry.cleanupSome(callback);
assert.sameValue(called, 1);
var proto = Object.getPrototypeOf(FinalizationRegistryCleanupIteratorPrototype);
assert.sameValue(
proto, IteratorPrototype,
'[[Prototype]] internal slot whose value is the intrinsic object %IteratorPrototype%'
);
}).then($DONE, resolveAsyncGC);

View File

@ -16,31 +16,26 @@ info: |
CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] )
...
3. Let iterator be ! CreateFinalizationRegistryCleanupIterator(finalizationRegistry).
...
6. Let result be Call(callback, undefined, « iterator »).
...
%FinalizationRegistryCleanupIteratorPrototype%.next ( )
8. If finalizationRegistry.[[Cells]] contains a Record cell such that cell.[[Target]] is empty,
3. While finalizationRegistry.[[Cells]] contains a Record cell such that cell.[[WeakRefTarget]] is ~empty~, then an implementation may perform the following steps,
a. Choose any such cell.
b. Remove cell from finalizationRegistry.[[Cells]].
c. Return CreateIterResultObject(cell.[[Holdings]], false).
9. Otherwise, return CreateIterResultObject(undefined, true).
c. Perform ? Call(callback, undefined, << cell.[[HeldValue]] >>).
...
features: [FinalizationRegistry, Symbol, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
function check(value, expectedName) {
var holdings;
var holdings = [];
var called = 0;
var finalizationRegistry = new FinalizationRegistry(function() {});
function callback(iterator) {
function callback(holding) {
called += 1;
holdings = [...iterator];
holdings.push(holding);
}
// This is internal to avoid conflicts

View File

@ -1,62 +0,0 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-finalization-registry.prototype.cleanupSome
description: Return abrupt completion from CleanupFinalizationRegistry
info: |
FinalizationRegistry.prototype.cleanupSome ( [ callback ] )
1. Let finalizationRegistry be the this value.
2. If Type(finalizationRegistry) is not Object, throw a TypeError exception.
3. If finalizationRegistry does not have a [[Cells]] internal slot, throw a TypeError exception.
4. If callback is not undefined and IsCallable(callback) is false, throw a TypeError exception.
5. Perform ? CleanupFinalizationRegistry(finalizationRegistry, callback).
6. Return undefined.
CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] )
4. If callback is undefined, set callback to finalizationRegistry.[[CleanupCallback]].
5. Set finalizationRegistry.[[IsFinalizationRegistryCleanupJobActive]] to true.
6. Let result be Call(callback, undefined, « iterator »).
7. Set finalizationRegistry.[[IsFinalizationRegistryCleanupJobActive]] to false.
8. If result is an abrupt completion, return result.
features: [FinalizationRegistry, arrow-function, async-functions, async-iteration, class, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var called = 0;
var iterator = false;
function poisoned(iter) {
called += 1;
iterator = iter;
iter.next(); // Won't throw
throw new Test262Error();
}
var finalizationRegistry = new FinalizationRegistry(function() {});
function emptyCells() {
var target = {};
finalizationRegistry.register(target);
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
assert.throws(Test262Error, function() {
finalizationRegistry.cleanupSome(poisoned);
});
assert.sameValue(called, 1);
assert.sameValue(typeof iterator, 'object');
assert.sameValue(typeof iterator.next, 'function');
assert.throws(TypeError, function() {
iterator.next();
}, 'iterator.next throws a TypeError if IsFinalizationRegistryCleanupJobActive is false');
}).then($DONE, resolveAsyncGC);

View File

@ -4,15 +4,10 @@
/*---
esid: sec-properties-of-the-finalization-registry-constructor
description: >
The cleanupSome() method throws if cleanup is currently in progress.
The cleanupSome() method can be reentered
info: |
FinalizationRegistry.prototype.cleanupSome ( [ callback ] )
1. Let finalizationRegistry be the this value.
...
4. If finalizationRegistry.[[IsFinalizationRegistryCleanupJobActive]] is true,
throw a TypeError exception.
features: [FinalizationRegistry, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
@ -22,16 +17,14 @@ var called = 0;
var endOfCall = 0;
var finalizationRegistry = new FinalizationRegistry(function() {});
function callback(iterator) {
function callback(holding) {
called += 1;
if (called === 1) {
// Atempt to re-enter the callback.
var nestedCallbackRan = false;
assert.throws(TypeError, () => {
finalizationRegistry.cleanupSome(() => { nestedCallbackRan = true });
});
assert.sameValue(nestedCallbackRan, false);
finalizationRegistry.cleanupSome(() => { nestedCallbackRan = true });
assert.sameValue(nestedCallbackRan, true);
}
endOfCall += 1;
@ -39,7 +32,10 @@ function callback(iterator) {
function emptyCells() {
var o1 = {};
var o2 = {};
// Register more than one objects to test reentrancy.
finalizationRegistry.register(o1, 'holdings 1');
finalizationRegistry.register(o2, 'holdings 2');
var prom = asyncGC(o1);
o1 = null;

View File

@ -39,46 +39,28 @@ function emptyCells() {
return prom;
}
var tests = [];
tests.push(emptyCells().then(function() {
emptyCells().then(function() {
called = 0;
assert.sameValue(finalizationRegistry.cleanupSome(cb), undefined, 'regular callback');
assert.sameValue(called, 1);
}));
tests.push(emptyCells().then(function() {
}).then(emptyCells).then(function() {
called = 0;
assert.sameValue(finalizationRegistry.cleanupSome(fn), undefined, 'regular callback, same FG cleanup function');
assert.sameValue(called, 1);
}));
tests.push(emptyCells().then(function() {
}).then(emptyCells).then(function() {
called = 0;
assert.sameValue(finalizationRegistry.cleanupSome(), undefined, 'undefined (implicit) callback, defer to FB callback');
assert.sameValue(called, 1);
}));
tests.push(emptyCells().then(function() {
}).then(emptyCells).then(function() {
called = 0;
assert.sameValue(finalizationRegistry.cleanupSome(undefined), undefined, 'undefined (explicit) callback, defer to FB callback');
assert.sameValue(called, 1);
}));
tests.push(emptyCells().then(function() {
assert.sameValue(finalizationRegistry.cleanupSome(() => 1), undefined, 'arrow function');
}));
tests.push(emptyCells().then(function() {
}).then(emptyCells).then(function() {
assert.sameValue(finalizationRegistry.cleanupSome(() => 1), undefined, 'arrow function');
}).then(emptyCells).then(function() {
assert.sameValue(finalizationRegistry.cleanupSome(async function() {}), undefined, 'async function');
}));
tests.push(emptyCells().then(function() {
}).then(emptyCells).then(function() {
assert.sameValue(finalizationRegistry.cleanupSome(function *() {}), undefined, 'generator');
}));
tests.push(emptyCells().then(function() {
}).then(emptyCells).then(function() {
assert.sameValue(finalizationRegistry.cleanupSome(async function *() {}), undefined, 'async generator');
}));
Promise.all(tests).then(() => { $DONE(); }, resolveAsyncGC);
}).then($DONE, resolveAsyncGC);

View File

@ -15,18 +15,11 @@ info: |
CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] )
...
3. Let iterator be ! CreateFinalizationRegistryCleanupIterator(finalizationRegistry).
...
6. Let result be Call(callback, undefined, « iterator »).
...
%FinalizationRegistryCleanupIteratorPrototype%.next ( )
8. If finalizationRegistry.[[Cells]] contains a Record cell such that cell.[[Target]] is empty,
3. While finalizationRegistry.[[Cells]] contains a Record cell such that cell.[[WeakRefTarget]] is ~empty~, then an implementation may perform the following steps,
a. Choose any such cell.
b. Remove cell from finalizationRegistry.[[Cells]].
c. Return CreateIterResultObject(cell.[[Holdings]], false).
9. Otherwise, return CreateIterResultObject(undefined, true).
c. Perform ? Call(callback, undefined, << cell.[[HeldValue]] >>).
...
FinalizationRegistry.prototype.unregister ( unregisterToken )
@ -57,10 +50,10 @@ function emptyCells() {
emptyCells().then(function() {
var called = 0;
var holdings;
finalizationRegistry.cleanupSome(function cb(iterator) {
var holdings = [];
finalizationRegistry.cleanupSome(function cb(holding) {
called += 1;
holdings = [...iterator];
holdings.push(holding);
});
assert.sameValue(called, 1);