Update tests for GC hook, apply async

- Fix incorrect tests for WeakRefs

Ref #2239
Fixes #2260
Fixes #2256
This commit is contained in:
Leo Balter 2019-09-04 13:51:41 -03:00 committed by Rick Waldron
parent 7134634aa4
commit 08844700fe
21 changed files with 494 additions and 508 deletions

71
harness/async-gc.js Normal file
View File

@ -0,0 +1,71 @@
// Copyright (C) 2019 Ecma International. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: >
Collection of functions used to capture references cleanup from garbage collectors
features: [Symbol, async-functions]
flags: [non-deterministic]
features: [FinalizationGroup]
---*/
function asyncGC(...targets) {
var fg = new FinalizationGroup(() => {});
var length = targets.length;
for (let target of targets) {
fg.register(target, 'target');
target = null;
}
targets = null;
return Promise.resolve('tick').then(() => asyncGCDeref()).then(() => {
var names;
// consume iterator to capture names
fg.cleanupSome(iter => { names = [...iter]; });
if (!names || names.length != length) {
throw asyncGC.notCollected;
}
});
}
asyncGC.notCollected = Symbol('Object was not collected');
async function asyncGCDeref() {
var trigger;
// TODO: Remove this when $262.clearKeptObject becomes documented and required
if ($262.clearKeptObjects) {
trigger = $262.clearKeptObjects();
}
await $262.gc();
return Promise.resolve(trigger);
}
function resolveAsyncGC(err) {
if (err === asyncGC.notCollected) {
// Do not fail as GC can't provide necessary resources.
$DONE();
}
$DONE(err);
}
// function emptyCells() {
// var target = {};
// var wr = new WeakRef(target);
// var collected = asyncGC(target, clearKeptObjects());
// target = null;
// return collected.then(() => {
// return wr.deref();
// });
// }
// emptyCells().then((derefAsync) => {
// assert.sameValue(derefAsync, undefined);
// });

View File

@ -26,8 +26,9 @@ info: |
The initial value of the @@toStringTag property is the String value "FinalizationGroup Cleanup Iterator".
This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
includes: [propertyHelper.js]
features: [FinalizationGroup, host-gc-required, Symbol, Symbol.toStringTag]
includes: [async-gc.js, propertyHelper.js]
flags: [async, non-deterministic]
---*/
var FinalizationGroupCleanupIteratorPrototype;
@ -39,20 +40,25 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
(function() {
var o = {};
fg.register(o);
})();
function emptyCells() {
var target = {};
fg.register(target);
$262.gc();
var prom = asyncGC(target);
target = null;
fg.cleanupSome(callback);
return prom;
}
assert.sameValue(called, 1, 'cleanup successful');
emptyCells().then(function() {
fg.cleanupSome(callback);
verifyProperty(FinalizationGroupCleanupIteratorPrototype, Symbol.toStringTag, {
value: 'FinalizationGroup Cleanup Iterator',
writable: false,
enumerable: false,
configurable: true
});
assert.sameValue(called, 1, 'cleanup successful');
verifyProperty(FinalizationGroupCleanupIteratorPrototype, Symbol.toStringTag, {
value: 'FinalizationGroup Cleanup Iterator',
writable: false,
enumerable: false,
configurable: true
});
}).then($DONE, resolveAsyncGC);

View File

