summaryrefslogtreecommitdiffstats
path: root/js/src/tests/test262/built-ins/FinalizationRegistry
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/tests/test262/built-ins/FinalizationRegistry
parentInitial commit. (diff)
downloadfirefox-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')
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/constructor.js18
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/gc-has-one-chance-to-call-cleanupCallback-for-object.js97
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/instance-extensible.js33
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/is-a-constructor.js27
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/length.js35
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/name.js34
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/newtarget-prototype-is-not-object.js61
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prop-desc.js25
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/proto-from-ctor-realm.js62
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/proto.js21
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype-from-newtarget-abrupt.js44
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype-from-newtarget-custom.js47
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype-from-newtarget.js36
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/Symbol.toStringTag.js26
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/callback-not-callable-throws.js56
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/cleanup-prevented-with-reference.js48
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/cleanup-prevented-with-unregister.js55
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/custom-this.js29
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/holdings-multiple-values.js70
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/length.js35
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/name.js34
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/not-a-constructor.js36
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/prop-desc.js27
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/reentrancy.js52
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/return-undefined-with-gc.js67
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/return-undefined.js44
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/shell.js0
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/this-does-not-have-internal-cells-throws.js51
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/cleanupSome/this-not-object-throws.js53
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/constructor.js26
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/prop-desc.js21
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/proto.js17
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/custom-this.js31
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/heldValue-same-as-target.js38
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/holdings-any-value-type.js38
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/length.js35
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/name.js34
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/not-a-constructor.js36
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/prop-desc.js27
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/return-undefined-register-itself.js33
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/return-undefined-register-object.js46
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/return-undefined-register-symbol.js76
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/shell.js0
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/this-does-not-have-internal-target-throws.js51
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/this-not-object-throws.js54
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/throws-when-target-cannot-be-held-weakly.js47
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/throws-when-unregisterToken-not-undefined-and-cannot-be-held-weakly.js47
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/unregisterToken-same-as-holdings-and-target.js30
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/unregisterToken-same-as-holdings.js30
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/register/unregisterToken-same-as-target.js29
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/shell.js0
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/custom-this.js50
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/length.js35
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/name.js34
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/not-a-constructor.js36
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/prop-desc.js27
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/shell.js0
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/this-does-not-have-internal-cells-throws.js51
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/this-not-object-throws.js52
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/throws-when-unregisterToken-cannot-be-held-weakly.js47
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/unregister-cleaned-up-object-cell.js64
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/unregister-object-token.js57
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/prototype/unregister/unregister-symbol-token.js64
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/returns-new-object-from-constructor.js42
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/shell.js83
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/target-not-callable-throws.js72
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/undefined-newtarget-throws.js31
-rw-r--r--js/src/tests/test262/built-ins/FinalizationRegistry/unnaffected-by-poisoned-cleanupCallback.js36
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);