diff --git a/Libraries/LibGC/CMakeLists.txt b/Libraries/LibGC/CMakeLists.txt index 40f75433829..ee3201d9c61 100644 --- a/Libraries/LibGC/CMakeLists.txt +++ b/Libraries/LibGC/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES ConservativeVector.cpp ForeignCell.cpp Root.cpp + RootHashMap.cpp RootVector.cpp Heap.cpp HeapBlock.cpp diff --git a/Libraries/LibGC/Heap.cpp b/Libraries/LibGC/Heap.cpp index 9617211726d..0c258537781 100644 --- a/Libraries/LibGC/Heap.cpp +++ b/Libraries/LibGC/Heap.cpp @@ -282,6 +282,9 @@ void Heap::gather_roots(HashMap& roots) for (auto& vector : m_root_vectors) vector.gather_roots(roots); + for (auto& hash_map : m_root_hash_maps) + hash_map.gather_roots(roots); + if constexpr (HEAP_DEBUG) { dbgln("gather_roots:"); for (auto* root : roots.keys()) diff --git a/Libraries/LibGC/Heap.h b/Libraries/LibGC/Heap.h index 5b39c1b6f80..315cc66ad4e 100644 --- a/Libraries/LibGC/Heap.h +++ b/Libraries/LibGC/Heap.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,9 @@ public: void did_create_root_vector(Badge, RootVectorBase&); void did_destroy_root_vector(Badge, RootVectorBase&); + void did_create_root_hash_map(Badge, RootHashMapBase&); + void did_destroy_root_hash_map(Badge, RootHashMapBase&); + void did_create_conservative_vector(Badge, ConservativeVectorBase&); void did_destroy_conservative_vector(Badge, ConservativeVectorBase&); @@ -142,6 +146,7 @@ private: RootImpl::List m_roots; RootVectorBase::List m_root_vectors; + RootHashMapBase::List m_root_hash_maps; ConservativeVectorBase::List m_conservative_vectors; WeakContainer::List m_weak_containers; @@ -181,6 +186,18 @@ inline void Heap::did_destroy_root_vector(Badge, RootVectorBase& m_root_vectors.remove(vector); } +inline void Heap::did_create_root_hash_map(Badge, RootHashMapBase& hash_map) +{ + VERIFY(!m_root_hash_maps.contains(hash_map)); + m_root_hash_maps.append(hash_map); +} + +inline void Heap::did_destroy_root_hash_map(Badge, RootHashMapBase& hash_map) +{ + VERIFY(m_root_hash_maps.contains(hash_map)); + m_root_hash_maps.remove(hash_map); +} + inline void Heap::did_create_conservative_vector(Badge, ConservativeVectorBase& vector) { VERIFY(!m_conservative_vectors.contains(vector)); diff --git a/Libraries/LibGC/HeapRoot.h b/Libraries/LibGC/HeapRoot.h index 26f03ef26ef..939f3863d98 100644 --- a/Libraries/LibGC/HeapRoot.h +++ b/Libraries/LibGC/HeapRoot.h @@ -15,6 +15,7 @@ struct HeapRoot { HeapFunctionCapturedPointer, Root, RootVector, + RootHashMap, ConservativeVector, RegisterPointer, StackPointer, diff --git a/Libraries/LibGC/RootHashMap.cpp b/Libraries/LibGC/RootHashMap.cpp new file mode 100644 index 00000000000..439d7e108b4 --- /dev/null +++ b/Libraries/LibGC/RootHashMap.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace GC { + +RootHashMapBase::RootHashMapBase(Heap& heap) + : m_heap(&heap) +{ + m_heap->did_create_root_hash_map({}, *this); +} + +RootHashMapBase::~RootHashMapBase() +{ + m_heap->did_destroy_root_hash_map({}, *this); +} + +void RootHashMapBase::assign_heap(Heap* heap) +{ + if (m_heap == heap) + return; + + m_heap = heap; + + // NOTE: IntrusiveList will remove this RootHashMap from the old heap it was part of. + m_heap->did_create_root_hash_map({}, *this); +} + +} diff --git a/Libraries/LibGC/RootHashMap.h b/Libraries/LibGC/RootHashMap.h new file mode 100644 index 00000000000..fec2d48ae34 --- /dev/null +++ b/Libraries/LibGC/RootHashMap.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace GC { + +class RootHashMapBase { +public: + virtual void gather_roots(HashMap&) const = 0; + +protected: + explicit RootHashMapBase(Heap&); + ~RootHashMapBase(); + + void assign_heap(Heap*); + + Heap* m_heap { nullptr }; + IntrusiveListNode m_list_node; + +public: + using List = IntrusiveList<&RootHashMapBase::m_list_node>; +}; + +template, typename ValueTraits = Traits, bool IsOrdered = false> +class RootHashMap final + : public RootHashMapBase + , public HashMap { + + using HashMapBase = HashMap; + +public: + explicit RootHashMap(Heap& heap) + : RootHashMapBase(heap) + { + } + + virtual ~RootHashMap() = default; + + virtual void gather_roots(HashMap& roots) const override + { + for (auto& [key, value] : *this) { + if constexpr (IsBaseOf) { + if (value.is_cell()) + roots.set(&const_cast(value).as_cell(), HeapRoot { .type = HeapRoot::Type::RootHashMap }); + } else { + roots.set(value, HeapRoot { .type = HeapRoot::Type::RootHashMap }); + } + } + } +}; + +template, typename ValueTraits = Traits> +using OrderedRootHashMap = RootHashMap; + +}