FinalizationRegistry.cpp 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  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_swept_cells(Badge<Heap>, Span<Cell*> cells)
  38. {
  39. auto any_cells_were_swept = false;
  40. for (auto* cell : cells) {
  41. for (auto& record : m_records) {
  42. if (record.target != cell)
  43. continue;
  44. record.target = nullptr;
  45. any_cells_were_swept = true;
  46. break;
  47. }
  48. }
  49. if (any_cells_were_swept)
  50. vm().enqueue_finalization_registry_cleanup_job(*this);
  51. }
  52. // 9.13 CleanupFinalizationRegistry ( finalizationRegistry ), https://tc39.es/ecma262/#sec-cleanup-finalization-registry
  53. void FinalizationRegistry::cleanup(FunctionObject* callback)
  54. {
  55. auto& vm = this->vm();
  56. auto cleanup_callback = callback ?: m_cleanup_callback;
  57. for (auto it = m_records.begin(); it != m_records.end(); ++it) {
  58. if (it->target != nullptr)
  59. continue;
  60. (void)vm.call(*cleanup_callback, js_undefined(), it->held_value);
  61. it.remove(m_records);
  62. if (vm.exception())
  63. return;
  64. }
  65. }
  66. void FinalizationRegistry::visit_edges(Cell::Visitor& visitor)
  67. {
  68. Base::visit_edges(visitor);
  69. visitor.visit(m_cleanup_callback);
  70. for (auto& record : m_records) {
  71. visitor.visit(record.held_value);
  72. visitor.visit(record.unregister_token);
  73. }
  74. }
  75. }