diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/tests/test262/built-ins/FinalizationRegistry | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/tests/test262/built-ins/FinalizationRegistry')
73 files changed, 2750 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/browser.js b/js/src/tests/test262/built-ins/FinalizationRegistry/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/browser.js diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/constructor.js b/js/src/tests/test262/built-ins/FinalizationRegistry/constructor.js new file mode 100644 index 0000000000..56ba61b07a --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/constructor.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-constructor +description: > + The FinalizationRegistry constructor is the %FinalizationRegistry% intrinsic object and the initial + value of the FinalizationRegistry property of the global object. +features: [FinalizationRegistry] +---*/ + +assert.sameValue( + typeof FinalizationRegistry, 'function', + 'typeof FinalizationRegistry is function' +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/gc-has-one-chance-to-call-cleanupCallback-for-object.js b/js/src/tests/test262/built-ins/FinalizationRegistry/gc-has-one-chance-to-call-cleanupCallback-for-object.js new file mode 100644 index 0000000000..276574af63 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/gc-has-one-chance-to-call-cleanupCallback-for-object.js @@ -0,0 +1,97 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) async -- FinalizationRegistry is not enabled unconditionally +// 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-target +description: > + cleanupCallback has only one optional chance to be called for a GC that cleans + up a registered Object target. +info: | + FinalizationRegistry.prototype.cleanupSome ( [ _callback_ ] ) + 3. If _callback_ is present and IsCallable(_callback_) is *false*, throw a + *TypeError* exception. + 4. Perform ? CleanupFinalizationRegistry(_finalizationRegistry_, _callback_). + 5. Return *undefined*. + + Execution + + At any time, if a set of objects and/or symbols _S_ is not live, an ECMAScript + implementation may perform the following steps atomically: + + 1. For each element _value_ of _S_, do + ... + b. For each FinalizationRegistry _fg_ such that _fg_.[[Cells]] contains a + Record _cell_ such that _cell_.[[WeakRefTarget]] is _value_, + i. Set _cell_.[[WeakRefTarget]] to ~empty~. + ii. Optionally, perform HostEnqueueFinalizationRegistryCleanupJob(_fg_). +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry, async-functions, host-gc-required] +flags: [async, non-deterministic] +includes: [async-gc.js, compareArray.js] +---*/ + +let cleanupCallback = 0; +let holdings = []; +function cb(holding) { + holdings.push(holding); +} + +let finalizationRegistry = new FinalizationRegistry(function() { + cleanupCallback += 1; +}); + +function emptyCells() { + let target = {}; + finalizationRegistry.register(target, 'a'); + + let prom = asyncGC(target); + target = null; + + return prom; +} + +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(holdings.length, 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 + // for the other executions of the Garbage Collector. + // The chance of having it called only happens right after the + // cell.[[WeakRefTarget]] is set to empty. + 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. + cleanupCallback = 0; + + await $262.gc(); + await Promise.resolve(2); // tick + + finalizationRegistry.cleanupSome(cb); + + assert.sameValue(holdings.length, expectedCalled, 'cleanupSome callback is not called anymore, no empty cells'); + assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #1'); + + await $262.gc(); + await Promise.resolve(3); // tick + + finalizationRegistry.cleanupSome(cb); + + assert.sameValue(holdings.length, expectedCalled, 'cleanupSome callback is not called again #2'); + assert.sameValue(cleanupCallback, 0, 'cleanupCallback is not called again #2'); + + if (holdings.length) { + assert.compareArray(holdings, ['a']); + } + + await $262.gc(); +}).then($DONE, resolveAsyncGC); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/instance-extensible.js b/js/src/tests/test262/built-ins/FinalizationRegistry/instance-extensible.js new file mode 100644 index 0000000000..b8e9fb09ce --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/instance-extensible.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-target +description: Instances of FinalizationRegistry are extensible +info: | + FinalizationRegistry ( cleanupCallback ) + + ... + 3. Let finalizationRegistry be ? OrdinaryCreateFromConstructor(NewTarget, "%FinalizationRegistryPrototype%", « [[Realm]], [[CleanupCallback]], [[Cells]], [[IsFinalizationRegistryCleanupJobActive]] »). + ... + 9. Return finalizationRegistry. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + ObjectCreate ( proto [ , internalSlotsList ] ) + + 4. Set obj.[[Prototype]] to proto. + 5. Set obj.[[Extensible]] to true. + 6. Return obj. +features: [FinalizationRegistry] +---*/ + +var finalizationRegistry = new FinalizationRegistry(function() {}); +assert.sameValue(Object.isExtensible(finalizationRegistry), true); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/is-a-constructor.js b/js/src/tests/test262/built-ins/FinalizationRegistry/is-a-constructor.js new file mode 100644 index 0000000000..bcd6332ff8 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/is-a-constructor.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-ecmascript-standard-built-in-objects +description: > + The FinalizationRegistry constructor implements [[Construct]] +info: | + IsConstructor ( argument ) + + The abstract operation IsConstructor takes argument argument (an ECMAScript language value). + It determines if argument is a function object with a [[Construct]] internal method. + It performs the following steps when called: + + If Type(argument) is not Object, return false. + If argument has a [[Construct]] internal method, return true. + Return false. +includes: [isConstructor.js] +features: [Reflect.construct, FinalizationRegistry, arrow-function] +---*/ + +assert.sameValue(isConstructor(FinalizationRegistry), true, 'isConstructor(FinalizationRegistry) must return true'); +new FinalizationRegistry(() => {}); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/length.js b/js/src/tests/test262/built-ins/FinalizationRegistry/length.js new file mode 100644 index 0000000000..5ac6d2f0d8 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/length.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-target +description: FinalizationRegistry.length property descriptor +info: | + FinalizationRegistry ( cleanupCallback ) + + 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: [propertyHelper.js] +features: [FinalizationRegistry] +---*/ + +verifyProperty(FinalizationRegistry, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/name.js b/js/src/tests/test262/built-ins/FinalizationRegistry/name.js new file mode 100644 index 0000000000..4b0655b261 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/name.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-target +description: FinalizationRegistry.name property descriptor +info: | + FinalizationRegistry ( value ) + + 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: [propertyHelper.js] +features: [FinalizationRegistry] +---*/ + +verifyProperty(FinalizationRegistry, 'name', { + value: 'FinalizationRegistry', + writable: false, + enumerable: false, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/newtarget-prototype-is-not-object.js b/js/src/tests/test262/built-ins/FinalizationRegistry/newtarget-prototype-is-not-object.js new file mode 100644 index 0000000000..26b0e91221 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/newtarget-prototype-is-not-object.js @@ -0,0 +1,61 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-target +description: > + [[Prototype]] defaults to %FinalizationRegistryPrototype% if NewTarget.prototype is not an object. +info: | + FinalizationRegistry ( cleanupCallback ) + + ... + 3. Let finalizationRegistry be ? OrdinaryCreateFromConstructor(NewTarget, "%FinalizationRegistryPrototype%", « [[Realm]], [[CleanupCallback]], [[Cells]], [[IsFinalizationRegistryCleanupJobActive]] »). + ... + 9. Return finalizationRegistry. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). + 4. If Type(proto) is not Object, then + a. Let realm be ? GetFunctionRealm(constructor). + b. Set proto to realm's intrinsic object named intrinsicDefaultProto. + 5. Return proto. +features: [FinalizationRegistry, Reflect.construct, Symbol] +---*/ + +var finalizationRegistry; +function newTarget() {} +function fn() {} + +newTarget.prototype = undefined; +finalizationRegistry = Reflect.construct(FinalizationRegistry, [fn], newTarget); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), FinalizationRegistry.prototype, 'newTarget.prototype is undefined'); + +newTarget.prototype = null; +finalizationRegistry = Reflect.construct(FinalizationRegistry, [fn], newTarget); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), FinalizationRegistry.prototype, 'newTarget.prototype is null'); + +newTarget.prototype = true; +finalizationRegistry = Reflect.construct(FinalizationRegistry, [fn], newTarget); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), FinalizationRegistry.prototype, 'newTarget.prototype is a Boolean'); + +newTarget.prototype = ''; +finalizationRegistry = Reflect.construct(FinalizationRegistry, [fn], newTarget); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), FinalizationRegistry.prototype, 'newTarget.prototype is a String'); + +newTarget.prototype = Symbol(); +finalizationRegistry = Reflect.construct(FinalizationRegistry, [fn], newTarget); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), FinalizationRegistry.prototype, 'newTarget.prototype is a Symbol'); + +newTarget.prototype = 1; +finalizationRegistry = Reflect.construct(FinalizationRegistry, [fn], newTarget); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), FinalizationRegistry.prototype, 'newTarget.prototype is a Number'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prop-desc.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prop-desc.js new file mode 100644 index 0000000000..20510998d7 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prop-desc.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-constructor +description: > + Property descriptor of FinalizationRegistry +info: | + 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] +features: [FinalizationRegistry] +---*/ + +verifyProperty(this, 'FinalizationRegistry', { + enumerable: false, + writable: true, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/proto-from-ctor-realm.js b/js/src/tests/test262/built-ins/FinalizationRegistry/proto-from-ctor-realm.js new file mode 100644 index 0000000000..f2807a5cd2 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/proto-from-ctor-realm.js @@ -0,0 +1,62 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-target +description: Default [[Prototype]] value derived from realm of the newTarget +info: | + FinalizationRegistry ( cleanupCallback ) + + ... + 3. Let finalizationRegistry be ? OrdinaryCreateFromConstructor(NewTarget, "%FinalizationRegistryPrototype%", « [[Realm]], [[CleanupCallback]], [[Cells]], [[IsFinalizationRegistryCleanupJobActive]] »). + ... + 9. Return finalizationRegistry. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). + 4. If Type(proto) is not Object, then + a. Let realm be ? GetFunctionRealm(constructor). + b. Set proto to realm's intrinsic object named intrinsicDefaultProto. + 5. Return proto. +features: [FinalizationRegistry, cross-realm, Reflect, Symbol] +---*/ + +var other = $262.createRealm().global; +var newTarget = new other.Function(); +function fn() {} +var finalizationRegistry; + +newTarget.prototype = undefined; +finalizationRegistry = Reflect.construct(FinalizationRegistry, [fn], newTarget); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), other.FinalizationRegistry.prototype, 'newTarget.prototype is undefined'); + +newTarget.prototype = null; +finalizationRegistry = Reflect.construct(FinalizationRegistry, [fn], newTarget); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), other.FinalizationRegistry.prototype, 'newTarget.prototype is null'); + +newTarget.prototype = true; +finalizationRegistry = Reflect.construct(FinalizationRegistry, [fn], newTarget); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), other.FinalizationRegistry.prototype, 'newTarget.prototype is a Boolean'); + +newTarget.prototype = ''; +finalizationRegistry = Reflect.construct(FinalizationRegistry, [fn], newTarget); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), other.FinalizationRegistry.prototype, 'newTarget.prototype is a String'); + +newTarget.prototype = Symbol(); +finalizationRegistry = Reflect.construct(FinalizationRegistry, [fn], newTarget); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), other.FinalizationRegistry.prototype, 'newTarget.prototype is a Symbol'); + +newTarget.prototype = 1; +finalizationRegistry = Reflect.construct(FinalizationRegistry, [fn], newTarget); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), other.FinalizationRegistry.prototype, 'newTarget.prototype is a Number'); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/proto.js b/js/src/tests/test262/built-ins/FinalizationRegistry/proto.js new file mode 100644 index 0000000000..f9bf522ede --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/proto.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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 prototype of FinalizationRegistry is Object.prototype +info: | + The value of the [[Prototype]] internal slot of the FinalizationRegistry object is the + intrinsic object %FunctionPrototype%. +features: [FinalizationRegistry] +---*/ + +assert.sameValue( + Object.getPrototypeOf(FinalizationRegistry), + Function.prototype, + 'Object.getPrototypeOf(FinalizationRegistry) returns the value of `Function.prototype`' +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype-from-newtarget-abrupt.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype-from-newtarget-abrupt.js new file mode 100644 index 0000000000..c945b62544 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype-from-newtarget-abrupt.js @@ -0,0 +1,44 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-target +description: > + Return abrupt from getting the NewTarget prototype +info: | + FinalizationRegistry ( cleanupCallback ) + + ... + 3. Let finalizationRegistry be ? OrdinaryCreateFromConstructor(NewTarget, "%FinalizationRegistryPrototype%", « [[Realm]], [[CleanupCallback]], [[Cells]], [[IsFinalizationRegistryCleanupJobActive]] »). + ... + 9. Return finalizationRegistry. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). +features: [FinalizationRegistry, Reflect.construct] +---*/ + +var calls = 0; +var newTarget = function() {}.bind(null); +Object.defineProperty(newTarget, 'prototype', { + get: function() { + calls += 1; + throw new Test262Error(); + } +}); + +assert.throws(Test262Error, function() { + Reflect.construct(FinalizationRegistry, [function() {}], newTarget); +}); + +assert.sameValue(calls, 1); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype-from-newtarget-custom.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype-from-newtarget-custom.js new file mode 100644 index 0000000000..b31b87972e --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype-from-newtarget-custom.js @@ -0,0 +1,47 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-target +description: > + The [[Prototype]] internal slot is computed from NewTarget. +info: | + FinalizationRegistry ( cleanupCallback ) + + ... + 3. Let finalizationRegistry be ? OrdinaryCreateFromConstructor(NewTarget, "%FinalizationRegistryPrototype%", « [[Realm]], [[CleanupCallback]], [[Cells]], [[IsFinalizationRegistryCleanupJobActive]] »). + ... + 9. Return finalizationRegistry. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). + 4. If Type(proto) is not Object, then + a. Let realm be ? GetFunctionRealm(constructor). + b. Set proto to realm's intrinsic object named intrinsicDefaultProto. + 5. Return proto. +features: [FinalizationRegistry, Reflect.construct] +---*/ + +var finalizationRegistry; + +finalizationRegistry = Reflect.construct(FinalizationRegistry, [function() {}], Object); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), Object.prototype, 'NewTarget is built-in Object constructor'); + +var newTarget = function() {}.bind(null); +Object.defineProperty(newTarget, 'prototype', { + get: function() { + return Array.prototype; + } +}); +finalizationRegistry = Reflect.construct(FinalizationRegistry, [function() {}], newTarget); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), Array.prototype, 'NewTarget is BoundFunction with accessor'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype-from-newtarget.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype-from-newtarget.js new file mode 100644 index 0000000000..75b44ab7f4 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype-from-newtarget.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-target +description: > + The [[Prototype]] internal slot is computed from NewTarget. +info: | + FinalizationRegistry ( cleanupCallback ) + + ... + 3. Let finalizationRegistry be ? OrdinaryCreateFromConstructor(NewTarget, "%FinalizationRegistryPrototype%", « [[Realm]], [[CleanupCallback]], [[Cells]], [[IsFinalizationRegistryCleanupJobActive]] »). + ... + 9. Return finalizationRegistry. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). + + GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto ) + + 3. Let proto be ? Get(constructor, 'prototype'). + 4. If Type(proto) is not Object, then + a. Let realm be ? GetFunctionRealm(constructor). + b. Set proto to realm's intrinsic object named intrinsicDefaultProto. + 5. Return proto. +features: [FinalizationRegistry] +---*/ + +var finalizationRegistry = new FinalizationRegistry(function() {}); +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), FinalizationRegistry.prototype); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/Symbol.toStringTag.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/Symbol.toStringTag.js new file mode 100644 index 0000000000..e687cd8771 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/Symbol.toStringTag.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-@@tostringtag +description: > + `Symbol.toStringTag` property descriptor +info: | + The initial value of the @@toStringTag property is the String value + 'FinalizationRegistry'. + + This property has the attributes { [[Writable]]: false, [[Enumerable]]: + false, [[Configurable]]: true }. +includes: [propertyHelper.js] +features: [FinalizationRegistry, Symbol, Symbol.toStringTag] +---*/ + +verifyProperty(FinalizationRegistry.prototype, Symbol.toStringTag, { + value: 'FinalizationRegistry', + writable: false, + enumerable: false, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/browser.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/browser.js diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/browser.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/browser.js diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/callback-not-callable-throws.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/callback-not-callable-throws.js new file mode 100644 index 0000000000..2e8450b19e --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/callback-not-callable-throws.js @@ -0,0 +1,56 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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: Throws a TypeError if callback is not callable +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. + ... +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry] +---*/ + +assert.sameValue(typeof FinalizationRegistry.prototype.cleanupSome, 'function'); + +var finalizationRegistry = new FinalizationRegistry(function() {}); + +assert.throws(TypeError, function() { + finalizationRegistry.cleanupSome(null); +}, 'null'); + +assert.throws(TypeError, function() { + finalizationRegistry.cleanupSome(true); +}, 'true'); + +assert.throws(TypeError, function() { + finalizationRegistry.cleanupSome(false); +}, 'false'); + +assert.throws(TypeError, function() { + finalizationRegistry.cleanupSome(1); +}, 'number'); + +assert.throws(TypeError, function() { + finalizationRegistry.cleanupSome('object'); +}, 'string'); + +var s = Symbol(); +assert.throws(TypeError, function() { + finalizationRegistry.cleanupSome(s); +}, 'symbol'); + +assert.throws(TypeError, function() { + finalizationRegistry.cleanupSome({}); +}, 'object'); + +assert.throws(TypeError, function() { + finalizationRegistry.cleanupSome(FinalizationRegistry.prototype); +}, 'FinalizationRegistry.prototype'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/cleanup-prevented-with-reference.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/cleanup-prevented-with-reference.js new file mode 100644 index 0000000000..d8c23a7d1e --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/cleanup-prevented-with-reference.js @@ -0,0 +1,48 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) async -- FinalizationRegistry is not enabled unconditionally +// 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: Cleanup might be prevented with a reference usage; +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. +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry, host-gc-required] +includes: [async-gc.js] +flags: [async, non-deterministic] +---*/ + +var holdingsList = []; +function cb(holding) { + holdingsList.push(holding); +}; +var finalizationRegistry = new FinalizationRegistry(function() {}); + +var referenced = {}; + +function emptyCells() { + var target = {}; + finalizationRegistry.register(target, 'target!'); + finalizationRegistry.register(referenced, 'referenced'); + + var prom = asyncGC(target); + target = null; + + return prom; +} + +emptyCells().then(function() { + finalizationRegistry.cleanupSome(cb); + + assert.sameValue(holdingsList.length, 1); + assert.sameValue(holdingsList[0], 'target!'); + + assert.sameValue(typeof referenced, 'object', 'referenced preserved'); +}).then($DONE, resolveAsyncGC); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/cleanup-prevented-with-unregister.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/cleanup-prevented-with-unregister.js new file mode 100644 index 0000000000..6669be38b2 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/cleanup-prevented-with-unregister.js @@ -0,0 +1,55 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) async -- FinalizationRegistry is not enabled unconditionally +// 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: Cleanup might be prevented with an unregister usage +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. + + FinalizationRegistry.prototype.unregister ( unregisterToken ) + + 1. Let removed be false. + 2. For each Record { [[Target]], [[Holdings]], [[UnregisterToken]] } cell that is an element of finalizationRegistry.[[Cells]], do + a. If SameValue(cell.[[UnregisterToken]], unregisterToken) is true, then + i. Remove cell from finalizationRegistry.[[Cells]]. + ii. Set removed to true. + 3. Return removed. +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry, host-gc-required] +includes: [async-gc.js] +flags: [async, non-deterministic] +---*/ + +var token = {}; +var finalizationRegistry = new FinalizationRegistry(function() {}); + +function emptyCells() { + var target = {}; + finalizationRegistry.register(target, 'target!', token); + + var prom = asyncGC(target); + target = null; + + return prom; +} + +emptyCells().then(function() { + var called = 0; + + var res = finalizationRegistry.unregister(token); + assert.sameValue(res, true, 'unregister target before iterating over it in cleanup'); + + finalizationRegistry.cleanupSome(function cb(holding) { + called += 1; + }); + + assert.sameValue(called, 0, 'callback was not called'); +}).then($DONE, resolveAsyncGC); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/custom-this.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/custom-this.js new file mode 100644 index 0000000000..1b99dc1917 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/custom-this.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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 values applying custom this +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. +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry] +---*/ + +var fn = function() {}; +var cleanupSome = FinalizationRegistry.prototype.cleanupSome; +var finalizationRegistry = new FinalizationRegistry(fn); + +var cb = function() {}; + +assert.sameValue(cleanupSome.call(finalizationRegistry, cb), undefined); +assert.sameValue(cleanupSome.call(finalizationRegistry, fn), undefined), 'reuse the same cleanup callback fn'; + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/holdings-multiple-values.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/holdings-multiple-values.js new file mode 100644 index 0000000000..4c8d99b11a --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/holdings-multiple-values.js @@ -0,0 +1,70 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) async -- FinalizationRegistry is not enabled unconditionally +// 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: > + Iterates over different type values in holdings +info: | + FinalizationRegistry.prototype.cleanupSome ( [ callback ] ) + + 1. Let finalizationRegistry be the this value. + ... + 5. Perform ! CleanupFinalizationRegistry(finalizationRegistry, callback). + ... + + CleanupFinalizationRegistry ( finalizationRegistry [ , callback ] ) + + ... + 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. Perform ? Call(callback, undefined, << cell.[[HeldValue]] >>). + ... + + +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry, Symbol, host-gc-required] +includes: [async-gc.js] +flags: [async, non-deterministic] +---*/ + +function check(value, expectedName) { + var holdings = []; + var called = 0; + var finalizationRegistry = new FinalizationRegistry(function() {}); + + function callback(holding) { + called += 1; + holdings.push(holding); + } + + // This is internal to avoid conflicts + function emptyCells(value) { + var target = {}; + finalizationRegistry.register(target, value); + + var prom = asyncGC(target); + target = null; + + return prom; + } + + return emptyCells(value).then(function() { + finalizationRegistry.cleanupSome(callback); + assert.sameValue(called, 1, expectedName); + assert.sameValue(holdings.length, 1, expectedName); + assert.sameValue(holdings[0], value, expectedName); + }); +} + +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); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/length.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/length.js new file mode 100644 index 0000000000..797ecd5694 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/length.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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: FinalizationRegistry.prototype.cleanupSome.length property descriptor +info: | + FinalizationRegistry.prototype.cleanupSome ( [ callback ] ) + + 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: [propertyHelper.js] +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry] +---*/ + +verifyProperty(FinalizationRegistry.prototype.cleanupSome, 'length', { + value: 0, + writable: false, + enumerable: false, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/name.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/name.js new file mode 100644 index 0000000000..e71415a2c2 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/name.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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: FinalizationRegistry.prototype.cleanupSome.name property descriptor +info: | + FinalizationRegistry.prototype.cleanupSome.name value and property descriptor + + 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: [propertyHelper.js] +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry] +---*/ + +verifyProperty(FinalizationRegistry.prototype.cleanupSome, 'name', { + value: 'cleanupSome', + writable: false, + enumerable: false, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/not-a-constructor.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/not-a-constructor.js new file mode 100644 index 0000000000..12c979cc12 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/not-a-constructor.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-ecmascript-standard-built-in-objects +description: > + FinalizationRegistry.prototype.cleanupSome does not implement [[Construct]], is not new-able +info: | + ECMAScript Function Objects + + Built-in function objects that are not identified as constructors do not + implement the [[Construct]] internal method unless otherwise specified in + the description of a particular function. + + sec-evaluatenew + + ... + 7. If IsConstructor(constructor) is false, throw a TypeError exception. + ... +includes: [isConstructor.js] +features: [Reflect.construct, FinalizationRegistry, FinalizationRegistry.prototype.cleanupSome, arrow-function] +---*/ + +assert.sameValue( + isConstructor(FinalizationRegistry.prototype.cleanupSome), + false, + 'isConstructor(FinalizationRegistry.prototype.cleanupSome) must return false' +); + +assert.throws(TypeError, () => { + let fr = new FinalizationRegistry(() => {}); new fr.cleanupSome(() => {}); +}, '`let fr = new FinalizationRegistry(() => {}); new fr.cleanupSome(() => {})` throws TypeError'); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/prop-desc.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/prop-desc.js new file mode 100644 index 0000000000..f942e2c1a4 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/prop-desc.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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: > + Property descriptor of FinalizationRegistry.prototype.cleanupSome +info: | + 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] +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry] +---*/ + +assert.sameValue(typeof FinalizationRegistry.prototype.cleanupSome, 'function'); + +verifyProperty(FinalizationRegistry.prototype, 'cleanupSome', { + enumerable: false, + writable: true, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/reentrancy.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/reentrancy.js new file mode 100644 index 0000000000..ebecca0725 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/reentrancy.js @@ -0,0 +1,52 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) async -- FinalizationRegistry is not enabled unconditionally +// 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 cleanupSome() method can be reentered +info: | + FinalizationRegistry.prototype.cleanupSome ( [ callback ] ) + +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry, host-gc-required] +includes: [async-gc.js] +flags: [async, non-deterministic] +---*/ + +var called = 0; +var endOfCall = 0; +var finalizationRegistry = new FinalizationRegistry(function() {}); + +function callback(holding) { + called += 1; + + if (called === 1) { + // Atempt to re-enter the callback. + var nestedCallbackRan = false; + finalizationRegistry.cleanupSome(() => { nestedCallbackRan = true }); + assert.sameValue(nestedCallbackRan, true); + } + + endOfCall += 1; +} + +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; + + return prom; +} + +emptyCells().then(function() { + finalizationRegistry.cleanupSome(callback); + + assert.sameValue(called, 1, 'callback was called'); + assert.sameValue(endOfCall, 1, 'callback finished'); +}).then($DONE, resolveAsyncGC); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/return-undefined-with-gc.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/return-undefined-with-gc.js new file mode 100644 index 0000000000..ef1f04b0e7 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/return-undefined-with-gc.js @@ -0,0 +1,67 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) async -- FinalizationRegistry is not enabled unconditionally +// 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 undefined regardless the result of 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. +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry, arrow-function, async-functions, async-iteration, class, host-gc-required] +includes: [async-gc.js] +flags: [async, non-deterministic] +---*/ + +var called; +var fn = function() { + called += 1; + return 39; +}; +var cb = function() { + called += 1; + return 42; +}; +var finalizationRegistry = new FinalizationRegistry(fn); + +function emptyCells() { + var target = {}; + finalizationRegistry.register(target); + + var prom = asyncGC(target); + target = null; + + return prom; +} + +emptyCells().then(function() { + called = 0; + assert.sameValue(finalizationRegistry.cleanupSome(cb), undefined, 'regular callback'); + assert.sameValue(called, 1); +}).then(emptyCells).then(function() { + called = 0; + assert.sameValue(finalizationRegistry.cleanupSome(fn), undefined, 'regular callback, same FG cleanup function'); + assert.sameValue(called, 1); +}).then(emptyCells).then(function() { + called = 0; + assert.sameValue(finalizationRegistry.cleanupSome(), undefined, 'undefined (implicit) callback, defer to FB callback'); + assert.sameValue(called, 1); +}).then(emptyCells).then(function() { + called = 0; + assert.sameValue(finalizationRegistry.cleanupSome(undefined), undefined, 'undefined (explicit) callback, defer to FB callback'); + assert.sameValue(called, 1); +}).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'); +}).then(emptyCells).then(function() { + assert.sameValue(finalizationRegistry.cleanupSome(function *() {}), undefined, 'generator'); +}).then(emptyCells).then(function() { + assert.sameValue(finalizationRegistry.cleanupSome(async function *() {}), undefined, 'async generator'); +}).then($DONE, resolveAsyncGC); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/return-undefined.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/return-undefined.js new file mode 100644 index 0000000000..6a5ff5a6e5 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/return-undefined.js @@ -0,0 +1,44 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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 undefined regardless the result of 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. +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry, arrow-function, async-functions, async-iteration, class] +---*/ + +var fn = function() {}; +var cb = function() {}; +var poisoned = function() { throw new Test262Error(); }; +var finalizationRegistry = new FinalizationRegistry(fn); + +assert.sameValue(finalizationRegistry.cleanupSome(cb), undefined, 'regular callback'); +assert.sameValue(finalizationRegistry.cleanupSome(fn), undefined, 'regular callback, same FG cleanup function'); + +assert.sameValue(finalizationRegistry.cleanupSome(() => {}), undefined, 'arrow function'); +assert.sameValue(finalizationRegistry.cleanupSome(finalizationRegistry.cleanupSome), undefined, 'cleanupSome itself'); +assert.sameValue(finalizationRegistry.cleanupSome(poisoned), undefined, 'poisoned'); +assert.sameValue(finalizationRegistry.cleanupSome(class {}), undefined, 'class expression'); +assert.sameValue(finalizationRegistry.cleanupSome(async function() {}), undefined, 'async function'); +assert.sameValue(finalizationRegistry.cleanupSome(function *() {}), undefined, 'generator'); +assert.sameValue(finalizationRegistry.cleanupSome(async function *() {}), undefined, 'async generator'); + +assert.sameValue(finalizationRegistry.cleanupSome(), undefined, 'undefined, implicit'); +assert.sameValue(finalizationRegistry.cleanupSome(undefined), undefined, 'undefined, explicit'); + +var poisonedFg = new FinalizationRegistry(poisoned); + +assert.sameValue(poisonedFg.cleanupSome(cb), undefined, 'regular callback on poisoned FG cleanup callback'); +assert.sameValue(poisonedFg.cleanupSome(poisoned), undefined, 'poisoned callback on poisoned FG cleanup callback'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/shell.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/shell.js diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/this-does-not-have-internal-cells-throws.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/this-does-not-have-internal-cells-throws.js new file mode 100644 index 0000000000..267e6d3163 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/this-does-not-have-internal-cells-throws.js @@ -0,0 +1,51 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')||!this.hasOwnProperty('WeakRef')) -- FinalizationRegistry,WeakRef is not enabled unconditionally +// 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: Throws a TypeError if this does not have a [[Cells]] internal slot +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. + ... +features: [FinalizationRegistry.prototype.cleanupSome, WeakSet, WeakMap, FinalizationRegistry, WeakRef] +---*/ + +assert.sameValue(typeof FinalizationRegistry.prototype.cleanupSome, 'function'); + +var cleanupSome = FinalizationRegistry.prototype.cleanupSome; +var cb = function() {}; + +assert.throws(TypeError, function() { + cleanupSome.call({ ['[[Cells]]']: {} }, cb); +}, 'Ordinary object without [[Cells]]'); + +assert.throws(TypeError, function() { + cleanupSome.call(WeakRef.prototype, cb); +}, 'WeakRef.prototype does not have a [[Cells]] internal slot'); + +assert.throws(TypeError, function() { + cleanupSome.call(WeakRef, cb); +}, 'WeakRef does not have a [[Cells]] internal slot'); + +var wr = new WeakRef({}); +assert.throws(TypeError, function() { + cleanupSome.call(wr, cb); +}, 'WeakRef instance'); + +var wm = new WeakMap(); +assert.throws(TypeError, function() { + cleanupSome.call(wm, cb); +}, 'WeakMap instance'); + +var ws = new WeakSet(); +assert.throws(TypeError, function() { + cleanupSome.call(ws, cb); +}, 'WeakSet instance'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/this-not-object-throws.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/this-not-object-throws.js new file mode 100644 index 0000000000..0be9066201 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/this-not-object-throws.js @@ -0,0 +1,53 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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: Throws a TypeError if this is not an Object +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. + ... +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry] +---*/ + +assert.sameValue(typeof FinalizationRegistry.prototype.cleanupSome, 'function'); + +var cleanupSome = FinalizationRegistry.prototype.cleanupSome; +var cb = function() {}; + +assert.throws(TypeError, function() { + cleanupSome.call(undefined, cb); +}, 'undefined'); + +assert.throws(TypeError, function() { + cleanupSome.call(null, cb); +}, 'null'); + +assert.throws(TypeError, function() { + cleanupSome.call(true, cb); +}, 'true'); + +assert.throws(TypeError, function() { + cleanupSome.call(false, cb); +}, 'false'); + +assert.throws(TypeError, function() { + cleanupSome.call(1, cb); +}, 'number'); + +assert.throws(TypeError, function() { + cleanupSome.call('object', cb); +}, 'string'); + +var s = Symbol(); +assert.throws(TypeError, function() { + cleanupSome.call(s, cb); +}, 'symbol'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/constructor.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/constructor.js new file mode 100644 index 0000000000..3f83b2e752 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/constructor.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.constructor +description: FinalizationRegistry.prototype.constructor property descriptor +info: | + FinalizationRegistry.prototype.constructor + + The initial value of FinalizationRegistry.prototype.constructor is the intrinsic + object %FinalizationRegistry%. + + 17 ECMAScript Standard Built-in Objects +includes: [propertyHelper.js] +features: [FinalizationRegistry] +---*/ + +verifyProperty(FinalizationRegistry.prototype, 'constructor', { + value: FinalizationRegistry, + writable: true, + enumerable: false, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/prop-desc.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/prop-desc.js new file mode 100644 index 0000000000..9694e2d296 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/prop-desc.js @@ -0,0 +1,21 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// Copyright (C) 2019 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: The property descriptor FinalizationRegistry.prototype +esid: sec-finalization-registry.prototype +info: | + This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, + [[Configurable]]: false }. +features: [FinalizationRegistry] +includes: [propertyHelper.js] +---*/ + +verifyProperty(FinalizationRegistry, 'prototype', { + writable: false, + enumerable: false, + configurable: false +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/proto.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/proto.js new file mode 100644 index 0000000000..9a6c7fa310 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/proto.js @@ -0,0 +1,17 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// Copyright (C) 2019 Leo Balter. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: The prototype of FinalizationRegistry.prototype is Object.prototype +esid: sec-properties-of-the-finalization-registry-prototype-object +info: | + The value of the [[Prototype]] internal slot of the FinalizationRegistry prototype object + is the intrinsic object %ObjectPrototype%. +features: [FinalizationRegistry] +---*/ + +var proto = Object.getPrototypeOf(FinalizationRegistry.prototype); +assert.sameValue(proto, Object.prototype); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/browser.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/browser.js diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/custom-this.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/custom-this.js new file mode 100644 index 0000000000..fa1df025da --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/custom-this.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: Return undefined (applying custom this) +info: | + FinalizationRegistry.prototype.register ( target , holdings [, unregisterToken ] ) + + 1. Let finalizationRegistry be the this value. + 2. If Type(finalizationRegistry) is not Object, throw a TypeError exception. + 3. If Type(target) is not Object, throw a TypeError exception. + 4. If finalizationRegistry does not have a [[Cells]] internal slot, throw a TypeError exception. + 5. If Type(unregisterToken) is not Object, + a. If unregisterToken is not undefined, throw a TypeError exception. + b. Set unregisterToken to empty. + 6. Let cell be the Record { [[Target]] : target, [[Holdings]]: holdings, [[UnregisterToken]]: unregisterToken }. + 7. Append cell to finalizationRegistry.[[Cells]]. + 8. Return undefined. +features: [FinalizationRegistry] +---*/ + +var fn = function() {}; +var register = FinalizationRegistry.prototype.register; +var finalizationRegistry = new FinalizationRegistry(fn); + +var target = {}; +assert.sameValue(register.call(finalizationRegistry, target), undefined); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/heldValue-same-as-target.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/heldValue-same-as-target.js new file mode 100644 index 0000000000..11c8142074 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/heldValue-same-as-target.js @@ -0,0 +1,38 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: heldValue may be the same as target +info: | + FinalizationRegistry.prototype.register ( _target_ , _heldValue_ [, _unregisterToken_ ] ) + 1. Let _finalizationRegistry_ be the *this* value. + 2. Perform ? RequireInternalSlot(_finalizationRegistry_, [[Cells]]). + 3. If CanBeHeldWeakly(_target_) is *false*, throw a *TypeError* exception. + 4. If SameValue(_target_, _heldValue_) is *true*, throw a *TypeError* exception. +features: [FinalizationRegistry, Symbol] +---*/ + +var finalizationRegistry = new FinalizationRegistry(function() {}); + +var target = {}; +assert.throws(TypeError, () => finalizationRegistry.register(target, target)); + +// The following will throw regardless of whether the implementation supports +// Symbols as weak values. Step 3 if no, Step 4 if yes. + +var symbolTarget = Symbol('a description'); +assert.throws( + TypeError, + () => finalizationRegistry.register(symbolTarget, symbolTarget), + 'target and heldValue are the same regular symbol' +); + +assert.throws( + TypeError, + () => finalizationRegistry.register(Symbol.hasInstance, Symbol.hasInstance), + 'target and heldValue are the same well-known symbol' +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/holdings-any-value-type.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/holdings-any-value-type.js new file mode 100644 index 0000000000..87dacdbb34 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/holdings-any-value-type.js @@ -0,0 +1,38 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: No restriction for the value or type of holdings +info: | + FinalizationRegistry.prototype.register ( target , holdings [, unregisterToken ] ) + + 1. Let finalizationRegistry be the this value. + 2. If Type(finalizationRegistry) is not Object, throw a TypeError exception. + 3. If Type(target) is not Object, throw a TypeError exception. + 4. If finalizationRegistry does not have a [[Cells]] internal slot, throw a TypeError exception. + 5. If Type(unregisterToken) is not Object, + a. If unregisterToken is not undefined, throw a TypeError exception. + b. Set unregisterToken to empty. + 6. Let cell be the Record { [[Target]] : target, [[Holdings]]: holdings, [[UnregisterToken]]: unregisterToken }. + 7. Append cell to finalizationRegistry.[[Cells]]. + 8. Return undefined. +features: [FinalizationRegistry] +---*/ + +var fn = function() {}; +var finalizationRegistry = new FinalizationRegistry(fn); + +var target = {}; +assert.sameValue(finalizationRegistry.register(target, undefined), undefined, 'undefined'); +assert.sameValue(finalizationRegistry.register(target, null), undefined, 'null'); +assert.sameValue(finalizationRegistry.register(target, false), undefined, 'false'); +assert.sameValue(finalizationRegistry.register(target, true), undefined, 'true'); +assert.sameValue(finalizationRegistry.register(target, Symbol()), undefined, 'symbol'); +assert.sameValue(finalizationRegistry.register(target, {}), undefined, 'object'); +assert.sameValue(finalizationRegistry.register(target, finalizationRegistry), undefined, 'same as finalizationRegistry instance'); +assert.sameValue(finalizationRegistry.register(target, 1), undefined, 'number'); +assert.sameValue(finalizationRegistry.register(target, 'holdings'), undefined, 'string'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/length.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/length.js new file mode 100644 index 0000000000..6b33da1d3c --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/length.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: FinalizationRegistry.prototype.register.length property descriptor +info: | + FinalizationRegistry.prototype.register ( target , holdings [, unregisterToken ] ) + + 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: [propertyHelper.js] +features: [FinalizationRegistry] +---*/ + +verifyProperty(FinalizationRegistry.prototype.register, 'length', { + value: 2, + enumerable: false, + writable: false, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/name.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/name.js new file mode 100644 index 0000000000..7296b1a76f --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/name.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: FinalizationRegistry.prototype.register.name property descriptor +info: | + FinalizationRegistry.prototype.register.name value and property descriptor + + 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: [propertyHelper.js] +features: [FinalizationRegistry] +---*/ + +verifyProperty(FinalizationRegistry.prototype.register, 'name', { + value: 'register', + enumerable: false, + writable: false, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/not-a-constructor.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/not-a-constructor.js new file mode 100644 index 0000000000..f2471782ab --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/not-a-constructor.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-ecmascript-standard-built-in-objects +description: > + FinalizationRegistry.prototype.register does not implement [[Construct]], is not new-able +info: | + ECMAScript Function Objects + + Built-in function objects that are not identified as constructors do not + implement the [[Construct]] internal method unless otherwise specified in + the description of a particular function. + + sec-evaluatenew + + ... + 7. If IsConstructor(constructor) is false, throw a TypeError exception. + ... +includes: [isConstructor.js] +features: [Reflect.construct, FinalizationRegistry, arrow-function] +---*/ + +assert.sameValue( + isConstructor(FinalizationRegistry.prototype.register), + false, + 'isConstructor(FinalizationRegistry.prototype.register) must return false' +); + +assert.throws(TypeError, () => { + let fr = new FinalizationRegistry(() => {}); new fr.register({}); +}, '`let fr = new FinalizationRegistry(() => {}); new fr.register({})` throws TypeError'); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/prop-desc.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/prop-desc.js new file mode 100644 index 0000000000..22bb9a3298 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/prop-desc.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: > + Property descriptor of FinalizationRegistry.prototype.register +info: | + 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] +features: [FinalizationRegistry] +---*/ + +assert.sameValue(typeof FinalizationRegistry.prototype.register, 'function'); + +verifyProperty(FinalizationRegistry.prototype, 'register', { + enumerable: false, + writable: true, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/return-undefined-register-itself.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/return-undefined-register-itself.js new file mode 100644 index 0000000000..00efa55a0a --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/return-undefined-register-itself.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: Return undefined after registering itself +info: | + FinalizationRegistry.prototype.register ( target , holdings [, unregisterToken ] ) + + 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 Type(target) is not Object, throw a TypeError exception. + 5. If SameValue(target, holdings), throw a TypeError exception. + 6. If Type(unregisterToken) is not Object, + a. If unregisterToken is not undefined, throw a TypeError exception. + b. Set unregisterToken to empty. + 7. Let cell be the Record { [[Target]] : target, [[Holdings]]: holdings, [[UnregisterToken]]: unregisterToken }. + 8. Append cell to finalizationRegistry.[[Cells]]. + 9. Return undefined. +features: [FinalizationRegistry] +---*/ + +var fn = function() {}; +var finalizationRegistry = new FinalizationRegistry(fn); +var holdings = {}; + +assert.sameValue(finalizationRegistry.register(finalizationRegistry), undefined, 'Register itself'); +assert.sameValue(finalizationRegistry.register(finalizationRegistry, holdings), undefined, 'Register itself with holdings'); +assert.sameValue(finalizationRegistry.register(finalizationRegistry, holdings, finalizationRegistry), undefined, 'Register itself with holdings and unregisterToken'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/return-undefined-register-object.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/return-undefined-register-object.js new file mode 100644 index 0000000000..b185a37113 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/return-undefined-register-object.js @@ -0,0 +1,46 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: Return undefined after registering an Object +info: | + FinalizationRegistry.prototype.register ( _target_ , _heldValue_ [, _unregisterToken_ ] ) + 1. Let _finalizationRegistry_ be the *this* value. + 2. Perform ? RequireInternalSlot(_finalizationRegistry_, [[Cells]]). + 3. If CanBeHeldWeakly(_target_) is *false*, throw a *TypeError* exception. + 4. If SameValue(_target_, _heldValue_) is *true*, throw a *TypeError* + exception. + 5. If CanBeHeldWeakly(_unregisterToken_) is *false*, + a. If _unregisterToken_ is not *undefined*, throw a *TypeError* exception. + b. Set _unregisterToken_ to ~empty~. + 6. Let _cell_ be the Record { [[WeakRefTarget]]: _target_, [[HeldValue]]: + _heldValue_, [[UnregisterToken]]: _unregisterToken_ }. + 7. Append _cell_ to _finalizationRegistry_.[[Cells]]. + 8. Return *undefined*. +features: [FinalizationRegistry] +---*/ + +var fn = function() {}; +var finalizationRegistry = new FinalizationRegistry(fn); + +var target = {}; +assert.sameValue(finalizationRegistry.register(target), undefined, 'Register a target'); +assert.sameValue(finalizationRegistry.register(target), undefined, 'Register the same target again'); +assert.sameValue(finalizationRegistry.register(target), undefined, 'Register the same target again and again'); + +assert.sameValue(finalizationRegistry.register({}), undefined, 'Register other targets'); + +assert.sameValue(finalizationRegistry.register(target, undefined, {}), undefined, 'Register target with unregisterToken'); +assert.sameValue( + finalizationRegistry.register(target, undefined, target), + undefined, + 'Register target with unregisterToken being the registered target' +); + +assert.sameValue(finalizationRegistry.register(target, undefined, undefined), undefined, 'Register target with explicit undefined unregisterToken'); + +assert.sameValue(finalizationRegistry.register(fn), undefined, 'register the cleanup callback fn'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/return-undefined-register-symbol.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/return-undefined-register-symbol.js new file mode 100644 index 0000000000..9129bbd5ad --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/return-undefined-register-symbol.js @@ -0,0 +1,76 @@ +// |reftest| skip -- symbols-as-weakmap-keys is not supported +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-finalization-registry.prototype.register +description: Return undefined after registering a Symbol +info: | + FinalizationRegistry.prototype.register ( _target_ , _heldValue_ [, _unregisterToken_ ] ) + 8. Return *undefined*. +features: [FinalizationRegistry, Symbol, symbols-as-weakmap-keys] +---*/ + +var fn = function() {}; +var reg = new FinalizationRegistry(fn); + +var target = Symbol('a description'); +assert.sameValue(reg.register(target), undefined, 'Register a regular symbol'); +assert.sameValue(reg.register(target), undefined, 'Register the same symbol again'); +assert.sameValue(reg.register(target), undefined, 'Register the same symbol a third time'); + +assert.sameValue( + reg.register(Symbol('a description')), + undefined, + 'Register another symbol with the same description' +); +assert.sameValue( + reg.register(Symbol('a different description')), + undefined, + 'Register another symbol with another description' +); + +assert.sameValue( + reg.register(target, undefined, Symbol('unregister token')), + undefined, + 'Register a regular symbol with a symbol unregister token' +); +assert.sameValue( + reg.register(target, undefined, target), + undefined, + 'Register a regular symbol with itself as the unregister token' +); + +assert.sameValue( + reg.register(target, undefined, undefined), + undefined, + 'Register a regular symbol with explicit undefined unregister token' +); + +assert.sameValue(reg.register(Symbol.hasInstance), undefined, 'Register a well-known symbol'); +assert.sameValue(reg.register(Symbol.hasInstance), undefined, 'Register the same well-known symbol again'); +assert.sameValue(reg.register(Symbol.hasInstance), undefined, 'Register the same well-known symbol a third time'); + +assert.sameValue( + reg.register(target, undefined, Symbol.hasInstance), + undefined, + 'Register a regular symbol with a well-known symbol unregister token' +); +assert.sameValue( + reg.register(Symbol.hasInstance, undefined, Symbol.iterator), + undefined, + 'Register a well-known symbol with a different well-known symbol as unregister token' +); +assert.sameValue( + reg.register(Symbol.hasInstance, undefined, Symbol.hasInstance), + undefined, + 'Register a well-known symbol with itself as the unregister token' +); + +assert.sameValue( + reg.register(Symbol.hasInstance, undefined, undefined), + undefined, + 'Register a well-known symbol with explicit undefined unregister token' +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/shell.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/shell.js diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/this-does-not-have-internal-target-throws.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/this-does-not-have-internal-target-throws.js new file mode 100644 index 0000000000..f7044833ba --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/this-does-not-have-internal-target-throws.js @@ -0,0 +1,51 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')||!this.hasOwnProperty('WeakRef')) -- FinalizationRegistry,WeakRef is not enabled unconditionally +// 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.register +description: Throws a TypeError if this does not have a [[Cells]] internal slot +info: | + FinalizationRegistry.prototype.register ( target , holdings [, unregisterToken ] ) + + 1. Let finalizationRegistry be the this value. + 2. If Type(finalizationRegistry) is not Object, throw a TypeError exception. + 3. If Type(target) is not Object, throw a TypeError exception. + 4. If finalizationRegistry does not have a [[Cells]] internal slot, throw a TypeError exception. + ... +features: [WeakSet, WeakMap, FinalizationRegistry, WeakRef] +---*/ + +assert.sameValue(typeof FinalizationRegistry.prototype.register, 'function'); + +var register = FinalizationRegistry.prototype.register; +var target = {}; + +assert.throws(TypeError, function() { + register.call({ ['[[Cells]]']: {} }, target); +}, 'Ordinary object without [[Cells]]'); + +assert.throws(TypeError, function() { + register.call(WeakRef.prototype, target); +}, 'WeakRef.prototype does not have a [[Cells]] internal slot'); + +assert.throws(TypeError, function() { + register.call(WeakRef, target); +}, 'WeakRef does not have a [[Cells]] internal slot'); + +var wr = new WeakRef({}); +assert.throws(TypeError, function() { + register.call(wr, target); +}, 'WeakRef instance'); + +var wm = new WeakMap(); +assert.throws(TypeError, function() { + register.call(wm, target); +}, 'WeakMap instance'); + +var ws = new WeakSet(); +assert.throws(TypeError, function() { + register.call(ws, target); +}, 'WeakSet instance'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/this-not-object-throws.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/this-not-object-throws.js new file mode 100644 index 0000000000..933a905e35 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/this-not-object-throws.js @@ -0,0 +1,54 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: Throws a TypeError if this is not an Object +info: | + FinalizationRegistry.prototype.register ( target , holdings [, unregisterToken ] ) + + 1. Let finalizationRegistry be the this value. + 2. If Type(finalizationRegistry) is not Object, throw a TypeError exception. + 3. If Type(target) is not Object, throw a TypeError exception. + 4. If finalizationRegistry does not have a [[Cells]] internal slot, throw a TypeError exception. + 5. If Type(unregisterToken) is not Object, + a. If unregisterToken is not undefined, throw a TypeError exception. + ... +features: [FinalizationRegistry] +---*/ + +assert.sameValue(typeof FinalizationRegistry.prototype.register, 'function'); + +var register = FinalizationRegistry.prototype.register; + +assert.throws(TypeError, function() { + register.call(undefined, {}); +}, 'undefined'); + +assert.throws(TypeError, function() { + register.call(null, {}); +}, 'null'); + +assert.throws(TypeError, function() { + register.call(true, {}); +}, 'true'); + +assert.throws(TypeError, function() { + register.call(false, {}); +}, 'false'); + +assert.throws(TypeError, function() { + register.call(1, {}); +}, 'number'); + +assert.throws(TypeError, function() { + register.call('object', {}); +}, 'string'); + +var s = Symbol(); +assert.throws(TypeError, function() { + register.call(s, {}); +}, 'symbol'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/throws-when-target-cannot-be-held-weakly.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/throws-when-target-cannot-be-held-weakly.js new file mode 100644 index 0000000000..fa2fe3e021 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/throws-when-target-cannot-be-held-weakly.js @@ -0,0 +1,47 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: Throws a TypeError if target cannot be held weakly +info: | + FinalizationRegistry.prototype.register ( _target_ , _heldValue_ [, _unregisterToken_ ] ) + 3. If CanBeHeldWeakly(_target_) is *false*, throw a *TypeError* exception. +features: [FinalizationRegistry] +---*/ + +assert.sameValue(typeof FinalizationRegistry.prototype.register, 'function'); + +var finalizationRegistry = new FinalizationRegistry(function() {}); + +assert.throws(TypeError, function() { + finalizationRegistry.register(undefined); +}, 'undefined'); + +assert.throws(TypeError, function() { + finalizationRegistry.register(null); +}, 'null'); + +assert.throws(TypeError, function() { + finalizationRegistry.register(true); +}, 'true'); + +assert.throws(TypeError, function() { + finalizationRegistry.register(false); +}, 'false'); + +assert.throws(TypeError, function() { + finalizationRegistry.register(1); +}, 'number'); + +assert.throws(TypeError, function() { + finalizationRegistry.register('object'); +}, 'string'); + +var s = Symbol.for('registered symbol'); +assert.throws(TypeError, function() { + finalizationRegistry.register(s); +}, 'registered symbol'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/throws-when-unregisterToken-not-undefined-and-cannot-be-held-weakly.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/throws-when-unregisterToken-not-undefined-and-cannot-be-held-weakly.js new file mode 100644 index 0000000000..6f7853a439 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/throws-when-unregisterToken-not-undefined-and-cannot-be-held-weakly.js @@ -0,0 +1,47 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: > + Throws a TypeError if unregisterToken is not undefined and cannot be held + weakly +info: | + FinalizationRegistry.prototype.register ( _target_ , _heldValue_ [, _unregisterToken_ ] ) + 5. If CanBeHeldWeakly(_unregisterToken_) is *false*, then + a. If _unregisterToken_ is not *undefined*, throw a *TypeError* exception. +features: [FinalizationRegistry] +---*/ + +assert.sameValue(typeof FinalizationRegistry.prototype.register, 'function'); + +var finalizationRegistry = new FinalizationRegistry(function() {}); +var target = {}; + +assert.throws(TypeError, function() { + finalizationRegistry.register(target, undefined, null); +}, 'null'); + +assert.throws(TypeError, function() { + finalizationRegistry.register(target, undefined, true); +}, 'true'); + +assert.throws(TypeError, function() { + finalizationRegistry.register(target, undefined, false); +}, 'false'); + +assert.throws(TypeError, function() { + finalizationRegistry.register(target, undefined, 1); +}, 'number'); + +assert.throws(TypeError, function() { + finalizationRegistry.register(target, undefined, 'object'); +}, 'string'); + +var s = Symbol.for('registered symbol'); +assert.throws(TypeError, function() { + finalizationRegistry.register(target, undefined, s); +}, 'registered symbol'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/unregisterToken-same-as-holdings-and-target.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/unregisterToken-same-as-holdings-and-target.js new file mode 100644 index 0000000000..a3ed546406 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/unregisterToken-same-as-holdings-and-target.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: unregisterToken may be the same as holdings and target +info: | + FinalizationRegistry.prototype.register ( target , holdings [, unregisterToken ] ) + + 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 Type(target) is not Object, throw a TypeError exception. + 5. If SameValue(target, holdings), throw a TypeError exception. + 6. If Type(unregisterToken) is not Object, + a. If unregisterToken is not undefined, throw a TypeError exception. + b. Set unregisterToken to empty. + 7. Let cell be the Record { [[Target]] : target, [[Holdings]]: holdings, [[UnregisterToken]]: unregisterToken }. + 8. Append cell to finalizationRegistry.[[Cells]]. + 9. Return undefined. +features: [FinalizationRegistry] +---*/ + +var finalizationRegistry = new FinalizationRegistry(function() {}); + +var target = {}; +assert.throws(TypeError, () => finalizationRegistry.register(target, target, target)); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/unregisterToken-same-as-holdings.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/unregisterToken-same-as-holdings.js new file mode 100644 index 0000000000..befc50ec10 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/unregisterToken-same-as-holdings.js @@ -0,0 +1,30 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: unregisterToken may be the same as holdings +info: | + FinalizationRegistry.prototype.register ( target , holdings [, unregisterToken ] ) + + 1. Let finalizationRegistry be the this value. + 2. If Type(finalizationRegistry) is not Object, throw a TypeError exception. + 3. If Type(target) is not Object, throw a TypeError exception. + 4. If finalizationRegistry does not have a [[Cells]] internal slot, throw a TypeError exception. + 5. If Type(unregisterToken) is not Object, + a. If unregisterToken is not undefined, throw a TypeError exception. + b. Set unregisterToken to empty. + 6. Let cell be the Record { [[Target]] : target, [[Holdings]]: holdings, [[UnregisterToken]]: unregisterToken }. + 7. Append cell to finalizationRegistry.[[Cells]]. + 8. Return undefined. +features: [FinalizationRegistry] +---*/ + +var finalizationRegistry = new FinalizationRegistry(function() {}); + +var target = {}; +var holdings = {}; +assert.sameValue(finalizationRegistry.register(target, holdings, holdings), undefined); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/unregisterToken-same-as-target.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/unregisterToken-same-as-target.js new file mode 100644 index 0000000000..bfe567cf50 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/unregisterToken-same-as-target.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.register +description: unregisterToken may be the same as target +info: | + FinalizationRegistry.prototype.register ( target , holdings [, unregisterToken ] ) + + 1. Let finalizationRegistry be the this value. + 2. If Type(finalizationRegistry) is not Object, throw a TypeError exception. + 3. If Type(target) is not Object, throw a TypeError exception. + 4. If finalizationRegistry does not have a [[Cells]] internal slot, throw a TypeError exception. + 5. If Type(unregisterToken) is not Object, + a. If unregisterToken is not undefined, throw a TypeError exception. + b. Set unregisterToken to empty. + 6. Let cell be the Record { [[Target]] : target, [[Holdings]]: holdings, [[UnregisterToken]]: unregisterToken }. + 7. Append cell to finalizationRegistry.[[Cells]]. + 8. Return undefined. +features: [FinalizationRegistry] +---*/ + +var finalizationRegistry = new FinalizationRegistry(function() {}); + +var target = {}; +assert.sameValue(finalizationRegistry.register(target, '1', target), undefined); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/shell.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/shell.js diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/browser.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/browser.js diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/custom-this.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/custom-this.js new file mode 100644 index 0000000000..ac7157940e --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/custom-this.js @@ -0,0 +1,50 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.unregister +description: Return values applying custom this +info: | + FinalizationRegistry.prototype.unregister ( unregisterToken ) + + 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 Type(unregisterToken) is not Object, throw a TypeError exception. + 5. Let removed be false. + 6. For each Record { [[Target]], [[Holdings]], [[UnregisterToken]] } cell that is an element of finalizationRegistry.[[Cells]], do + a. If SameValue(cell.[[UnregisterToken]], unregisterToken) is true, then + i. Remove cell from finalizationRegistry.[[Cells]]. + ii. Set removed to true. + 7. Return removed. +features: [FinalizationRegistry] +---*/ + +var fn = function() {}; +var unregister = FinalizationRegistry.prototype.unregister; +var finalizationRegistry = new FinalizationRegistry(fn); + +var target1 = {}; +var target2 = {}; +var target3 = {}; +var token1 = {}; +var token2 = {}; + +assert.sameValue(unregister.call(finalizationRegistry, token1), false, 'unregistering token1 from empty finalizationRegistry'); +assert.sameValue(unregister.call(finalizationRegistry, token2), false, 'unregistering token2 from empty finalizationRegistry'); + +finalizationRegistry.register(target1, undefined, token1); +finalizationRegistry.register(target2, undefined, token2); +finalizationRegistry.register(target3, undefined, token2); + +assert.sameValue(unregister.call(finalizationRegistry, target1), false, 'own target does not work on unregister, #1'); +assert.sameValue(unregister.call(finalizationRegistry, target2), false, 'own target does not work on unregister, #2'); +assert.sameValue(unregister.call(finalizationRegistry, target3), false, 'own target does not work on unregister, #3'); + +assert.sameValue(unregister.call(finalizationRegistry, token1), true, 'unregistering token1 from finalizationRegistry'); +assert.sameValue(unregister.call(finalizationRegistry, token1), false, 'unregistering token1 again from finalizationRegistry'); +assert.sameValue(unregister.call(finalizationRegistry, token2), true, 'unregistering token2 to remove target2 and target3'); +assert.sameValue(unregister.call(finalizationRegistry, token2), false, 'unregistering token2 from empty finalizationRegistry'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/length.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/length.js new file mode 100644 index 0000000000..72d6570581 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/length.js @@ -0,0 +1,35 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.unregister +description: FinalizationRegistry.prototype.unregister.length property descriptor +info: | + FinalizationRegistry.prototype.unregister ( unregisterToken ) + + 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: [propertyHelper.js] +features: [FinalizationRegistry] +---*/ + +verifyProperty(FinalizationRegistry.prototype.unregister, 'length', { + value: 1, + writable: false, + enumerable: false, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/name.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/name.js new file mode 100644 index 0000000000..3b92b98d58 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/name.js @@ -0,0 +1,34 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.unregister +description: FinalizationRegistry.prototype.unregister.name property descriptor +info: | + FinalizationRegistry.prototype.unregister.name value and property descriptor + + 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: [propertyHelper.js] +features: [FinalizationRegistry] +---*/ + +verifyProperty(FinalizationRegistry.prototype.unregister, 'name', { + value: 'unregister', + writable: false, + enumerable: false, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/not-a-constructor.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/not-a-constructor.js new file mode 100644 index 0000000000..ea51595556 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/not-a-constructor.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// Copyright (C) 2020 Rick Waldron. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-ecmascript-standard-built-in-objects +description: > + FinalizationRegistry.prototype.unregister does not implement [[Construct]], is not new-able +info: | + ECMAScript Function Objects + + Built-in function objects that are not identified as constructors do not + implement the [[Construct]] internal method unless otherwise specified in + the description of a particular function. + + sec-evaluatenew + + ... + 7. If IsConstructor(constructor) is false, throw a TypeError exception. + ... +includes: [isConstructor.js] +features: [Reflect.construct, FinalizationRegistry, arrow-function] +---*/ + +assert.sameValue( + isConstructor(FinalizationRegistry.prototype.unregister), + false, + 'isConstructor(FinalizationRegistry.prototype.unregister) must return false' +); + +assert.throws(TypeError, () => { + let fr = new FinalizationRegistry(() => {}); let token = {}; fr.register(token); new fr.unregister(token); +}, '`let fr = new FinalizationRegistry(() => {}); let token = {}; fr.register(token); new fr.unregister(token)` throws TypeError'); + + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/prop-desc.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/prop-desc.js new file mode 100644 index 0000000000..0e4aa0564c --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/prop-desc.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.unregister +description: > + Property descriptor of FinalizationRegistry.prototype.unregister +info: | + 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] +features: [FinalizationRegistry] +---*/ + +assert.sameValue(typeof FinalizationRegistry.prototype.unregister, 'function'); + +verifyProperty(FinalizationRegistry.prototype, 'unregister', { + enumerable: false, + writable: true, + configurable: true +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/shell.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/shell.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/shell.js diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/this-does-not-have-internal-cells-throws.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/this-does-not-have-internal-cells-throws.js new file mode 100644 index 0000000000..a10e58c01d --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/this-does-not-have-internal-cells-throws.js @@ -0,0 +1,51 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')||!this.hasOwnProperty('WeakRef')) -- FinalizationRegistry,WeakRef is not enabled unconditionally +// 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.unregister +description: Throws a TypeError if this does not have a [[Cells]] internal slot +info: | + FinalizationRegistry.prototype.unregister ( unregisterToken ) + + 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 Type(unregisterToken) is not Object, throw a TypeError exception. + ... +features: [WeakSet, WeakMap, FinalizationRegistry, WeakRef] +---*/ + +assert.sameValue(typeof FinalizationRegistry.prototype.unregister, 'function'); + +var unregister = FinalizationRegistry.prototype.unregister; +var token = {}; + +assert.throws(TypeError, function() { + unregister.call({ ['[[Cells]]']: {} }, token); +}, 'Ordinary object without [[Cells]]'); + +assert.throws(TypeError, function() { + unregister.call(WeakRef.prototype, token); +}, 'WeakRef.prototype does not have a [[Cells]] internal slot'); + +assert.throws(TypeError, function() { + unregister.call(WeakRef, token); +}, 'WeakRef does not have a [[Cells]] internal slot'); + +var wr = new WeakRef({}); +assert.throws(TypeError, function() { + unregister.call(wr, token); +}, 'WeakRef instance'); + +var wm = new WeakMap(); +assert.throws(TypeError, function() { + unregister.call(wm, token); +}, 'WeakMap instance'); + +var ws = new WeakSet(); +assert.throws(TypeError, function() { + unregister.call(ws, token); +}, 'WeakSet instance'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/this-not-object-throws.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/this-not-object-throws.js new file mode 100644 index 0000000000..7cb536cb9c --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/this-not-object-throws.js @@ -0,0 +1,52 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.unregister +description: Throws a TypeError if this is not an Object +info: | + FinalizationRegistry.prototype.unregister ( unregisterToken ) + + 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 Type(unregisterToken) is not Object, throw a TypeError exception. + ... +features: [FinalizationRegistry] +---*/ + +assert.sameValue(typeof FinalizationRegistry.prototype.unregister, 'function'); + +var unregister = FinalizationRegistry.prototype.unregister; + +assert.throws(TypeError, function() { + unregister.call(undefined, {}); +}, 'undefined'); + +assert.throws(TypeError, function() { + unregister.call(null, {}); +}, 'null'); + +assert.throws(TypeError, function() { + unregister.call(true, {}); +}, 'true'); + +assert.throws(TypeError, function() { + unregister.call(false, {}); +}, 'false'); + +assert.throws(TypeError, function() { + unregister.call(1, {}); +}, 'number'); + +assert.throws(TypeError, function() { + unregister.call('object', {}); +}, 'string'); + +var s = Symbol(); +assert.throws(TypeError, function() { + unregister.call(s, {}); +}, 'symbol'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/throws-when-unregisterToken-cannot-be-held-weakly.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/throws-when-unregisterToken-cannot-be-held-weakly.js new file mode 100644 index 0000000000..403b569d5a --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/throws-when-unregisterToken-cannot-be-held-weakly.js @@ -0,0 +1,47 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.unregister +description: Throws a TypeError if unregisterToken cannot be held weakly +info: | + FinalizationRegistry.prototype.unregister ( _unregisterToken_ ) + 3. If CanBeHeldWeakly(_unregisterToken_) is *false*, throw a *TypeError* exception. +features: [FinalizationRegistry] +---*/ + +assert.sameValue(typeof FinalizationRegistry.prototype.unregister, 'function'); + +var finalizationRegistry = new FinalizationRegistry(function() {}); + +assert.throws(TypeError, function() { + finalizationRegistry.unregister(undefined); +}, 'undefined'); + +assert.throws(TypeError, function() { + finalizationRegistry.unregister(null); +}, 'null'); + +assert.throws(TypeError, function() { + finalizationRegistry.unregister(true); +}, 'true'); + +assert.throws(TypeError, function() { + finalizationRegistry.unregister(false); +}, 'false'); + +assert.throws(TypeError, function() { + finalizationRegistry.unregister(1); +}, 'number'); + +assert.throws(TypeError, function() { + finalizationRegistry.unregister('object'); +}, 'string'); + +var s = Symbol.for('registered symbol'); +assert.throws(TypeError, function() { + finalizationRegistry.unregister(s); +}, 'registered symbol'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/unregister-cleaned-up-object-cell.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/unregister-cleaned-up-object-cell.js new file mode 100644 index 0000000000..da74a59287 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/unregister-cleaned-up-object-cell.js @@ -0,0 +1,64 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) async -- FinalizationRegistry is not enabled unconditionally +// Copyright (C) 2019 Mathieu Hofman. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-finalization-registry.prototype.unregister +description: > + Cannot unregister a cell referring to an Object that has been cleaned up +info: | + FinalizationRegistry.prototype.cleanupSome ( [ _callback_ ] ) + 4. Perform ? CleanupFinalizationRegistry(_finalizationRegistry_, _callback_). + + CleanupFinalizationRegistry ( _finalizationRegistry_ ): + 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. Perform ? HostCallJobCallback(_callback_, *undefined*, + « _cell_.[[HeldValue]] »). + + FinalizationRegistry.prototype.unregister ( _unregisterToken_ ) + 4. Let _removed_ be *false*. + 5. For each Record { [[WeakRefTarget]], [[HeldValue]], [[UnregisterToken]] } + _cell_ of _finalizationRegistry_.[[Cells]], do + a. If _cell_.[[UnregisterToken]] is not ~empty~ and + SameValue(_cell_.[[UnregisterToken]], _unregisterToken_) is *true*, then + i. Remove _cell_ from _finalizationRegistry_.[[Cells]]. + ii. Set _removed_ to *true*. + 6. Return _removed_. +features: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry, host-gc-required] +includes: [async-gc.js] +flags: [async, non-deterministic] +---*/ + +var value = 'target!'; +var token = {}; +var finalizationRegistry = new FinalizationRegistry(function() {}); + +function emptyCells() { + var target = {}; + finalizationRegistry.register(target, value, token); + + var prom = asyncGC(target); + target = null; + + return prom; +} + +emptyCells().then(function() { + var called = 0; + var holdings = []; + finalizationRegistry.cleanupSome(function cb(holding) { + called += 1; + holdings.push(holding); + }); + + assert.sameValue(called, 1); + assert.sameValue(holdings.length, 1); + assert.sameValue(holdings[0], value); + + var res = finalizationRegistry.unregister(token); + assert.sameValue(res, false, 'unregister after iterating over it in cleanup'); +}).then($DONE, resolveAsyncGC); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/unregister-object-token.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/unregister-object-token.js new file mode 100644 index 0000000000..0dd685e4b8 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/unregister-object-token.js @@ -0,0 +1,57 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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.unregister +description: > + Return boolean values indicating unregistering of values with Object token +info: | + FinalizationRegistry.prototype.unregister ( _unregisterToken_ ) + 4. Let _removed_ be *false*. + 5. For each Record { [[WeakRefTarget]], [[HeldValue]], [[UnregisterToken]] } + _cell_ of _finalizationRegistry_.[[Cells]], do + a. If _cell_.[[UnregisterToken]] is not ~empty~ and + SameValue(_cell_.[[UnregisterToken]], _unregisterToken_) is *true*, then + i. Remove _cell_ from _finalizationRegistry_.[[Cells]]. + ii. Set _removed_ to *true*. + 6. Return _removed_. +features: [FinalizationRegistry] +---*/ + +var fn = function() {}; +var finalizationRegistry = new FinalizationRegistry(fn); + +var target1 = {}; +var target2 = {}; +var target3 = {}; +var token1 = {}; +var token2 = {}; + +assert.sameValue(finalizationRegistry.unregister(token1), false, 'unregistering token1 from empty finalizationRegistry'); +assert.sameValue(finalizationRegistry.unregister(token2), false, 'unregistering token2 from empty finalizationRegistry'); + +finalizationRegistry.register(target1, undefined, token1); +finalizationRegistry.register(target1, undefined, token1); // Repeat registering un purpose +finalizationRegistry.register(target2, undefined, token2); +finalizationRegistry.register(target3, undefined, token2); + +assert.sameValue(finalizationRegistry.unregister(target1), false, 'own target does not work on unregister, #1'); +assert.sameValue(finalizationRegistry.unregister(target2), false, 'own target does not work on unregister, #2'); +assert.sameValue(finalizationRegistry.unregister(target3), false, 'own target does not work on unregister, #3'); + +assert.sameValue(finalizationRegistry.unregister(token1), true, 'unregistering token1 from finalizationRegistry'); +assert.sameValue(finalizationRegistry.unregister(token1), false, 'unregistering token1 again from finalizationRegistry'); +assert.sameValue(finalizationRegistry.unregister(token2), true, 'unregistering token2 to remove target2 and target3'); +assert.sameValue(finalizationRegistry.unregister(token2), false, 'unregistering token2 from empty finalizationRegistry'); + +// Notice these assertions take advantage of adding targets previously added with a token, +// but now they got no token so it won't be used to remove them. +finalizationRegistry.register(target1, token1); // holdings, not unregisterToken +finalizationRegistry.register(target2, token2); // holdings, not unregisterToken +finalizationRegistry.register(target3); + +assert.sameValue(finalizationRegistry.unregister(token1), false, 'nothing to remove without a set unregisterToken #1'); +assert.sameValue(finalizationRegistry.unregister(token2), false, 'nothing to remove without a set unregisterToken #2'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/unregister-symbol-token.js b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/unregister-symbol-token.js new file mode 100644 index 0000000000..760347c9f1 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/unregister-symbol-token.js @@ -0,0 +1,64 @@ +// |reftest| skip -- symbols-as-weakmap-keys is not supported +// Copyright (C) 2022 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-finalization-registry.prototype.unregister +description: > + Return boolean values indicating unregistering of values with Symbol token +info: | + FinalizationRegistry.prototype.unregister ( _unregisterToken_ ) + 4. Let _removed_ be *false*. + 5. For each Record { [[WeakRefTarget]], [[HeldValue]], [[UnregisterToken]] } + _cell_ of _finalizationRegistry_.[[Cells]], do + a. If _cell_.[[UnregisterToken]] is not ~empty~ and + SameValue(_cell_.[[UnregisterToken]], _unregisterToken_) is *true*, then + i. Remove _cell_ from _finalizationRegistry_.[[Cells]]. + ii. Set _removed_ to *true*. + 6. Return _removed_. +features: [FinalizationRegistry, Symbol, symbols-as-weakmap-keys] +---*/ + +var fn = function() {}; +var reg = new FinalizationRegistry(fn); + +var target1 = {}; +var target2 = {}; +var target3 = {}; +var token = Symbol('unregister'); + +assert.sameValue(reg.unregister(token), false, 'unregistering regular symbol from empty registry'); +assert.sameValue(reg.unregister(Symbol.hasInstance), false, 'unregistering well-known symbol from empty registry'); + +reg.register(target1, undefined, token); +reg.register(target1, undefined, token); // Repeat registering on purpose +reg.register(target2, undefined, Symbol.hasInstance); +reg.register(target3, undefined, Symbol.hasInstance); + +assert.sameValue(reg.unregister(token), true, 'unregistering regular symbol from finalization registry'); +assert.sameValue(reg.unregister(token), false, 'unregistering regular symbol again from finalization registry'); +assert.sameValue( + reg.unregister(Symbol.hasInstance), + true, + 'unregistering well-known symbol to remove target2 and target3' +); +assert.sameValue( + reg.unregister(Symbol.hasInstance), + false, + 'unregistering well-known again from finalization registry' +); + +// Notice these assertions take advantage of adding targets previously added +// with a token, but now they have no token so it won't be used to remove them. +reg.register(target1, token); // heldValue, not unregisterToken +reg.register(target2, Symbol.hasInstance); // heldValue, not unregisterToken +reg.register(target3); + +assert.sameValue(reg.unregister(token), false, 'nothing to remove with regular symbol unregister token'); +assert.sameValue( + reg.unregister(Symbol.hasInstance), + false, + 'nothing to remove with well-known symbol unregister token' +); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/returns-new-object-from-constructor.js b/js/src/tests/test262/built-ins/FinalizationRegistry/returns-new-object-from-constructor.js new file mode 100644 index 0000000000..86cb020b36 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/returns-new-object-from-constructor.js @@ -0,0 +1,42 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-target +description: > + Returns a new ordinary object from the FinalizationRegistry constructor +info: | + FinalizationRegistry ( cleanupCallback ) + + ... + 3. Let finalizationRegistry be ? OrdinaryCreateFromConstructor(NewTarget, "%FinalizationRegistryPrototype%", « [[Realm]], [[CleanupCallback]], [[Cells]], [[IsFinalizationRegistryCleanupJobActive]] »). + ... + 9. Return finalizationRegistry. + + OrdinaryCreateFromConstructor ( constructor, intrinsicDefaultProto [ , internalSlotsList ] ) + + ... + 2. Let proto be ? GetPrototypeFromConstructor(constructor, intrinsicDefaultProto). + 3. Return ObjectCreate(proto, internalSlotsList). +features: [FinalizationRegistry, for-of] +---*/ + +var cleanupCallback = function() {}; +var finalizationRegistry = new FinalizationRegistry(cleanupCallback); + +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), FinalizationRegistry.prototype); +assert.notSameValue(finalizationRegistry, cleanupCallback, 'does not return the same function'); +assert.sameValue(finalizationRegistry instanceof FinalizationRegistry, true, 'instanceof'); + +for (let key of Object.getOwnPropertyNames(finalizationRegistry)) { + assert(false, `should not set any own named properties: ${key}`); +} + +for (let key of Object.getOwnPropertySymbols(finalizationRegistry)) { + assert(false, `should not set any own symbol properties: ${String(key)}`); +} + +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), FinalizationRegistry.prototype); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/shell.js b/js/src/tests/test262/built-ins/FinalizationRegistry/shell.js new file mode 100644 index 0000000000..b4d29ea4e9 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/shell.js @@ -0,0 +1,83 @@ +// GENERATED, DO NOT EDIT +// file: async-gc.js +// 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: [FinalizationRegistry.prototype.cleanupSome, FinalizationRegistry, Symbol, async-functions] +flags: [non-deterministic] +defines: [asyncGC, asyncGCDeref, resolveAsyncGC] +---*/ + +function asyncGC(...targets) { + var finalizationRegistry = new FinalizationRegistry(() => {}); + var length = targets.length; + + for (let target of targets) { + finalizationRegistry.register(target, 'target'); + target = null; + } + + targets = null; + + return Promise.resolve('tick').then(() => asyncGCDeref()).then(() => { + var names = []; + + // consume iterator to capture names + finalizationRegistry.cleanupSome(name => { names.push(name); }); + + 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(); + return; + } + + $DONE(err); +} + +// file: isConstructor.js +// Copyright (C) 2017 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: | + Test if a given function is a constructor function. +defines: [isConstructor] +features: [Reflect.construct] +---*/ + +function isConstructor(f) { + if (typeof f !== "function") { + throw new Test262Error("isConstructor invoked with a non-function value"); + } + + try { + Reflect.construct(function(){}, [], f); + } catch (e) { + return false; + } + return true; +} diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/target-not-callable-throws.js b/js/src/tests/test262/built-ins/FinalizationRegistry/target-not-callable-throws.js new file mode 100644 index 0000000000..e68fecc72e --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/target-not-callable-throws.js @@ -0,0 +1,72 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')||!this.hasOwnProperty('WeakRef')) -- FinalizationRegistry,WeakRef is not enabled unconditionally +// 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-target +description: > + Throws a TypeError if target is not callable +info: | + FinalizationRegistry ( cleanupCallback ) + + 1. If NewTarget is undefined, throw a TypeError exception. + 2. If IsCallable(cleanupCallback) is false, throw a TypeError exception. + ... +features: [FinalizationRegistry, WeakRef] +---*/ + +assert.sameValue( + typeof FinalizationRegistry, 'function', + 'typeof FinalizationRegistry is function' +); + +assert.throws(TypeError, function() { + new FinalizationRegistry({}); +}, 'ordinary object'); + +assert.throws(TypeError, function() { + new FinalizationRegistry(WeakRef.prototype); +}, 'WeakRef.prototype'); + +assert.throws(TypeError, function() { + new FinalizationRegistry(FinalizationRegistry.prototype); +}, 'FinalizationRegistry.prototype'); + +assert.throws(TypeError, function() { + new FinalizationRegistry([]); +}, 'Array'); + +assert.throws(TypeError, function() { + new FinalizationRegistry(); +}, 'implicit undefined'); + +assert.throws(TypeError, function() { + new FinalizationRegistry(undefined); +}, 'explicit undefined'); + +assert.throws(TypeError, function() { + new FinalizationRegistry(null); +}, 'null'); + +assert.throws(TypeError, function() { + new FinalizationRegistry(1); +}, 'number'); + +assert.throws(TypeError, function() { + new FinalizationRegistry('Object'); +}, 'string'); + +var s = Symbol(); +assert.throws(TypeError, function() { + new FinalizationRegistry(s); +}, 'symbol'); + +assert.throws(TypeError, function() { + new FinalizationRegistry(true); +}, 'Boolean, true'); + +assert.throws(TypeError, function() { + new FinalizationRegistry(false); +}, 'Boolean, false'); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/undefined-newtarget-throws.js b/js/src/tests/test262/built-ins/FinalizationRegistry/undefined-newtarget-throws.js new file mode 100644 index 0000000000..ebdef99c37 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/undefined-newtarget-throws.js @@ -0,0 +1,31 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-target +description: > + Throws a TypeError if NewTarget is undefined. +info: | + FinalizationRegistry ( cleanupCallback ) + + 1. If NewTarget is undefined, throw a TypeError exception. + 2. If IsCallable(cleanupCallback) is false, throw a TypeError exception. + ... +features: [FinalizationRegistry] +---*/ + +assert.sameValue( + typeof FinalizationRegistry, 'function', + 'typeof FinalizationRegistry is function' +); + +assert.throws(TypeError, function() { + FinalizationRegistry(); +}); + +assert.throws(TypeError, function() { + FinalizationRegistry(function() {}); +}); + +reportCompare(0, 0); diff --git a/js/src/tests/test262/built-ins/FinalizationRegistry/unnaffected-by-poisoned-cleanupCallback.js b/js/src/tests/test262/built-ins/FinalizationRegistry/unnaffected-by-poisoned-cleanupCallback.js new file mode 100644 index 0000000000..a28a89ed91 --- /dev/null +++ b/js/src/tests/test262/built-ins/FinalizationRegistry/unnaffected-by-poisoned-cleanupCallback.js @@ -0,0 +1,36 @@ +// |reftest| skip-if(!this.hasOwnProperty('FinalizationRegistry')) -- FinalizationRegistry is not enabled unconditionally +// 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-target +description: > + Normal completion even if the cleanupCallback fn is poisoned +info: | + FinalizationRegistry ( cleanupCallback ) + + ... + 3. Let finalizationRegistry be ? OrdinaryCreateFromConstructor(NewTarget, "%FinalizationRegistryPrototype%", « [[Realm]], [[CleanupCallback]], [[Cells]], [[IsFinalizationRegistryCleanupJobActive]] »). + ... + 9. Return finalizationRegistry. +features: [FinalizationRegistry] +---*/ + +var cleanupCallback = function() { throw new Test262Error('should not throw yet'); }; +var finalizationRegistry = new FinalizationRegistry(cleanupCallback); + +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), FinalizationRegistry.prototype); +assert.notSameValue(finalizationRegistry, cleanupCallback, 'does not return the same function'); +assert.sameValue(finalizationRegistry instanceof FinalizationRegistry, true, 'instanceof'); + +for (let key of Object.getOwnPropertyNames(finalizationRegistry)) { + assert(false, `should not set any own named properties: ${key}`); +} + +for (let key of Object.getOwnPropertySymbols(finalizationRegistry)) { + assert(false, `should not set any own symbol properties: ${String(key)}`); +} + +assert.sameValue(Object.getPrototypeOf(finalizationRegistry), FinalizationRegistry.prototype); + +reportCompare(0, 0); |