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". 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 }. This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
includes: [propertyHelper.js]
features: [FinalizationGroup, host-gc-required, Symbol, Symbol.toStringTag] features: [FinalizationGroup, host-gc-required, Symbol, Symbol.toStringTag]
includes: [async-gc.js, propertyHelper.js]
flags: [async, non-deterministic]
---*/ ---*/
var FinalizationGroupCleanupIteratorPrototype; var FinalizationGroupCleanupIteratorPrototype;
@ -39,13 +40,17 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator); FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
} }
(function() { function emptyCells() {
var o = {}; var target = {};
fg.register(o); fg.register(target);
})();
$262.gc(); var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
fg.cleanupSome(callback); fg.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful'); assert.sameValue(called, 1, 'cleanup successful');
@ -56,3 +61,4 @@ verifyProperty(FinalizationGroupCleanupIteratorPrototype, Symbol.toStringTag, {
enumerable: false, enumerable: false,
configurable: true configurable: true
}); });
}).then($DONE, resolveAsyncGC);

View File

@ -29,6 +29,8 @@ info: |
2. If Type(iterator) is not Object, throw a TypeError exception. 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. 3. If iterator does not have a [[FinalizationGroup]] internal slot, throw a TypeError exception.
features: [FinalizationGroup, WeakRef, host-gc-required, Symbol] features: [FinalizationGroup, WeakRef, host-gc-required, Symbol]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/ ---*/
var iter; var iter;
@ -42,13 +44,17 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator); FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
} }
(function() { function emptyCells() {
var o = {}; var target = {};
fg.register(o); fg.register(target, 'target');
})();
$262.gc(); var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
fg.cleanupSome(callback); fg.cleanupSome(callback);
// Make sure everything is set // Make sure everything is set
@ -60,3 +66,4 @@ assert.sameValue(Object.getPrototypeOf(iter), FinalizationGroupCleanupIteratorPr
assert.throws(TypeError, function() { assert.throws(TypeError, function() {
iter.next(); iter.next();
}, 'Iter should fail if not called during the cleanupSome call'); }, '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 Unless otherwise specified, the length property of a built-in
function object has the attributes { [[Writable]]: false, function object has the attributes { [[Writable]]: false,
[[Enumerable]]: false, [[Configurable]]: true }. [[Enumerable]]: false, [[Configurable]]: true }.
includes: [propertyHelper.js] includes: [async-gc.js, propertyHelper.js]
flags: [async, non-deterministic]
features: [FinalizationGroup, host-gc-required, Symbol] features: [FinalizationGroup, host-gc-required, Symbol]
---*/ ---*/
@ -47,24 +48,27 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator); FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
} }
(function() { function emptyCells() {
var o = {}; var target = {};
fg.register(o); fg.register(target);
})();
$262.gc(); var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
fg.cleanupSome(callback); fg.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful'); assert.sameValue(called, 1, 'cleanup successful');
assert.sameValue(typeof FinalizationGroupCleanupIteratorPrototype.next, 'function'); assert.sameValue(typeof FinalizationGroupCleanupIteratorPrototype.next, 'function');
var next = FinalizationGroupCleanupIteratorPrototype.next; verifyProperty(FinalizationGroupCleanupIteratorPrototype.next, 'length', {
verifyProperty(next, 'length', {
value: 0, value: 0,
enumerable: false, enumerable: false,
writable: false, writable: false,
configurable: true, configurable: true,
}); });
}).then($DONE, resolveAsyncGC);

View File

