From a119b6178295e948639ae963a53d7a867711cd32 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 18 Mar 2020 20:03:17 +0100 Subject: [PATCH] LibJS: Add Handle, a strong C++ handle for keeping GC objects alive This is pretty heavy and unoptimized, but it will do the trick for now. Basically, Heap now has a HashTable and you can call JS::make_handle(T*) to construct a Handle that guarantees that the pointee will always survive GC until the Handle is destroyed. --- Libraries/LibJS/Forward.h | 4 +++ Libraries/LibJS/Heap/Handle.cpp | 18 +++++++++++ Libraries/LibJS/Heap/Handle.h | 57 +++++++++++++++++++++++++++++++++ Libraries/LibJS/Heap/Heap.cpp | 17 ++++++++++ Libraries/LibJS/Heap/Heap.h | 6 ++++ Libraries/LibJS/Makefile | 1 + 6 files changed, 103 insertions(+) create mode 100644 Libraries/LibJS/Heap/Handle.cpp create mode 100644 Libraries/LibJS/Heap/Handle.h diff --git a/Libraries/LibJS/Forward.h b/Libraries/LibJS/Forward.h index 36895e65879..8e1febcfcd8 100644 --- a/Libraries/LibJS/Forward.h +++ b/Libraries/LibJS/Forward.h @@ -33,6 +33,7 @@ class Argument; class Cell; class Expression; class Function; +class HandleImpl; class Heap; class HeapBlock; class Interpreter; @@ -42,4 +43,7 @@ class ScopeNode; class Value; enum class DeclarationType; +template +class Handle; + } diff --git a/Libraries/LibJS/Heap/Handle.cpp b/Libraries/LibJS/Heap/Handle.cpp new file mode 100644 index 00000000000..e8bd7f26216 --- /dev/null +++ b/Libraries/LibJS/Heap/Handle.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + +namespace JS { + +HandleImpl::HandleImpl(Cell* cell) + : m_cell(cell) +{ + m_cell->heap().did_create_handle({}, *this); +} + +HandleImpl::~HandleImpl() +{ + m_cell->heap().did_destroy_handle({}, *this); +} + +} diff --git a/Libraries/LibJS/Heap/Handle.h b/Libraries/LibJS/Heap/Handle.h new file mode 100644 index 00000000000..ec5695e43a7 --- /dev/null +++ b/Libraries/LibJS/Heap/Handle.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace JS { + +class HandleImpl : public RefCounted { + AK_MAKE_NONCOPYABLE(HandleImpl); + AK_MAKE_NONMOVABLE(HandleImpl); + +public: + ~HandleImpl(); + + Cell* cell() { return m_cell; } + const Cell* cell() const { return m_cell; } + +private: + template + friend class Handle; + + explicit HandleImpl(Cell*); + Cell* m_cell { nullptr }; +}; + +template +class Handle { +public: + Handle() {} + + static Handle create(T* cell) + { + return Handle(adopt(*new HandleImpl(cell))); + } + + T* cell() { return static_cast(m_impl->cell()); } + const T* cell() const { return static_cast(m_impl->cell()); } + +private: + explicit Handle(NonnullRefPtr impl) + : m_impl(move(impl)) + { + } + + RefPtr m_impl; +}; + +template +inline Handle make_handle(T* cell) +{ + return Handle::create(cell); +} + +} diff --git a/Libraries/LibJS/Heap/Heap.cpp b/Libraries/LibJS/Heap/Heap.cpp index f8ee6794c7e..047e039a64a 100644 --- a/Libraries/LibJS/Heap/Heap.cpp +++ b/Libraries/LibJS/Heap/Heap.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -79,6 +80,9 @@ void Heap::gather_roots(HashTable& roots) gather_conservative_roots(roots); + for (auto* handle : m_handles) + roots.set(handle->cell()); + #ifdef HEAP_DEBUG dbg() << "gather_roots:"; for (auto* root : roots) { @@ -196,4 +200,17 @@ void Heap::sweep_dead_cells() }); } } + +void Heap::did_create_handle(Badge, HandleImpl& impl) +{ + ASSERT(!m_handles.contains(&impl)); + m_handles.set(&impl); +} + +void Heap::did_destroy_handle(Badge, HandleImpl& impl) +{ + ASSERT(m_handles.contains(&impl)); + m_handles.remove(&impl); +} + } diff --git a/Libraries/LibJS/Heap/Heap.h b/Libraries/LibJS/Heap/Heap.h index 53e85fe8a51..53ec59d2258 100644 --- a/Libraries/LibJS/Heap/Heap.h +++ b/Libraries/LibJS/Heap/Heap.h @@ -26,11 +26,13 @@ #pragma once +#include #include #include #include #include #include +#include #include namespace JS { @@ -58,6 +60,9 @@ public: bool should_collect_on_every_allocation() const { return m_should_collect_on_every_allocation; } void set_should_collect_on_every_allocation(bool b) { m_should_collect_on_every_allocation = b; } + void did_create_handle(Badge, HandleImpl&); + void did_destroy_handle(Badge, HandleImpl&); + private: Cell* allocate_cell(size_t); @@ -72,6 +77,7 @@ private: Interpreter& m_interpreter; Vector> m_blocks; + HashTable m_handles; }; } diff --git a/Libraries/LibJS/Makefile b/Libraries/LibJS/Makefile index d7e06e7b4bf..084a2155fe3 100644 --- a/Libraries/LibJS/Makefile +++ b/Libraries/LibJS/Makefile @@ -1,5 +1,6 @@ OBJS = \ AST.o \ + Heap/Handle.o \ Heap/Heap.o \ Heap/HeapBlock.o \ Interpreter.o \