diff --git a/Libraries/LibGC/RootHashMap.h b/Libraries/LibGC/RootHashMap.h index 2dcb8feb7d..3b8a93fbe8 100644 --- a/Libraries/LibGC/RootHashMap.h +++ b/Libraries/LibGC/RootHashMap.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace GC { @@ -49,24 +50,15 @@ public: virtual void gather_roots(HashMap& roots) const override { - static constexpr bool KeyIsGCType = IsBaseOf || IsConvertible; - static constexpr bool ValueIsGCType = IsBaseOf || IsConvertible; + static constexpr bool KeyIsGCType = Detail::RootableValueTraits::is_rootable; + static constexpr bool ValueIsGCType = Detail::RootableValueTraits::is_rootable; static_assert(KeyIsGCType || ValueIsGCType, "RootHashMap requires at least one of key or value types to be convertible to Cell const* or derive from NanBoxedValue"); for (auto& [key, value] : *this) { - if constexpr (IsBaseOf) { - if (key.is_cell()) - roots.set(&const_cast(key).as_cell(), HeapRoot { .type = HeapRoot::Type::RootHashMap }); - } else if constexpr (IsConvertible) { - roots.set(const_cast(static_cast(key)), HeapRoot { .type = HeapRoot::Type::RootHashMap }); - } - - if constexpr (IsBaseOf) { - if (value.is_cell()) - roots.set(&const_cast(value).as_cell(), HeapRoot { .type = HeapRoot::Type::RootHashMap }); - } else if constexpr (IsConvertible) { - roots.set(const_cast(static_cast(value)), HeapRoot { .type = HeapRoot::Type::RootHashMap }); - } + if constexpr (KeyIsGCType) + Detail::gather_root(roots, key, HeapRoot::Type::RootHashMap); + if constexpr (ValueIsGCType) + Detail::gather_root(roots, value, HeapRoot::Type::RootHashMap); } } }; diff --git a/Libraries/LibGC/RootHashTable.h b/Libraries/LibGC/RootHashTable.h index 23d89f9a39..9ccf6eadc1 100644 --- a/Libraries/LibGC/RootHashTable.h +++ b/Libraries/LibGC/RootHashTable.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace GC { @@ -48,16 +49,10 @@ public: virtual void gather_roots(HashMap& roots) const override { - static_assert(IsBaseOf || IsConvertible, + static_assert(Detail::RootableValueTraits::is_rootable, "RootHashTable element type must be convertible to Cell const* or derive from NanBoxedValue"); - for (auto& value : *this) { - if constexpr (IsBaseOf) { - if (value.is_cell()) - roots.set(&const_cast(value).as_cell(), HeapRoot { .type = HeapRoot::Type::RootHashTable }); - } else if constexpr (IsConvertible) { - roots.set(const_cast(static_cast(value)), HeapRoot { .type = HeapRoot::Type::RootHashTable }); - } - } + for (auto& value : *this) + Detail::gather_root(roots, value, HeapRoot::Type::RootHashTable); } }; diff --git a/Libraries/LibGC/RootVector.h b/Libraries/LibGC/RootVector.h index 68fbfc4c41..bb958a7dd9 100644 --- a/Libraries/LibGC/RootVector.h +++ b/Libraries/LibGC/RootVector.h @@ -13,6 +13,7 @@ #include #include #include +#include namespace GC { @@ -86,16 +87,10 @@ public: virtual void gather_roots(HashMap& roots) const override { - static_assert(IsBaseOf || IsConvertible, + static_assert(Detail::RootableValueTraits::is_rootable, "RootVector element type must be convertible to Cell const* or derive from NanBoxedValue"); - for (auto& value : *this) { - if constexpr (IsBaseOf) { - if (value.is_cell()) - roots.set(&const_cast(value).as_cell(), HeapRoot { .type = HeapRoot::Type::RootVector }); - } else if constexpr (IsConvertible) { - roots.set(const_cast(static_cast(value)), HeapRoot { .type = HeapRoot::Type::RootVector }); - } - } + for (auto& value : *this) + Detail::gather_root(roots, value, HeapRoot::Type::RootVector); } }; diff --git a/Libraries/LibGC/Rootable.h b/Libraries/LibGC/Rootable.h new file mode 100644 index 0000000000..ac66854d32 --- /dev/null +++ b/Libraries/LibGC/Rootable.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026, the Ladybird developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace GC::Detail { + +template +struct RootableValueTraits { + static constexpr bool is_rootable = IsBaseOf || IsConvertible; + + static Cell* cell(T const& value) + { + if constexpr (IsBaseOf) { + if (value.is_cell()) + return &const_cast(value).as_cell(); + } else if constexpr (IsConvertible) { + return const_cast(static_cast(value)); + } + + return nullptr; + } +}; + +template +static void gather_root(HashMap& roots, T const& value, HeapRoot::Type root_type) +{ + if (auto* cell = RootableValueTraits::cell(value)) + roots.set(cell, HeapRoot { .type = root_type }); +} + +}