LibGC: Make MarkingVisitor better at bulk-visiting Vector<JS::Value>
When passing a Vector<JS::Value> to the MarkingVisitor, we were iterating over the vector and visiting one value at a time. This led to a very inefficient way of building up the GC's work queue. By adding a new visit_impl() virtual to Cell::Visitor, we can now grow the work queue capacity once, and then add without incrementally growing the storage.
This commit is contained in:
parent
2ac363dcba
commit
8b19992f8c
3 changed files with 54 additions and 0 deletions
|
|
@ -16,6 +16,7 @@
|
|||
#include <AK/Weakable.h>
|
||||
#include <LibGC/Forward.h>
|
||||
#include <LibGC/Internals.h>
|
||||
#include <LibGC/NanBoxedValue.h>
|
||||
#include <LibGC/Ptr.h>
|
||||
|
||||
namespace GC {
|
||||
|
|
@ -103,6 +104,13 @@ public:
|
|||
visit(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(ReadonlySpan<T> span)
|
||||
requires(IsBaseOf<NanBoxedValue, T>)
|
||||
{
|
||||
visit_impl(ReadonlySpan<NanBoxedValue>(span.data(), span.size()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(Span<T> span)
|
||||
{
|
||||
|
|
@ -110,6 +118,13 @@ public:
|
|||
visit(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(Span<T> span)
|
||||
requires(IsBaseOf<NanBoxedValue, T>)
|
||||
{
|
||||
visit_impl(ReadonlySpan<NanBoxedValue>(span.data(), span.size()));
|
||||
}
|
||||
|
||||
template<typename T, size_t inline_capacity>
|
||||
void visit(Vector<T, inline_capacity> const& vector)
|
||||
{
|
||||
|
|
@ -117,6 +132,13 @@ public:
|
|||
visit(value);
|
||||
}
|
||||
|
||||
template<typename T, size_t inline_capacity>
|
||||
void visit(Vector<T, inline_capacity> const& vector)
|
||||
requires(IsBaseOf<NanBoxedValue, T>)
|
||||
{
|
||||
visit_impl(ReadonlySpan<NanBoxedValue>(vector.span().data(), vector.size()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(HashTable<T> const& table)
|
||||
{
|
||||
|
|
@ -173,6 +195,7 @@ public:
|
|||
|
||||
protected:
|
||||
virtual void visit_impl(Cell&) = 0;
|
||||
virtual void visit_impl(ReadonlySpan<NanBoxedValue>) = 0;
|
||||
virtual ~Visitor() = default;
|
||||
} SWIFT_UNSAFE_REFERENCE;
|
||||
|
||||
|
|
|
|||
|
|
@ -150,6 +150,12 @@ public:
|
|||
m_work_queue.append(cell);
|
||||
}
|
||||
|
||||
virtual void visit_impl(ReadonlySpan<NanBoxedValue> values) override
|
||||
{
|
||||
for (auto const& value : values)
|
||||
visit(value);
|
||||
}
|
||||
|
||||
virtual void visit_possible_values(ReadonlyBytes bytes) override
|
||||
{
|
||||
HashMap<FlatPtr, HeapRoot> possible_pointers;
|
||||
|
|
@ -490,6 +496,23 @@ public:
|
|||
m_work_queue.append(cell);
|
||||
}
|
||||
|
||||
virtual void visit_impl(ReadonlySpan<NanBoxedValue> values) override
|
||||
{
|
||||
m_work_queue.ensure_capacity(m_work_queue.size() + values.size());
|
||||
|
||||
for (auto value : values) {
|
||||
if (!value.is_cell())
|
||||
continue;
|
||||
auto& cell = value.as_cell();
|
||||
if (cell.is_marked())
|
||||
continue;
|
||||
dbgln_if(HEAP_DEBUG, " ! {}", &cell);
|
||||
|
||||
cell.set_marked(true);
|
||||
m_work_queue.unchecked_append(cell);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit_possible_values(ReadonlyBytes bytes) override
|
||||
{
|
||||
HashMap<FlatPtr, HeapRoot> possible_pointers;
|
||||
|
|
|
|||
|
|
@ -260,6 +260,14 @@ struct ExecutionContextRootsCollector : public Cell::Visitor {
|
|||
roots.set(&cell);
|
||||
}
|
||||
|
||||
virtual void visit_impl(ReadonlySpan<GC::NanBoxedValue> values) override
|
||||
{
|
||||
for (auto const& value : values) {
|
||||
if (value.is_cell())
|
||||
roots.set(value.as_cell());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit_possible_values(ReadonlyBytes) override
|
||||
{
|
||||
VERIFY_NOT_REACHED();
|
||||
|
|
|
|||
Loading…
Reference in a new issue