diff --git a/Userland/Libraries/LibJS/Heap/Cell.h b/Userland/Libraries/LibJS/Heap/Cell.h index c870a998ee..d3820616ac 100644 --- a/Userland/Libraries/LibJS/Heap/Cell.h +++ b/Userland/Libraries/LibJS/Heap/Cell.h @@ -77,6 +77,9 @@ public: virtual bool is_environment() const { return false; } virtual void visit_edges(Visitor&) { } + // This will be called on unmarked objects by the garbage collector in a separate pass before destruction. + virtual void finalize() { } + Heap& heap() const; VM& vm() const; diff --git a/Userland/Libraries/LibJS/Heap/Heap.cpp b/Userland/Libraries/LibJS/Heap/Heap.cpp index a9860b9473..e7664761f6 100644 --- a/Userland/Libraries/LibJS/Heap/Heap.cpp +++ b/Userland/Libraries/LibJS/Heap/Heap.cpp @@ -106,6 +106,7 @@ void Heap::collect_garbage(CollectionType collection_type, bool print_report) gather_roots(roots); mark_live_cells(roots); } + finalize_unmarked_cells(); sweep_dead_cells(print_report, collection_measurement_timer); } @@ -231,6 +232,17 @@ void Heap::mark_live_cells(HashTable const& roots) m_uprooted_cells.clear(); } +void Heap::finalize_unmarked_cells() +{ + for_each_block([&](auto& block) { + block.template for_each_cell_in_state([](Cell* cell) { + if (!cell->is_marked()) + cell->finalize(); + }); + return IterationDecision::Continue; + }); +} + void Heap::sweep_dead_cells(bool print_report, Core::ElapsedTimer const& measurement_timer) { dbgln_if(HEAP_DEBUG, "sweep_dead_cells:"); diff --git a/Userland/Libraries/LibJS/Heap/Heap.h b/Userland/Libraries/LibJS/Heap/Heap.h index 435d7c6364..f8e43177d4 100644 --- a/Userland/Libraries/LibJS/Heap/Heap.h +++ b/Userland/Libraries/LibJS/Heap/Heap.h @@ -84,6 +84,7 @@ private: void gather_roots(HashTable&); void gather_conservative_roots(HashTable&); void mark_live_cells(HashTable const& live_cells); + void finalize_unmarked_cells(); void sweep_dead_cells(bool print_report, Core::ElapsedTimer const&); CellAllocator& allocator_for_size(size_t);