diff --git a/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.cpp b/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.cpp index 2f35131b301..2a33a676ee7 100644 --- a/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.cpp +++ b/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Idan Horowitz + * Copyright (c) 2021-2022, Idan Horowitz * * SPDX-License-Identifier: BSD-2-Clause */ @@ -17,13 +17,13 @@ FinalizationRegistry::FinalizationRegistry(Realm& realm, JobCallback cleanup_cal { } -void FinalizationRegistry::add_finalization_record(Cell& target, Value held_value, Object* unregister_token) +void FinalizationRegistry::add_finalization_record(Cell& target, Value held_value, Cell* unregister_token) { VERIFY(!held_value.is_empty()); m_records.append({ &target, held_value, unregister_token }); } -bool FinalizationRegistry::remove_by_token(Object& unregister_token) +bool FinalizationRegistry::remove_by_token(Cell& unregister_token) { auto removed = false; for (auto it = m_records.begin(); it != m_records.end(); ++it) { diff --git a/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.h b/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.h index 7967cacf927..83903c4b1bd 100644 --- a/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.h +++ b/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Idan Horowitz + * Copyright (c) 2021-2022, Idan Horowitz * * SPDX-License-Identifier: BSD-2-Clause */ @@ -25,8 +25,8 @@ public: explicit FinalizationRegistry(Realm&, JobCallback, Object& prototype); virtual ~FinalizationRegistry() override = default; - void add_finalization_record(Cell& target, Value held_value, Object* unregister_token); - bool remove_by_token(Object& unregister_token); + void add_finalization_record(Cell& target, Value held_value, Cell* unregister_token); + bool remove_by_token(Cell& unregister_token); ThrowCompletionOr cleanup(Optional = {}); virtual void remove_dead_cells(Badge) override; @@ -46,7 +46,7 @@ private: struct FinalizationRecord { Cell* target { nullptr }; Value held_value; - Object* unregister_token { nullptr }; + Cell* unregister_token { nullptr }; }; SinglyLinkedList m_records; }; diff --git a/Userland/Libraries/LibJS/Runtime/FinalizationRegistryPrototype.cpp b/Userland/Libraries/LibJS/Runtime/FinalizationRegistryPrototype.cpp index 765c916c71b..03f59b1538e 100644 --- a/Userland/Libraries/LibJS/Runtime/FinalizationRegistryPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/FinalizationRegistryPrototype.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Idan Horowitz + * Copyright (c) 2021-2022, Idan Horowitz * * SPDX-License-Identifier: BSD-2-Clause */ @@ -50,18 +50,18 @@ JS_DEFINE_NATIVE_FUNCTION(FinalizationRegistryPrototype::register_) auto* finalization_registry = TRY(typed_this_object(global_object)); auto target = vm.argument(0); - if (!target.is_object()) - return vm.throw_completion(global_object, ErrorType::NotAnObject, target.to_string_without_side_effects()); + if (!can_be_held_weakly(target)) + return vm.throw_completion(global_object, ErrorType::CannotBeHeldWeakly, target.to_string_without_side_effects()); auto held_value = vm.argument(1); if (same_value(target, held_value)) return vm.throw_completion(global_object, ErrorType::FinalizationRegistrySameTargetAndValue); auto unregister_token = vm.argument(2); - if (!unregister_token.is_object() && !unregister_token.is_undefined()) - return vm.throw_completion(global_object, ErrorType::NotAnObject, unregister_token.to_string_without_side_effects()); + if (!can_be_held_weakly(unregister_token) && !unregister_token.is_undefined()) + return vm.throw_completion(global_object, ErrorType::CannotBeHeldWeakly, unregister_token.to_string_without_side_effects()); - finalization_registry->add_finalization_record(target.as_cell(), held_value, unregister_token.is_undefined() ? nullptr : &unregister_token.as_object()); + finalization_registry->add_finalization_record(target.as_cell(), held_value, unregister_token.is_undefined() ? nullptr : &unregister_token.as_cell()); return js_undefined(); } @@ -72,10 +72,10 @@ JS_DEFINE_NATIVE_FUNCTION(FinalizationRegistryPrototype::unregister) auto* finalization_registry = TRY(typed_this_object(global_object)); auto unregister_token = vm.argument(0); - if (!unregister_token.is_object()) - return vm.throw_completion(global_object, ErrorType::NotAnObject, unregister_token.to_string_without_side_effects()); + if (!can_be_held_weakly(unregister_token)) + return vm.throw_completion(global_object, ErrorType::CannotBeHeldWeakly, unregister_token.to_string_without_side_effects()); - return Value(finalization_registry->remove_by_token(unregister_token.as_object())); + return Value(finalization_registry->remove_by_token(unregister_token.as_cell())); } } diff --git a/Userland/Libraries/LibJS/Tests/builtins/FinalizationRegistry/FinalizationRegistry.prototype.register.js b/Userland/Libraries/LibJS/Tests/builtins/FinalizationRegistry/FinalizationRegistry.prototype.register.js index 04daa86ad34..e33ea6c8d90 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/FinalizationRegistry/FinalizationRegistry.prototype.register.js +++ b/Userland/Libraries/LibJS/Tests/builtins/FinalizationRegistry/FinalizationRegistry.prototype.register.js @@ -12,9 +12,15 @@ test("basic functionality", () => { var target2 = {}; var heldValue2 = {}; - var token = {}; + var token1 = {}; - registry.register(target2, heldValue2, token); + registry.register(target2, heldValue2, token1); + + var target3 = Symbol("target"); + var heldValue3 = {}; + var token2 = Symbol("token"); + + registry.register(target3, heldValue3, token2); }); test("errors", () => { @@ -22,14 +28,19 @@ test("errors", () => { expect(() => { registry.register(5, {}); - }).toThrowWithMessage(TypeError, "is not an object"); + }).toThrowWithMessage(TypeError, "cannot be held weakly"); expect(() => { var a = {}; registry.register(a, a); }).toThrowWithMessage(TypeError, "Target and held value must not be the same"); + expect(() => { + var a = Symbol(); + registry.register(a, a); + }).toThrowWithMessage(TypeError, "Target and held value must not be the same"); + expect(() => { registry.register({}, {}, 5); - }).toThrowWithMessage(TypeError, "is not an object"); + }).toThrowWithMessage(TypeError, "cannot be held weakly"); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/FinalizationRegistry/FinalizationRegistry.prototype.unregister.js b/Userland/Libraries/LibJS/Tests/builtins/FinalizationRegistry/FinalizationRegistry.prototype.unregister.js index b67c9c9f696..91bc8028891 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/FinalizationRegistry/FinalizationRegistry.prototype.unregister.js +++ b/Userland/Libraries/LibJS/Tests/builtins/FinalizationRegistry/FinalizationRegistry.prototype.unregister.js @@ -5,15 +5,25 @@ test("length is 2", () => { test("basic functionality", () => { var registry = new FinalizationRegistry(() => {}); - var target = {}; - var heldValue = {}; - var token = {}; + var target1 = {}; + var heldValue1 = {}; + var token1 = {}; - registry.register(target, heldValue, token); + registry.register(target1, heldValue1, token1); expect(registry.unregister({})).toBe(false); - expect(registry.unregister(token)).toBe(true); - expect(registry.unregister(token)).toBe(false); + expect(registry.unregister(token1)).toBe(true); + expect(registry.unregister(token1)).toBe(false); + + var target2 = Symbol("target"); + var heldValue2 = Symbol("heldValue"); + var token2 = Symbol("token"); + + registry.register(target2, heldValue2, token2); + + expect(registry.unregister(Symbol("token"))).toBe(false); + expect(registry.unregister(token2)).toBe(true); + expect(registry.unregister(token2)).toBe(false); }); test("errors", () => { @@ -21,5 +31,5 @@ test("errors", () => { expect(() => { registry.unregister(5); - }).toThrowWithMessage(TypeError, "is not an object"); + }).toThrowWithMessage(TypeError, "cannot be held weakly"); });