diff --git a/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.cpp b/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.cpp index aa2026fe33..42ddfe47d3 100644 --- a/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.cpp +++ b/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.cpp @@ -58,18 +58,30 @@ void FinalizationRegistry::remove_dead_cells(Badge) } // 9.13 CleanupFinalizationRegistry ( finalizationRegistry ), https://tc39.es/ecma262/#sec-cleanup-finalization-registry -void FinalizationRegistry::cleanup(FunctionObject* callback) +ThrowCompletionOr FinalizationRegistry::cleanup(FunctionObject* callback) { - auto& vm = this->vm(); + // 1. Assert: finalizationRegistry has [[Cells]] and [[CleanupCallback]] internal slots. + // Note: Ensured by type. + + // 2. Let callback be finalizationRegistry.[[CleanupCallback]]. auto cleanup_callback = callback ?: m_cleanup_callback; + + // 3. While finalizationRegistry.[[Cells]] contains a Record cell such that cell.[[WeakRefTarget]] is empty, an implementation may perform the following steps: for (auto it = m_records.begin(); it != m_records.end(); ++it) { + // a. Choose any such cell. if (it->target != nullptr) continue; - (void)call(global_object(), *cleanup_callback, js_undefined(), it->held_value); + auto cell = *it; + + // b. Remove cell from finalizationRegistry.[[Cells]]. it.remove(m_records); - if (vm.exception()) - return; + + // c. Perform ? HostCallJobCallback(callback, undefined, « cell.[[HeldValue]] »). + (void)TRY(call(global_object(), *cleanup_callback, js_undefined(), cell.held_value)); } + + // 4. Return NormalCompletion(empty). + return {}; } void FinalizationRegistry::visit_edges(Cell::Visitor& visitor) diff --git a/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.h b/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.h index 53f008f51e..a4b9a9696f 100644 --- a/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.h +++ b/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.h @@ -28,7 +28,7 @@ public: void add_finalization_record(Cell& target, Value held_value, Object* unregister_token); bool remove_by_token(Object& unregister_token); - void cleanup(FunctionObject* callback = nullptr); + ThrowCompletionOr cleanup(FunctionObject* callback = nullptr); virtual void remove_dead_cells(Badge) override; diff --git a/Userland/Libraries/LibJS/Runtime/FinalizationRegistryPrototype.cpp b/Userland/Libraries/LibJS/Runtime/FinalizationRegistryPrototype.cpp index 2a610d5c9e..7d90b8c797 100644 --- a/Userland/Libraries/LibJS/Runtime/FinalizationRegistryPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/FinalizationRegistryPrototype.cpp @@ -41,7 +41,7 @@ JS_DEFINE_NATIVE_FUNCTION(FinalizationRegistryPrototype::cleanup_some) if (vm.argument_count() > 0 && !callback.is_function()) return vm.throw_completion(global_object, ErrorType::NotAFunction, callback.to_string_without_side_effects()); - finalization_registry->cleanup(callback.is_undefined() ? nullptr : &callback.as_function()); + TRY(finalization_registry->cleanup(callback.is_undefined() ? nullptr : &callback.as_function())); return js_undefined(); }