@ -29,6 +29,8 @@ info: |
2. If Type(iterator) is not Object, throw a TypeError exception.
3. If iterator does not have a [[FinalizationGroup]] internal slot, throw a TypeError exception.
features: [FinalizationGroup, WeakRef, host-gc-required, Symbol]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var iter;
@ -42,21 +44,26 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
(function() {
var o = {};
fg.register(o);
})();
function emptyCells() {
var target = {};
fg.register(target, 'target');
$262.gc();
var prom = asyncGC(target);
target = null;
fg.cleanupSome(callback);
return prom;
}
// Make sure everything is set
assert.sameValue(called, 1, 'cleanup successful');
assert.sameValue(typeof iter, 'object');
assert.sameValue(Object.getPrototypeOf(iter), FinalizationGroupCleanupIteratorPrototype);
emptyCells().then(function() {
fg.cleanupSome(callback);
// To the actual assertion
assert.throws(TypeError, function() {
iter.next();
}, 'Iter should fail if not called during the cleanupSome call');
// Make sure everything is set
assert.sameValue(called, 1, 'cleanup successful');
assert.sameValue(typeof iter, 'object');
assert.sameValue(Object.getPrototypeOf(iter), FinalizationGroupCleanupIteratorPrototype);
// 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

@ -34,7 +34,8 @@ info: |
Unless otherwise specified, the length property of a built-in
function object has the attributes { [[Writable]]: false,
[[Enumerable]]: false, [[Configurable]]: true }.
includes: [propertyHelper.js]
includes: [async-gc.js, propertyHelper.js]
flags: [async, non-deterministic]
features: [FinalizationGroup, host-gc-required, Symbol]
---*/
@ -47,24 +48,27 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
(function() {
var o = {};
fg.register(o);
})();
function emptyCells() {
var target = {};
fg.register(target);
$262.gc();
var prom = asyncGC(target);
target = null;
fg.cleanupSome(callback);
return prom;
}
assert.sameValue(called, 1, 'cleanup successful');
emptyCells().then(function() {
fg.cleanupSome(callback);
assert.sameValue(typeof FinalizationGroupCleanupIteratorPrototype.next, 'function');
assert.sameValue(called, 1, 'cleanup successful');
var next = FinalizationGroupCleanupIteratorPrototype.next;
assert.sameValue(typeof FinalizationGroupCleanupIteratorPrototype.next, 'function');
verifyProperty(next, 'length', {
value: 0,
enumerable: false,
writable: false,
configurable: true,
});
verifyProperty(FinalizationGroupCleanupIteratorPrototype.next, 'length', {
value: 0,
enumerable: false,
writable: false,
configurable: true,
});
}).then($DONE, resolveAsyncGC);

View File

@ -27,6 +27,8 @@ info: |
2. If Type(iterator) is not Object, throw a TypeError exception.
3. If iterator does not have a [[FinalizationGroup]] internal slot, throw a TypeError exception.
features: [FinalizationGroup, WeakRef, host-gc-required, Symbol]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var FinalizationGroupCleanupIteratorPrototype;
@ -70,14 +72,19 @@ function callback(iterator) {
endOfCall += 1;
}
(function() {
var o = {};
fg.register(o);
})();
function emptyCells() {
var target = {};
fg.register(target);
$262.gc();
var prom = asyncGC(target);
target = null;
fg.cleanupSome(callback);
return prom;
}
assert.sameValue(called, 1, 'cleanup successful');
assert.sameValue(endOfCall, 1, 'Abrupt completions are not directly returned.');
emptyCells().then(function() {
fg.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful');
assert.sameValue(endOfCall, 1, 'Abrupt completions are not directly returned.');
}).then($DONE, resolveAsyncGC);

View File

@ -33,7 +33,8 @@ info: |
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: [propertyHelper.js]
includes: [async-gc.js, propertyHelper.js]
flags: [async, non-deterministic]
features: [FinalizationGroup, host-gc-required, Symbol]
---*/
@ -46,24 +47,29 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
(function() {
var o = {};
fg.register(o);
})();
function emptyCells() {
var target = {};
fg.register(target);
$262.gc();
var prom = asyncGC(target);
target = null;
fg.cleanupSome(callback);
return prom;
}
assert.sameValue(called, 1, 'cleanup successful');
emptyCells().then(function() {
fg.cleanupSome(callback);
assert.sameValue(typeof FinalizationGroupCleanupIteratorPrototype.next, 'function');
assert.sameValue(called, 1, 'cleanup successful');
var next = FinalizationGroupCleanupIteratorPrototype.next;
assert.sameValue(typeof FinalizationGroupCleanupIteratorPrototype.next, 'function');
verifyProperty(next, 'name', {
value: 'next',
enumerable: false,
writable: false,
configurable: true,
});
var next = FinalizationGroupCleanupIteratorPrototype.next;
verifyProperty(next, 'name', {
value: 'next',
enumerable: false,
writable: false,
configurable: true,
});
}).then($DONE, resolveAsyncGC);

View File

@ -26,6 +26,8 @@ info: |
1. Let iterator be the this value.
2. If Type(iterator) is not Object, throw a TypeError exception.
features: [FinalizationGroup, host-gc-required, Symbol]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var FinalizationGroupCleanupIteratorPrototype;
@ -37,46 +39,51 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
(function() {
var o = {};
fg.register(o);
})();
function emptyCells() {
var target = {};
fg.register(target);
$262.gc();
var prom = asyncGC(target);
target = null;
fg.cleanupSome(callback);
return prom;
}
assert.sameValue(called, 1, 'cleanup successful');
emptyCells().then(function() {
fg.cleanupSome(callback);
assert.sameValue(typeof FinalizationGroupCleanupIteratorPrototype.next, 'function');
assert.sameValue(called, 1, 'cleanup successful');
var next = FinalizationGroupCleanupIteratorPrototype.next;
assert.sameValue(typeof FinalizationGroupCleanupIteratorPrototype.next, 'function');
assert.throws(TypeError, function() {
next.call(undefined);
}, 'undefined');
var next = FinalizationGroupCleanupIteratorPrototype.next;
assert.throws(TypeError, function() {
next.call(null);
}, 'null');
assert.throws(TypeError, function() {
next.call(undefined);
}, 'undefined');
assert.throws(TypeError, function() {
next.call(true);
}, 'true');
assert.throws(TypeError, function() {
next.call(null);
}, 'null');
assert.throws(TypeError, function() {
next.call(false);
}, 'false');
assert.throws(TypeError, function() {
next.call(true);
}, 'true');
assert.throws(TypeError, function() {
next.call(1);
}, '1');
assert.throws(TypeError, function() {
next.call(false);
}, 'false');
assert.throws(TypeError, function() {
next.call('string');
}, 'string');
assert.throws(TypeError, function() {
next.call(1);
}, '1');
var symbol = Symbol();
assert.throws(TypeError, function() {
next.call(symbol);
}, 'symbol');
assert.throws(TypeError, function() {
next.call('string');
}, 'string');
var symbol = Symbol();
assert.throws(TypeError, function() {
next.call(symbol);
}, 'symbol');
}).then($DONE, resolveAsyncGC);

View File

@ -26,7 +26,8 @@ info: |
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]
includes: [propertyHelper.js, async-gc.js]
flags: [async, non-deterministic]
features: [FinalizationGroup, host-gc-required, Symbol]
---*/
@ -39,23 +40,28 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
(function() {
var o = {};
fg.register(o);
})();
function emptyCells() {
var target = {};
fg.register(target);
$262.gc();
var prom = asyncGC(target);
target = null;
fg.cleanupSome(callback);
return prom;
}
assert.sameValue(called, 1, 'cleanup successful');
emptyCells().then(function() {
fg.cleanupSome(callback);
assert.sameValue(typeof FinalizationGroupCleanupIteratorPrototype.next, 'function');
assert.sameValue(called, 1, 'cleanup successful');
var next = FinalizationGroupCleanupIteratorPrototype.next;
assert.sameValue(typeof FinalizationGroupCleanupIteratorPrototype.next, 'function');
verifyProperty(FinalizationGroupCleanupIteratorPrototype, 'next', {
enumerable: false,
writable: true,
configurable: true,
});
var next = FinalizationGroupCleanupIteratorPrototype.next;
verifyProperty(FinalizationGroupCleanupIteratorPrototype, 'next', {
enumerable: false,
writable: true,
configurable: true,
});
}).then($DONE, resolveAsyncGC);

View File

@ -49,6 +49,8 @@ info: |
6. Set iterator.[[FinalizationGroup]] to finalizationGroup.
7. Return iterator.
features: [FinalizationGroup, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
@ -64,21 +66,26 @@ function callback(iterator) {
var fg = new FinalizationGroup(function() {});
(function() {
var o = {};
fg.register(o);
})();
function emptyCells() {
var target = {};
fg.register(target);
$262.gc();
var prom = asyncGC(target);
target = null;
fg.cleanupSome(callback);
return prom;
}
assert.sameValue(called, 1, 'cleanup successful');
emptyCells().then(function() {
fg.cleanupSome(callback);
var proto = Object.getPrototypeOf(FinalizationGroupCleanupIteratorPrototype);
assert.sameValue(
proto, IteratorPrototype,
'[[Prototype]] internal slot whose value is the intrinsic object %IteratorPrototype%'
);
assert.sameValue(called, 1, 'cleanup successful');
assert.sameValue(cleanupCallbackCalled, 0, 'if a callback is given, do not call cleanupCallback');
var proto = Object.getPrototypeOf(FinalizationGroupCleanupIteratorPrototype);
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

@ -26,7 +26,8 @@ info: |
a. Set cell.[[Target]] to empty.
b. Optionally, perform ! HostCleanupFinalizationGroup(fg).
features: [FinalizationGroup, async-functions, host-gc-required]
flags: [async]
flags: [async, non-deterministic]
includes: [async-gc.js]
---*/
var cleanupCallback = 0;
@ -44,17 +45,15 @@ var fg = new FinalizationGroup(function() {
});
function emptyCells() {
(function() {
var a = {};
fg.register(a, 'a');
})();
var target = {};
fg.register(target, 'a');
// GC is called here
$262.gc();
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells();
// Let's add some async ticks, as the cleanupCallback is not meant to interrupt
// synchronous operations.
async function fn() {
@ -76,7 +75,7 @@ async function fn() {
// callback is not called again.
cleanupCallback = 0;
$262.gc();
await $262.gc();
await Promise.resolve(2); // tick
fg.cleanupSome(cb);
@ -86,7 +85,7 @@ async function fn() {
assert.sameValue(called, 2, 'cleanupSome callback for the second time');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #1');
$262.gc();
await $262.gc();
await Promise.resolve(3); // tick
fg.cleanupSome(cb);
@ -94,11 +93,12 @@ async function fn() {
assert.sameValue(called, 3, 'cleanupSome callback for the third time');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #2');
$262.gc();
await $262.gc();
}
fn()
.then(async function() { // tick
emptyCells()
.then(async function() {
await fn();// tick
await Promise.resolve(4); // tick
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #3');
@ -108,7 +108,7 @@ fn()
assert.sameValue(called, 4, 'cleanupSome callback for the fourth time');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #4');
$262.gc();
await $262.gc();
// Now we are exhausting the iterator, so cleanupSome callback will also not be called.
fg.cleanupSome(iterator => {
@ -121,7 +121,7 @@ fn()
assert.sameValue(called, 5, 'cleanupSome callback for the fifth time');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #4');
$262.gc();
await $262.gc();
await Promise.resolve(5); // tick
await await Promise.resolve(6); // more ticks
@ -132,4 +132,4 @@ fn()
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, $DONE);
.then($DONE, resolveAsyncGC);

View File

@ -48,6 +48,8 @@ info: |
6. Set iterator.[[FinalizationGroup]] to finalizationGroup.
7. Return iterator.
features: [FinalizationGroup, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
@ -65,23 +67,32 @@ var fg = new FinalizationGroup(function() {
cleanupCallbackCalled += 1;
});
(function() {
let o = {};
fg.register(o);
})();
async function register() {
var target = {};
fg.register(target);
var prom = asyncGC(target);
target = null;
assert.sameValue(called, 0); // never called in sync execution
assert.sameValue(called, 0);
return prom;
}
$262.gc();
fg.cleanupSome(callback);
register()
.then(function() {
// We can't observe if the cleanupCallback was called, but we can make sure cleanupSome won't call it.
cleanupCallbackCalled = 0;
assert.sameValue(called, 1);
fg.cleanupSome(callback);
var proto = Object.getPrototypeOf(FinalizationGroupCleanupIteratorPrototype);
assert.sameValue(
proto, IteratorPrototype,
'[[Prototype]] internal slot whose value is the intrinsic object %IteratorPrototype%'
);
assert.sameValue(called, 1);
var proto = Object.getPrototypeOf(FinalizationGroupCleanupIteratorPrototype);
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');
assert.sameValue(cleanupCallbackCalled, 0, 'if a callback is given, do not call cleanupCallback');
})
.then($DONE, resolveAsyncGC);

View File

@ -14,6 +14,8 @@ info: |
5. Perform ? CleanupFinalizationGroup(finalizationGroup, callback).
6. Return undefined.
features: [FinalizationGroup, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var holdingsList;
@ -22,27 +24,24 @@ function cb(iterator) {
};
var fg = new FinalizationGroup(function() {});
var referenced = {};
function emptyCells() {
var x;
(function() {
var a = {};
b = {};
x = {};
var y = {};
fg.register(x, 'x');
fg.register(a, 'a');
fg.register(y, y);
fg.register(b, 'b');
var b;
})();
$262.gc();
x; // This is an intentional reference to x, please leave it here, after the GC
var target = {};
fg.register(target, 'target!');
fg.register(referenced, 'referenced');
var prom = asyncGC(target, referenced);
target = null;
return prom;
}
emptyCells();
fg.cleanupSome(cb);
emptyCells().then(function() {
fg.cleanupSome(cb);
// The order is per implementation so we can't use compareArray without sorting
assert.sameValue(holdingsList.length, 2);
assert(holdingsList.includes('a'));
assert(holdingsList.includes('b'));
assert.sameValue(holdingsList.length, 1);
assert.sameValue(holdingsList[0], 'target!');
assert.sameValue(typeof referenced, 'object', 'referenced preserved');
}).then($DONE, resolveAsyncGC);

View File

@ -23,66 +23,31 @@ info: |
ii. Set removed to true.
3. Return removed.
features: [FinalizationGroup, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var holdingsList;
var called = 0;
var fg = new FinalizationGroup(function() {});
var unregA = {};
var unregB = {};
var unregC = {};
var unregDE = {}; // Use the same unregister token for D and E
function emptyCells() {
(function() {
var a = {};
var b = {};
var c = {};
var d = {};
var e = {};
fg.register(a, 'a', unregA);
fg.register(b, 'b', unregB);
fg.register(c, 'c', unregC);
fg.register(d, 'd', unregDE);
fg.register(e, 'e', unregDE);
})();
var target = {};
var token = {};
fg.register(target, 'target!', token);
var res = fg.unregister(unregC); // unregister 'c' before GC
assert.sameValue(res, true, 'unregister c before GC');
var prom = asyncGC(target);
target = null;
$262.gc();
var res = fg.unregister(token);
assert.sameValue(res, true, 'unregister target before iterating over it in cleanup');
return prom;
}
emptyCells();
var res = fg.unregister(unregDE);
assert.sameValue(res, true, 'unregister d and e after GC');
fg.cleanupSome(function cb(iterator) {
var res = fb.unregister(unregA);
assert.sameValue(res, true, 'unregister a before the iterator is consumed.');
holdingsList = [...iterator];
// It's not possible to verify an unregister during the iterator consumption
// as it's .next() does not have any specific order to follow for each item.
});
assert.sameValue(holdingsList[0], 'b');
assert.sameValue(holdingsList.length, 1);
// Second run
res = fg.unregister(unregB); // let's empty the cells
assert.sameValue(res, true, 'unregister B for cleanup');
holdingsList = undefined;
emptyCells();
fg.cleanupSome(function cb(iterator) {
var res = fb.unregister(unregDE);
assert.sameValue(res, true, 'unregister d and e before the iterator is consumed.');
holdingsList = [...iterator];
});
assert(holdingsList.includes('b'));
assert(holdingsList.includes('a'), 'just like the first run, now without removing a');
assert.sameValue(holdingsList.length, 2);
emptyCells().then(function() {
fg.cleanupSome(function cb(iterator) {
called += 1;
});
assert.sameValue(called, 0, 'callback was not called');
}).then($DONE, resolveAsyncGC);

View File

@ -48,6 +48,8 @@ info: |
6. Set iterator.[[FinalizationGroup]] to finalizationGroup.
7. Return iterator.
features: [FinalizationGroup, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
@ -60,23 +62,25 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
}
var fg = new FinalizationGroup(callback);
var fg = new FinalizationGroup(function() {});
(function() {
let o = {};
fg.register(o);
})();
function emptyCells() {
var target = {};
fg.register(target);
assert.sameValue(called, 0);
var prom = asyncGC(target);
target = null;
$262.gc();
fg.cleanupSome();
return prom;
}
assert.sameValue(called, 1);
var proto = Object.getPrototypeOf(FinalizationGroupCleanupIteratorPrototype);
assert.sameValue(
proto, IteratorPrototype,
'[[Prototype]] internal slot whose value is the intrinsic object %IteratorPrototype%'
);
emptyCells().then(function() {
fg.cleanupSome(callback);
assert.sameValue(called, 1);
var proto = Object.getPrototypeOf(FinalizationGroupCleanupIteratorPrototype);
assert.sameValue(
proto, IteratorPrototype,
'[[Prototype]] internal slot whose value is the intrinsic object %IteratorPrototype%'
);
}).then($DONE, resolveAsyncGC);

View File

@ -1,51 +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-group.prototype.cleanupSome
description: WeakRef deref should not prevent a GC event
info: |
FinalizationGroup.prototype.cleanupSome ( [ callback ] )
...
4. If callback is not undefined and IsCallable(callback) is false, throw a TypeError exception.
5. Perform ? CleanupFinalizationGroup(finalizationGroup, callback).
6. Return undefined.
WeakRef.prototype.deref ( )
...
4. Let target be the value of weakRef.[[Target]].
5. If target is not empty,
a. Perform ! KeepDuringJob(target).
b. Return target.
6. Return undefined.
features: [FinalizationGroup, WeakRef, host-gc-required]
---*/
var holdingsList;
function cb(iterator) {
holdingsList = [...iterator];
}
var fg = new FinalizationGroup(function() {});
var deref = false;
function emptyCells() {
var wr;
(function() {
var a = {};
wr = new WeakRef(a);
fg.register(a, 'a');
})();
$262.gc();
deref = wr.deref();
}
emptyCells();
fg.cleanupSome(cb);
assert.sameValue(holdingsList.length, 1);
assert.sameValue(holdingsList[0], 'a');
assert.sameValue(deref, undefined, 'deref handles an empty wearRef.[[Target]] returning undefined');

View File

@ -29,6 +29,8 @@ info: |
c. Return CreateIterResultObject(cell.[[Holdings]], false).
9. Otherwise, return CreateIterResultObject(undefined, true).
features: [FinalizationGroup, host-gc-required, Symbol]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var called = 0;
@ -67,32 +69,38 @@ function callback(iterator) {
endOfCall += 1;
}
(function() {
function emptyCells() {
var o1 = {};
var o2 = {};
fg.register(o1, 'holdings 1');
fg.register(o2, 'holdings 2');
})();
$262.gc();
var prom = asyncGC(o1, o2);
o1 = null;
o2 = null;
fg.cleanupSome(callback);
return prom;
}
// Make sure everything is set
assert.sameValue(called, 4, 'cleanup successfully');
assert.sameValue(endOfCall, 4, 'cleanup ended successfully');
emptyCells().then(function() {
fg.cleanupSome(callback);
assert.notSameValue(firstIter, secondIter, 'callback is not called with the same iterator #1');
assert.notSameValue(firstIter, thirdIter, 'callback is not called with the same iterator #2');
assert.notSameValue(secondIter, thirdIter, 'callback is not called with the same iterator #3');
assert.sameValue(first.value, undefined, 'iterator is already consumed');
assert.sameValue(first.done, true, 'first callback will find no empty Targets');
assert.sameValue(second.done, false, 'second callback will find an empty Target');
assert.sameValue(third.done, false, 'third callback will find an empty Target');
// 8.a. Choose any such cell.
var holdings = [second.value, third.value];
assert(holdings.includes('holdings 1'), 'iterators consume emptied cells #1');
assert(holdings.includes('holdings 2'), 'iterators consume emptied cells #2');
// Make sure everything is set
assert.sameValue(called, 4, 'cleanup successfully');
assert.sameValue(endOfCall, 4, 'cleanup ended successfully');
assert.notSameValue(firstIter, secondIter, 'callback is not called with the same iterator #1');
assert.notSameValue(firstIter, thirdIter, 'callback is not called with the same iterator #2');
assert.notSameValue(secondIter, thirdIter, 'callback is not called with the same iterator #3');
assert.sameValue(first.value, undefined, 'iterator is already consumed');
assert.sameValue(first.done, true, 'first callback will find no empty Targets');
assert.sameValue(second.done, false, 'second callback will find an empty Target');
assert.sameValue(third.done, false, 'third callback will find an empty Target');
// 8.a. Choose any such cell.
var holdings = [second.value, third.value];
assert(holdings.includes('holdings 1'), 'iterators consume emptied cells #1');
assert(holdings.includes('holdings 2'), 'iterators consume emptied cells #2');
}).then($DONE, resolveAsyncGC);

View File

@ -29,88 +29,46 @@ info: |
c. Return CreateIterResultObject(cell.[[Holdings]], false).
9. Otherwise, return CreateIterResultObject(undefined, true).
features: [FinalizationGroup, Symbol, host-gc-required]
includes: [compareArray.js]
includes: [compareArray.js, async-gc.js]
flags: [async, non-deterministic]
---*/
var holdings;
var fg = new FinalizationGroup(function() {});
function check(value, expectedName) {
var holdings;
var called = 0;
var fg = new FinalizationGroup(function() {});
function callback(iterator) {
holdings = [...iterator];
function callback(iterator) {
called += 1;
holdings = [...iterator];
}
// This is internal to avoid conflicts
function emptyCells(value) {
var target = {};
fg.register(target, value);
var prom = asyncGC(target);
target = null;
return prom;
}
return emptyCells(value).then(function() {
fg.cleanupSome(callback);
assert.sameValue(called, 1, expectedName);
assert.sameValue(holdings.length, 1, expectedName);
assert.sameValue(holdings[0], value, expectedName);
});
}
(function() {
var o = {};
fg.register(o);
fg.register(o, undefined);
})();
$262.gc();
fg.cleanupSome(callback);
assert.compareArray(holdings, [undefined, undefined], 'undefined');
(function() {
var o = {};
fg.register(o, null);
})();
$262.gc();
fg.cleanupSome(callback);
assert.compareArray(holdings, [null], 'null');
(function() {
var o = {};
fg.register(o, '');
})();
$262.gc();
fg.cleanupSome(callback);
assert.compareArray(holdings, [''], 'the empty string');
var other = {};
(function() {
var o = {};
fg.register(o, other);
})();
$262.gc();
fg.cleanupSome(callback);
assert.compareArray(holdings, [other], '{}');
(function() {
var o = {};
fg.register(o, 42);
})();
$262.gc();
fg.cleanupSome(callback);
assert.compareArray(holdings, [42], '42');
(function() {
var o = {};
fg.register(o, true);
})();
$262.gc();
fg.cleanupSome(callback);
assert.compareArray(holdings, [true], 'true');
(function() {
var o = {};
fg.register(o, false);
})();
$262.gc();
fg.cleanupSome(callback);
assert.compareArray(holdings, [false], 'false');
var s = Symbol();
(function() {
var o = {};
fg.register(o, s);
})();
$262.gc();
fg.cleanupSome(callback);
assert.compareArray(holdings, [s], 'symbol');
Promise.all([
check(undefined, 'undefined'),
check(null, 'null'),
check('', 'the empty string'),
check({}, 'object'),
check(42, 'number'),
check(true, 'true'),
check(false, 'false'),
check(Symbol(1), 'symbol'),
]).then(() => $DONE(), resolveAsyncGC);

View File

@ -22,37 +22,41 @@ info: |
7. Set finalizationGroup.[[IsFinalizationGroupCleanupJobActive]] to false.
8. If result is an abrupt completion, return result.
features: [FinalizationGroup, arrow-function, async-functions, async-iteration, class, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var called = 0;
var iterator;
var iterator = false;
function poisoned(iter) {
called += 1;
iterator = iter;
iter.next(); // Won't throw
throw new Test262Error();
}
var fg = new FinalizationGroup(function() {
called += 1;
});
var fg = new FinalizationGroup(function() {});
function emptyCells() {
(function() {
var o = {};
fg.register(o);
})();
$262.gc();
var target = {};
fg.register(target);
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells();
emptyCells().then(function() {
assert.throws(Test262Error, function() {
fg.cleanupSome(poisoned);
});
assert.sameValue(called, 1);
assert.throws(Test262Error, function() {
fg.cleanupSome(poisoned);
});
assert.sameValue(called, 0);
assert.sameValue(typeof iteraror.next, 'function');
assert.throws(TypeError, function() {
iterator.next();
}, 'iterator.next throws a TypeError if IsFinalizationGroupCleanupJobActive is false');
assert.sameValue(typeof iterator, 'object');
assert.sameValue(typeof iteraror.next, 'function');
assert.throws(TypeError, function() {
iterator.next();
}, 'iterator.next throws a TypeError if IsFinalizationGroupCleanupJobActive is false');
}).then($DONE, resolveAsyncGC);

View File

@ -1,52 +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-group.prototype.cleanupSome
description: Return abrupt completion from CleanupFinalizationGroup (using CleanupCallback)
info: |
FinalizationGroup.prototype.cleanupSome ( [ callback ] )
1. Let finalizationGroup be the this value.
2. If Type(finalizationGroup) is not Object, throw a TypeError exception.
3. If finalizationGroup 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 ? CleanupFinalizationGroup(finalizationGroup, callback).
6. Return undefined.
CleanupFinalizationGroup ( finalizationGroup [ , callback ] )
4. If callback is undefined, set callback to finalizationGroup.[[CleanupCallback]].
5. Set finalizationGroup.[[IsFinalizationGroupCleanupJobActive]] to true.
6. Let result be Call(callback, undefined, « iterator »).
7. Set finalizationGroup.[[IsFinalizationGroupCleanupJobActive]] to false.
8. If result is an abrupt completion, return result.
features: [FinalizationGroup, arrow-function, async-functions, async-iteration, class, host-gc-required]
---*/
var iterator;
function poisoned(iter) {
iterator = iter;
iter.next(); // Won't throw
throw new Test262Error();
}
var fg = new FinalizationGroup(poisoned);
function emptyCells() {
(function() {
var o = {};
fg.register(o);
})();
$262.gc();
}
emptyCells();
assert.throws(Test262Error, function() {
fg.cleanupSome();
});
assert.sameValue(typeof iteraror.next, 'function');
assert.throws(TypeError, function() {
iterator.next();
}, 'iterator.next throws a TypeError if IsFinalizationGroupCleanupJobActive is false');

View File

@ -14,6 +14,8 @@ info: |
5. Perform ? CleanupFinalizationGroup(finalizationGroup, callback).
6. Return undefined.
features: [FinalizationGroup, arrow-function, async-functions, async-iteration, class, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var called;
@ -28,42 +30,55 @@ var cb = function() {
var fg = new FinalizationGroup(fn);
function emptyCells() {
called = 0;
(function() {
var o = {};
fg.register(o);
})();
$262.gc();
var target = {};
fg.register(target);
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells();
assert.sameValue(fg.cleanupSome(cb), undefined, 'regular callback');
assert.sameValue(called, 1);
var tests = [];
emptyCells();
assert.sameValue(fg.cleanupSome(fn), undefined, 'regular callback, same FG cleanup function');
assert.sameValue(called, 1);
tests.push(emptyCells().then(function() {
called = 0;
assert.sameValue(fg.cleanupSome(cb), undefined, 'regular callback');
assert.sameValue(called, 1);
}));
emptyCells();
assert.sameValue(fg.cleanupSome(() => 1), undefined, 'arrow function');
tests.push(emptyCells().then(function() {
called = 0;
assert.sameValue(fg.cleanupSome(fn), undefined, 'regular callback, same FG cleanup function');
assert.sameValue(called, 1);
}));
emptyCells();
assert.sameValue(fg.cleanupSome(fg.cleanupSome), undefined, 'cleanupSome itself');
tests.push(emptyCells().then(function() {
called = 0;
assert.sameValue(fg.cleanupSome(), undefined, 'undefined (implicit) callback, defer to FB callback');
assert.sameValue(called, 1);
}));
emptyCells();
assert.sameValue(fg.cleanupSome(class {}), undefined, 'class expression');
tests.push(emptyCells().then(function() {
called = 0;
assert.sameValue(fg.cleanupSome(undefined), undefined, 'undefined (explicit) callback, defer to FB callback');
assert.sameValue(called, 1);
}));
emptyCells();
assert.sameValue(fg.cleanupSome(async function() {}), undefined, 'async function');
tests.push(emptyCells().then(function() {
assert.sameValue(fg.cleanupSome(() => 1), undefined, 'arrow function');
}));
emptyCells();
assert.sameValue(fg.cleanupSome(function *() {}), undefined, 'generator');
tests.push(emptyCells().then(function() {
assert.sameValue(fg.cleanupSome(async function() {}), undefined, 'async function');
}));
emptyCells();
assert.sameValue(fg.cleanupSome(async function *() {}), undefined, 'async generator');
tests.push(emptyCells().then(function() {
assert.sameValue(fg.cleanupSome(function *() {}), undefined, 'generator');
}));
emptyCells();
assert.sameValue(fg.cleanupSome(), undefined, 'undefined, implicit');
tests.push(emptyCells().then(function() {
assert.sameValue(fg.cleanupSome(async function *() {}), undefined, 'async generator');
}));
emptyCells();
assert.sameValue(fg.cleanupSome(undefined), undefined, 'undefined, explicit');
Promise.all(tests).then(() => { $DONE(); }, resolveAsyncGC);

View File

@ -14,20 +14,24 @@ info: |
b. Return target.
6. Return undefined.
features: [WeakRef, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/
var deref = false;
function emptyCells() {
var wr;
(function() {
var a = {};
wr = new WeakRef(a);
})();
$262.gc();
deref = wr.deref();
var target = {};
wr = new WeakRef(target);
var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells();
assert.sameValue(deref, undefined);
emptyCells().then(function() {
deref = wr.deref();
assert.sameValue(deref, undefined);
}).then($DONE, resolveAsyncGC);