mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-19 15:43:20 +00:00

This is a weak pointer that integrates with the garbage collector. It has a number of differences compared to AK::WeakPtr, including: - The "control block" is allocated from a well-packed WeakBlock owned by the GC heap, not just a generic malloc allocation. - Pointers to dead cells are nulled out by the garbage collector immediately before running destructors. - It works on any GC::Cell derived type, meaning you don't have to inherit from AK::Weakable for the ability to be weakly referenced. - The Weak always points to a control block, even when "null" (it then points to a null WeakImpl), which means one less null check when chasing pointers.
77 lines
1.9 KiB
C++
77 lines
1.9 KiB
C++
/*
|
|
* Copyright (c) 2025, Andreas Kling <andreas@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibGC/Cell.h>
|
|
#include <LibGC/WeakBlock.h>
|
|
#include <sys/mman.h>
|
|
|
|
#if defined(AK_OS_WINDOWS)
|
|
# include <AK/Windows.h>
|
|
# include <memoryapi.h>
|
|
#endif
|
|
|
|
namespace GC {
|
|
|
|
WeakImpl WeakImpl::the_null_weak_impl;
|
|
|
|
WeakBlock* WeakBlock::create()
|
|
{
|
|
#if !defined(AK_OS_WINDOWS)
|
|
auto* block = (HeapBlock*)mmap(nullptr, WeakBlock::BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
VERIFY(block != MAP_FAILED);
|
|
#else
|
|
auto* block = (HeapBlock*)VirtualAlloc(NULL, WeakBlock::BLOCK_SIZE, MEM_COMMIT, PAGE_READWRITE);
|
|
VERIFY(block);
|
|
#endif
|
|
return new (block) WeakBlock;
|
|
}
|
|
|
|
WeakBlock::WeakBlock()
|
|
{
|
|
for (size_t i = 0; i < IMPL_COUNT; ++i) {
|
|
m_impls[i].set_ptr({}, i + 1 < IMPL_COUNT ? &m_impls[i + 1] : nullptr);
|
|
m_impls[i].set_state(WeakImpl::State::Freelist);
|
|
}
|
|
m_freelist = &m_impls[0];
|
|
}
|
|
|
|
WeakBlock::~WeakBlock() = default;
|
|
|
|
WeakImpl* WeakBlock::allocate(Cell* cell)
|
|
{
|
|
auto* impl = m_freelist;
|
|
if (!impl)
|
|
return nullptr;
|
|
VERIFY(impl->ref_count() == 0);
|
|
m_freelist = impl->ptr() ? static_cast<WeakImpl*>(impl->ptr()) : nullptr;
|
|
impl->set_ptr({}, cell);
|
|
impl->set_state(WeakImpl::State::Allocated);
|
|
return impl;
|
|
}
|
|
|
|
void WeakBlock::deallocate(WeakImpl* impl)
|
|
{
|
|
VERIFY(impl->ref_count() == 0);
|
|
impl->set_ptr({}, m_freelist);
|
|
impl->set_state(WeakImpl::State::Freelist);
|
|
m_freelist = impl;
|
|
}
|
|
|
|
void WeakBlock::sweep()
|
|
{
|
|
for (size_t i = 0; i < IMPL_COUNT; ++i) {
|
|
auto& impl = m_impls[i];
|
|
if (impl.state() == WeakImpl::State::Freelist)
|
|
continue;
|
|
auto* cell = static_cast<Cell*>(impl.ptr());
|
|
if (!cell || !cell->is_marked())
|
|
impl.set_ptr({}, nullptr);
|
|
if (impl.ref_count() == 0)
|
|
deallocate(&impl);
|
|
}
|
|
}
|
|
|
|
}
|