@ -27,6 +27,8 @@ info: |
2. If Type(iterator) is not Object, throw a TypeError exception. 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. 3. If iterator does not have a [[FinalizationGroup]] internal slot, throw a TypeError exception.
features: [FinalizationGroup, WeakRef, host-gc-required, Symbol] features: [FinalizationGroup, WeakRef, host-gc-required, Symbol]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/ ---*/
var FinalizationGroupCleanupIteratorPrototype; var FinalizationGroupCleanupIteratorPrototype;
@ -70,14 +72,19 @@ function callback(iterator) {
endOfCall += 1; endOfCall += 1;
} }
(function() { function emptyCells() {
var o = {}; var target = {};
fg.register(o); fg.register(target);
})();
$262.gc(); var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
fg.cleanupSome(callback); fg.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful'); assert.sameValue(called, 1, 'cleanup successful');
assert.sameValue(endOfCall, 1, 'Abrupt completions are not directly returned.'); 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 Unless otherwise specified, the name property of a built-in function
object, if it exists, has the attributes { [[Writable]]: false, object, if it exists, has the attributes { [[Writable]]: false,
[[Enumerable]]: false, [[Configurable]]: true }. [[Enumerable]]: false, [[Configurable]]: true }.
includes: [propertyHelper.js] includes: [async-gc.js, propertyHelper.js]
flags: [async, non-deterministic]
features: [FinalizationGroup, host-gc-required, Symbol] features: [FinalizationGroup, host-gc-required, Symbol]
---*/ ---*/
@ -46,13 +47,17 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator); FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
} }
(function() { function emptyCells() {
var o = {}; var target = {};
fg.register(o); fg.register(target);
})();
$262.gc(); var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
fg.cleanupSome(callback); fg.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful'); assert.sameValue(called, 1, 'cleanup successful');
@ -67,3 +72,4 @@ verifyProperty(next, 'name', {
writable: false, writable: false,
configurable: true, configurable: true,
}); });
}).then($DONE, resolveAsyncGC);

View File

@ -26,6 +26,8 @@ info: |
1. Let iterator be the this value. 1. Let iterator be the this value.
2. If Type(iterator) is not Object, throw a TypeError exception. 2. If Type(iterator) is not Object, throw a TypeError exception.
features: [FinalizationGroup, host-gc-required, Symbol] features: [FinalizationGroup, host-gc-required, Symbol]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/ ---*/
var FinalizationGroupCleanupIteratorPrototype; var FinalizationGroupCleanupIteratorPrototype;
@ -37,13 +39,17 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator); FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
} }
(function() { function emptyCells() {
var o = {}; var target = {};
fg.register(o); fg.register(target);
})();
$262.gc(); var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
fg.cleanupSome(callback); fg.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful'); assert.sameValue(called, 1, 'cleanup successful');
@ -80,3 +86,4 @@ var symbol = Symbol();
assert.throws(TypeError, function() { assert.throws(TypeError, function() {
next.call(symbol); next.call(symbol);
}, '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 Every other data property described in clauses 18 through 26 and in Annex B.2
has the attributes { [[Writable]]: true, [[Enumerable]]: false, has the attributes { [[Writable]]: true, [[Enumerable]]: false,
[[Configurable]]: true } unless otherwise specified. [[Configurable]]: true } unless otherwise specified.
includes: [propertyHelper.js] includes: [propertyHelper.js, async-gc.js]
flags: [async, non-deterministic]
features: [FinalizationGroup, host-gc-required, Symbol] features: [FinalizationGroup, host-gc-required, Symbol]
---*/ ---*/
@ -39,13 +40,17 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator); FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
} }
(function() { function emptyCells() {
var o = {}; var target = {};
fg.register(o); fg.register(target);
})();
$262.gc(); var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
fg.cleanupSome(callback); fg.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful'); assert.sameValue(called, 1, 'cleanup successful');
@ -59,3 +64,4 @@ verifyProperty(FinalizationGroupCleanupIteratorPrototype, 'next', {
writable: true, writable: true,
configurable: true, configurable: true,
}); });
}).then($DONE, resolveAsyncGC);

View File

