FinalizationRegistry.cpp 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. /*
  2. * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Runtime/FinalizationRegistry.h>
  7. namespace JS {
  8. FinalizationRegistry* FinalizationRegistry::create(GlobalObject& global_object, FunctionObject& cleanup_callback)
  9. {
  10. return global_object.heap().allocate<FinalizationRegistry>(global_object, cleanup_callback, *global_object.finalization_registry_prototype());
  11. }
  12. FinalizationRegistry::FinalizationRegistry(FunctionObject& cleanup_callback, Object& prototype)
  13. : Object(prototype)
  14. , WeakContainer(heap())
  15. , m_cleanup_callback(&cleanup_callback)
  16. {
  17. }
  18. FinalizationRegistry::~FinalizationRegistry()
  19. {
  20. }
  21. void FinalizationRegistry::add_finalization_record(Cell& target, Value held_value, Object* unregister_token)
  22. {
  23. VERIFY(!held_value.is_empty());
  24. m_records.append({ &target, held_value, unregister_token });
  25. }
  26. bool FinalizationRegistry::remove_by_token(Object& unregister_token)
  27. {
  28. auto removed = false;
  29. for (auto it = m_records.begin(); it != m_records.end(); ++it) {
  30. if (it->unregister_token == &unregister_token) {
  31. it.remove(m_records);
  32. removed = true;
  33. }
  34. }
  35. return removed;
  36. }
  37. void FinalizationRegistry::remove_dead_cells(Badge<Heap>)
  38. {
  39. auto any_cells_were_removed = false;
  40. for (auto& record : m_records) {
  41. if (!record.target || record.target->state() == Cell::State::Live)
  42. continue;
  43. record.target = nullptr;
  44. any_cells_were_removed = true;
  45. break;
  46. }
  47. if (any_cells_were_removed)
  48. vm().enqueue_finalization_registry_cleanup_job(*this);
  49. }
  50. // 9.13 CleanupFinalizationRegistry ( finalizationRegistry ), https://tc39.es/ecma262/#sec-cleanup-finalization-registry
  51. void FinalizationRegistry::cleanup(FunctionObject* callback)
  52. {
  53. auto& vm = this->vm();
  54. auto cleanup_callback = callback ?: m_cleanup_callback;
  55. for (auto it = m_records.begin(); it != m_records.end(); ++it) {
  56. if (it->target != nullptr)
  57. continue;
  58. (void)vm.call(*cleanup_callback, js_undefined(), it->held_value);
  59. it.remove(m_records);
  60. if (vm.exception())
  61. return;
  62. }
  63. }
  64. void FinalizationRegistry::visit_edges(Cell::Visitor& visitor)
  65. {
  66. Base::visit_edges(visitor);
  67. visitor.visit(m_cleanup_callback);
  68. for (auto& record : m_records) {
  69. visitor.visit(record.held_value);
  70. visitor.visit(record.unregister_token);
  71. }
  72. }
  73. }