FinalizationRegistryPrototype.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /*
  2. * Copyright (c) 2021-2022, Idan Horowitz <idan.horowitz@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/TypeCasts.h>
  7. #include <LibJS/Runtime/AbstractOperations.h>
  8. #include <LibJS/Runtime/FinalizationRegistryPrototype.h>
  9. namespace JS {
  10. GC_DEFINE_ALLOCATOR(FinalizationRegistryPrototype);
  11. FinalizationRegistryPrototype::FinalizationRegistryPrototype(Realm& realm)
  12. : PrototypeObject(realm.intrinsics().object_prototype())
  13. {
  14. }
  15. void FinalizationRegistryPrototype::initialize(Realm& realm)
  16. {
  17. auto& vm = this->vm();
  18. Base::initialize(realm);
  19. u8 attr = Attribute::Writable | Attribute::Configurable;
  20. define_native_function(realm, vm.names.cleanupSome, cleanup_some, 0, attr);
  21. define_native_function(realm, vm.names.register_, register_, 2, attr);
  22. define_native_function(realm, vm.names.unregister, unregister, 1, attr);
  23. // 26.2.3.4 FinalizationRegistry.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-finalization-registry.prototype-@@tostringtag
  24. define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, vm.names.FinalizationRegistry.as_string()), Attribute::Configurable);
  25. }
  26. // @STAGE 2@ FinalizationRegistry.prototype.cleanupSome ( [ callback ] ), https://github.com/tc39/proposal-cleanup-some/blob/master/spec/finalization-registry.html
  27. JS_DEFINE_NATIVE_FUNCTION(FinalizationRegistryPrototype::cleanup_some)
  28. {
  29. auto callback = vm.argument(0);
  30. // 1. Let finalizationRegistry be the this value.
  31. // 2. Perform ? RequireInternalSlot(finalizationRegistry, [[Cells]]).
  32. auto finalization_registry = TRY(typed_this_object(vm));
  33. // 3. If callback is present and IsCallable(callback) is false, throw a TypeError exception.
  34. if (vm.argument_count() > 0 && !callback.is_function())
  35. return vm.throw_completion<TypeError>(ErrorType::NotAFunction, callback.to_string_without_side_effects());
  36. // IMPLEMENTATION DEFINED: The specification for this function hasn't been updated to accommodate for JobCallback records.
  37. // This just follows how the constructor immediately converts the callback to a JobCallback using HostMakeJobCallback.
  38. // 4. Perform ? CleanupFinalizationRegistry(finalizationRegistry, callback).
  39. TRY(finalization_registry->cleanup(callback.is_undefined() ? GC::Ptr<JobCallback> {} : vm.host_make_job_callback(callback.as_function())));
  40. // 5. Return undefined.
  41. return js_undefined();
  42. }
  43. // 26.2.3.2 FinalizationRegistry.prototype.register ( target, heldValue [ , unregisterToken ] ), https://tc39.es/ecma262/#sec-finalization-registry.prototype.register
  44. JS_DEFINE_NATIVE_FUNCTION(FinalizationRegistryPrototype::register_)
  45. {
  46. auto target = vm.argument(0);
  47. auto held_value = vm.argument(1);
  48. auto unregister_token = vm.argument(2);
  49. // 1. Let finalizationRegistry be the this value.
  50. // 2. Perform ? RequireInternalSlot(finalizationRegistry, [[Cells]]).
  51. auto finalization_registry = TRY(typed_this_object(vm));
  52. // 3. If target is not an Object, throw a TypeError exception.
  53. if (!can_be_held_weakly(target))
  54. return vm.throw_completion<TypeError>(ErrorType::CannotBeHeldWeakly, target.to_string_without_side_effects());
  55. // 4. If SameValue(target, heldValue) is true, throw a TypeError exception.
  56. if (same_value(target, held_value))
  57. return vm.throw_completion<TypeError>(ErrorType::FinalizationRegistrySameTargetAndValue);
  58. // 5. If unregisterToken is not an Object, then
  59. // a. If unregisterToken is not undefined, throw a TypeError exception.
  60. // b. Set unregisterToken to empty.
  61. if (!can_be_held_weakly(unregister_token) && !unregister_token.is_undefined())
  62. return vm.throw_completion<TypeError>(ErrorType::CannotBeHeldWeakly, unregister_token.to_string_without_side_effects());
  63. // 6. Let cell be the Record { [[WeakRefTarget]]: target, [[HeldValue]]: heldValue, [[UnregisterToken]]: unregisterToken }.
  64. // 7. Append cell to finalizationRegistry.[[Cells]].
  65. finalization_registry->add_finalization_record(target.as_cell(), held_value, unregister_token.is_undefined() ? nullptr : &unregister_token.as_cell());
  66. // 8. Return undefined.
  67. return js_undefined();
  68. }
  69. // 26.2.3.3 FinalizationRegistry.prototype.unregister ( unregisterToken ), https://tc39.es/ecma262/#sec-finalization-registry.prototype.unregister
  70. JS_DEFINE_NATIVE_FUNCTION(FinalizationRegistryPrototype::unregister)
  71. {
  72. auto unregister_token = vm.argument(0);
  73. // 1. Let finalizationRegistry be the this value.
  74. // 2. Perform ? RequireInternalSlot(finalizationRegistry, [[Cells]]).
  75. auto finalization_registry = TRY(typed_this_object(vm));
  76. // 3. If unregisterToken is not an Object, throw a TypeError exception.
  77. if (!can_be_held_weakly(unregister_token))
  78. return vm.throw_completion<TypeError>(ErrorType::CannotBeHeldWeakly, unregister_token.to_string_without_side_effects());
  79. // 4-6.
  80. return Value(finalization_registry->remove_by_token(unregister_token.as_cell()));
  81. }
  82. }