@ -49,6 +49,8 @@ info: |
6. Set iterator.[[FinalizationGroup]] to finalizationGroup. 6. Set iterator.[[FinalizationGroup]] to finalizationGroup.
7. Return iterator. 7. Return iterator.
features: [FinalizationGroup, host-gc-required] features: [FinalizationGroup, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/ ---*/
var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
@ -64,13 +66,17 @@ function callback(iterator) {
var fg = new FinalizationGroup(function() {}); var fg = new FinalizationGroup(function() {});
(function() { function emptyCells() {
var o = {}; var target = {};
fg.register(o); fg.register(target);
})();
$262.gc(); var prom = asyncGC(target);
target = null;
return prom;
}
emptyCells().then(function() {
fg.cleanupSome(callback); fg.cleanupSome(callback);
assert.sameValue(called, 1, 'cleanup successful'); assert.sameValue(called, 1, 'cleanup successful');
@ -82,3 +88,4 @@ assert.sameValue(
); );
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

@ -26,7 +26,8 @@ info: |
a. Set cell.[[Target]] to empty. a. Set cell.[[Target]] to empty.
b. Optionally, perform ! HostCleanupFinalizationGroup(fg). b. Optionally, perform ! HostCleanupFinalizationGroup(fg).
features: [FinalizationGroup, async-functions, host-gc-required] features: [FinalizationGroup, async-functions, host-gc-required]
flags: [async] flags: [async, non-deterministic]
includes: [async-gc.js]
---*/ ---*/
var cleanupCallback = 0; var cleanupCallback = 0;
@ -44,17 +45,15 @@ var fg = new FinalizationGroup(function() {
}); });
function emptyCells() { function emptyCells() {
(function() { var target = {};
var a = {}; fg.register(target, 'a');
fg.register(a, 'a');
})();
// GC is called here var prom = asyncGC(target);
$262.gc(); target = null;
return prom;
} }
emptyCells();
// Let's add some async ticks, as the cleanupCallback is not meant to interrupt // Let's add some async ticks, as the cleanupCallback is not meant to interrupt
// synchronous operations. // synchronous operations.
async function fn() { async function fn() {
@ -76,7 +75,7 @@ async function fn() {
// callback is not called again. // callback is not called again.
cleanupCallback = 0; cleanupCallback = 0;
$262.gc(); await $262.gc();
await Promise.resolve(2); // tick await Promise.resolve(2); // tick
fg.cleanupSome(cb); fg.cleanupSome(cb);
@ -86,7 +85,7 @@ async function fn() {
assert.sameValue(called, 2, 'cleanupSome callback for the second time'); assert.sameValue(called, 2, 'cleanupSome callback for the second time');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #1'); assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #1');
$262.gc(); await $262.gc();
await Promise.resolve(3); // tick await Promise.resolve(3); // tick
fg.cleanupSome(cb); fg.cleanupSome(cb);
@ -94,11 +93,12 @@ async function fn() {
assert.sameValue(called, 3, 'cleanupSome callback for the third time'); assert.sameValue(called, 3, 'cleanupSome callback for the third time');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #2'); assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #2');
$262.gc(); await $262.gc();
} }
fn() emptyCells()
.then(async function() { // tick .then(async function() {
await fn();// tick
await Promise.resolve(4); // tick await Promise.resolve(4); // tick
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #3'); 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(called, 4, 'cleanupSome callback for the fourth time');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #4'); 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. // Now we are exhausting the iterator, so cleanupSome callback will also not be called.
fg.cleanupSome(iterator => { fg.cleanupSome(iterator => {
@ -121,7 +121,7 @@ fn()
assert.sameValue(called, 5, 'cleanupSome callback for the fifth time'); assert.sameValue(called, 5, 'cleanupSome callback for the fifth time');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #4'); assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #4');
$262.gc(); await $262.gc();
await Promise.resolve(5); // tick await Promise.resolve(5); // tick
await await Promise.resolve(6); // more ticks 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(called, 5, 'cleanupSome callback is not called anymore, no empty cells');
assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #5'); 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. 6. Set iterator.[[FinalizationGroup]] to finalizationGroup.
7. Return iterator. 7. Return iterator.
features: [FinalizationGroup, host-gc-required] features: [FinalizationGroup, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/ ---*/
var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
@ -65,14 +67,22 @@ var fg = new FinalizationGroup(function() {
cleanupCallbackCalled += 1; cleanupCallbackCalled += 1;
}); });
(function() { async function register() {
let o = {}; var target = {};
fg.register(o); fg.register(target);
})(); var prom = asyncGC(target);
assert.sameValue(called, 0); 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;
$262.gc();
fg.cleanupSome(callback); fg.cleanupSome(callback);
assert.sameValue(called, 1); assert.sameValue(called, 1);
@ -83,5 +93,6 @@ assert.sameValue(
'[[Prototype]] internal slot whose value is the intrinsic object %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). 5. Perform ? CleanupFinalizationGroup(finalizationGroup, callback).
6. Return undefined. 6. Return undefined.
features: [FinalizationGroup, host-gc-required] features: [FinalizationGroup, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/ ---*/
var holdingsList; var holdingsList;
@ -22,27 +24,24 @@ function cb(iterator) {
}; };
var fg = new FinalizationGroup(function() {}); var fg = new FinalizationGroup(function() {});
var referenced = {};
function emptyCells() { function emptyCells() {
var x; var target = {};
(function() { fg.register(target, 'target!');
var a = {}; fg.register(referenced, 'referenced');
b = {};
x = {}; var prom = asyncGC(target, referenced);
var y = {}; target = null;
fg.register(x, 'x');
fg.register(a, 'a'); return prom;
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
} }
emptyCells(); emptyCells().then(function() {
fg.cleanupSome(cb); fg.cleanupSome(cb);
// The order is per implementation so we can't use compareArray without sorting assert.sameValue(holdingsList.length, 1);
assert.sameValue(holdingsList.length, 2); assert.sameValue(holdingsList[0], 'target!');
assert(holdingsList.includes('a'));
assert(holdingsList.includes('b')); assert.sameValue(typeof referenced, 'object', 'referenced preserved');
}).then($DONE, resolveAsyncGC);

View File

@ -23,66 +23,31 @@ info: |
ii. Set removed to true. ii. Set removed to true.
3. Return removed. 3. Return removed.
features: [FinalizationGroup, host-gc-required] features: [FinalizationGroup, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/ ---*/
var holdingsList; var called = 0;
var fg = new FinalizationGroup(function() {}); 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 emptyCells() {
(function() { var target = {};
var a = {}; var token = {};
var b = {}; fg.register(target, 'target!', token);
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 res = fg.unregister(unregC); // unregister 'c' before GC var prom = asyncGC(target);
assert.sameValue(res, true, 'unregister c before GC'); target = null;
$262.gc(); var res = fg.unregister(token);
assert.sameValue(res, true, 'unregister target before iterating over it in cleanup');
return prom;
} }
emptyCells(); emptyCells().then(function() {
var res = fg.unregister(unregDE);
assert.sameValue(res, true, 'unregister d and e after GC');
fg.cleanupSome(function cb(iterator) { fg.cleanupSome(function cb(iterator) {
var res = fb.unregister(unregA); called += 1;
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(called, 0, 'callback was not called');
assert.sameValue(holdingsList.length, 1); }).then($DONE, resolveAsyncGC);
// 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);

View File

@ -48,6 +48,8 @@ info: |
6. Set iterator.[[FinalizationGroup]] to finalizationGroup. 6. Set iterator.[[FinalizationGroup]] to finalizationGroup.
7. Return iterator. 7. Return iterator.
features: [FinalizationGroup, host-gc-required] features: [FinalizationGroup, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/ ---*/
var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
@ -60,18 +62,20 @@ function callback(iterator) {
FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator); FinalizationGroupCleanupIteratorPrototype = Object.getPrototypeOf(iterator);
} }
var fg = new FinalizationGroup(callback); var fg = new FinalizationGroup(function() {});
(function() { function emptyCells() {
let o = {}; var target = {};
fg.register(o); fg.register(target);
})();
assert.sameValue(called, 0); var prom = asyncGC(target);
target = null;
$262.gc(); return prom;
fg.cleanupSome(); }
emptyCells().then(function() {
fg.cleanupSome(callback);
assert.sameValue(called, 1); assert.sameValue(called, 1);
var proto = Object.getPrototypeOf(FinalizationGroupCleanupIteratorPrototype); var proto = Object.getPrototypeOf(FinalizationGroupCleanupIteratorPrototype);
@ -79,4 +83,4 @@ assert.sameValue(
proto, IteratorPrototype, proto, IteratorPrototype,
'[[Prototype]] internal slot whose value is the intrinsic object %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). c. Return CreateIterResultObject(cell.[[Holdings]], false).
9. Otherwise, return CreateIterResultObject(undefined, true). 9. Otherwise, return CreateIterResultObject(undefined, true).
features: [FinalizationGroup, host-gc-required, Symbol] features: [FinalizationGroup, host-gc-required, Symbol]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/ ---*/
var called = 0; var called = 0;
@ -67,15 +69,20 @@ function callback(iterator) {
endOfCall += 1; endOfCall += 1;
} }
(function() { function emptyCells() {
var o1 = {}; var o1 = {};
var o2 = {}; var o2 = {};
fg.register(o1, 'holdings 1'); fg.register(o1, 'holdings 1');
fg.register(o2, 'holdings 2'); fg.register(o2, 'holdings 2');
})();
$262.gc(); var prom = asyncGC(o1, o2);
o1 = null;
o2 = null;
return prom;
}
emptyCells().then(function() {
fg.cleanupSome(callback); fg.cleanupSome(callback);
// Make sure everything is set // Make sure everything is set
@ -96,3 +103,4 @@ var holdings = [second.value, third.value];
assert(holdings.includes('holdings 1'), 'iterators consume emptied cells #1'); assert(holdings.includes('holdings 1'), 'iterators consume emptied cells #1');
assert(holdings.includes('holdings 2'), 'iterators consume emptied cells #2'); 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). c. Return CreateIterResultObject(cell.[[Holdings]], false).
9. Otherwise, return CreateIterResultObject(undefined, true). 9. Otherwise, return CreateIterResultObject(undefined, true).
features: [FinalizationGroup, Symbol, host-gc-required] features: [FinalizationGroup, Symbol, host-gc-required]
includes: [compareArray.js] includes: [compareArray.js, async-gc.js]
flags: [async, non-deterministic]
---*/ ---*/
function check(value, expectedName) {
var holdings; var holdings;
var called = 0;
var fg = new FinalizationGroup(function() {}); var fg = new FinalizationGroup(function() {});
function callback(iterator) { function callback(iterator) {
called += 1;
holdings = [...iterator]; holdings = [...iterator];
} }
(function() { // This is internal to avoid conflicts
var o = {}; function emptyCells(value) {
fg.register(o); var target = {};
fg.register(o, undefined); fg.register(target, value);
})();
$262.gc(); var prom = asyncGC(target);
target = null;
return prom;
}
return emptyCells(value).then(function() {
fg.cleanupSome(callback); fg.cleanupSome(callback);
assert.sameValue(called, 1, expectedName);
assert.sameValue(holdings.length, 1, expectedName);
assert.sameValue(holdings[0], value, expectedName);
});
}
assert.compareArray(holdings, [undefined, undefined], 'undefined'); Promise.all([
check(undefined, 'undefined'),
(function() { check(null, 'null'),
var o = {}; check('', 'the empty string'),
fg.register(o, null); check({}, 'object'),
})(); check(42, 'number'),
check(true, 'true'),
$262.gc(); check(false, 'false'),
fg.cleanupSome(callback); check(Symbol(1), 'symbol'),
assert.compareArray(holdings, [null], 'null'); ]).then(() => $DONE(), resolveAsyncGC);
(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');

View File

@ -22,37 +22,41 @@ info: |
7. Set finalizationGroup.[[IsFinalizationGroupCleanupJobActive]] to false. 7. Set finalizationGroup.[[IsFinalizationGroupCleanupJobActive]] to false.
8. If result is an abrupt completion, return result. 8. If result is an abrupt completion, return result.
features: [FinalizationGroup, arrow-function, async-functions, async-iteration, class, host-gc-required] features: [FinalizationGroup, arrow-function, async-functions, async-iteration, class, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/ ---*/
var called = 0; var called = 0;
var iterator; var iterator = false;
function poisoned(iter) { function poisoned(iter) {
called += 1;
iterator = iter; iterator = iter;
iter.next(); // Won't throw iter.next(); // Won't throw
throw new Test262Error(); throw new Test262Error();
} }
var fg = new FinalizationGroup(function() { var fg = new FinalizationGroup(function() {});
called += 1;
});
function emptyCells() { function emptyCells() {
(function() { var target = {};
var o = {}; fg.register(target);
fg.register(o);
})(); var prom = asyncGC(target);
$262.gc(); target = null;
return prom;
} }
emptyCells(); emptyCells().then(function() {
assert.throws(Test262Error, function() { assert.throws(Test262Error, function() {
fg.cleanupSome(poisoned); fg.cleanupSome(poisoned);
}); });
assert.sameValue(called, 0); assert.sameValue(called, 1);
assert.sameValue(typeof iterator, 'object');
assert.sameValue(typeof iteraror.next, 'function'); assert.sameValue(typeof iteraror.next, 'function');
assert.throws(TypeError, function() { assert.throws(TypeError, function() {
iterator.next(); iterator.next();
}, 'iterator.next throws a TypeError if IsFinalizationGroupCleanupJobActive is false'); }, '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). 5. Perform ? CleanupFinalizationGroup(finalizationGroup, callback).
6. Return undefined. 6. Return undefined.
features: [FinalizationGroup, arrow-function, async-functions, async-iteration, class, host-gc-required] features: [FinalizationGroup, arrow-function, async-functions, async-iteration, class, host-gc-required]
includes: [async-gc.js]
flags: [async, non-deterministic]
---*/ ---*/
var called; var called;
@ -28,42 +30,55 @@ var cb = function() {
var fg = new FinalizationGroup(fn); var fg = new FinalizationGroup(fn);
function emptyCells() { function emptyCells() {
called = 0; var target = {};
(function() { fg.register(target);
var o = {};
fg.register(o); var prom = asyncGC(target);
})(); target = null;
$262.gc();
return prom;
} }
emptyCells(); var tests = [];
tests.push(emptyCells().then(function() {
called = 0;
assert.sameValue(fg.cleanupSome(cb), undefined, 'regular callback'); assert.sameValue(fg.cleanupSome(cb), undefined, 'regular callback');
assert.sameValue(called, 1); assert.sameValue(called, 1);
}));
emptyCells(); tests.push(emptyCells().then(function() {
called = 0;
assert.sameValue(fg.cleanupSome(fn), undefined, 'regular callback, same FG cleanup function'); assert.sameValue(fg.cleanupSome(fn), undefined, 'regular callback, same FG cleanup function');
assert.sameValue(called, 1); assert.sameValue(called, 1);
}));
emptyCells(); tests.push(emptyCells().then(function() {
called = 0;
assert.sameValue(fg.cleanupSome(), undefined, 'undefined (implicit) callback, defer to FB callback');
assert.sameValue(called, 1);
}));
tests.push(emptyCells().then(function() {
called = 0;
assert.sameValue(fg.cleanupSome(undefined), undefined, 'undefined (explicit) callback, defer to FB callback');
assert.sameValue(called, 1);
}));
tests.push(emptyCells().then(function() {
assert.sameValue(fg.cleanupSome(() => 1), undefined, 'arrow function'); assert.sameValue(fg.cleanupSome(() => 1), undefined, 'arrow function');
}));
emptyCells(); tests.push(emptyCells().then(function() {
assert.sameValue(fg.cleanupSome(fg.cleanupSome), undefined, 'cleanupSome itself');
emptyCells();
assert.sameValue(fg.cleanupSome(class {}), undefined, 'class expression');
emptyCells();
assert.sameValue(fg.cleanupSome(async function() {}), undefined, 'async function'); assert.sameValue(fg.cleanupSome(async function() {}), undefined, 'async function');
}));
emptyCells(); tests.push(emptyCells().then(function() {
assert.sameValue(fg.cleanupSome(function *() {}), undefined, 'generator'); assert.sameValue(fg.cleanupSome(function *() {}), undefined, 'generator');
}));
emptyCells(); tests.push(emptyCells().then(function() {
assert.sameValue(fg.cleanupSome(async function *() {}), undefined, 'async generator'); assert.sameValue(fg.cleanupSome(async function *() {}), undefined, 'async generator');
}));
emptyCells(); Promise.all(tests).then(() => { $DONE(); }, resolveAsyncGC);
assert.sameValue(fg.cleanupSome(), undefined, 'undefined, implicit');
emptyCells();
assert.sameValue(fg.cleanupSome(undefined), undefined, 'undefined, explicit');

View File

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