diff --git a/Libraries/LibJS/CMakeLists.txt b/Libraries/LibJS/CMakeLists.txt index 86d710e49dc..ede0471ca1a 100644 --- a/Libraries/LibJS/CMakeLists.txt +++ b/Libraries/LibJS/CMakeLists.txt @@ -21,6 +21,7 @@ set(SOURCES CyclicModule.cpp Heap/BlockAllocator.cpp Heap/Cell.cpp + Heap/CellImpl.cpp Heap/CellAllocator.cpp Heap/ConservativeVector.cpp Heap/Handle.cpp diff --git a/Libraries/LibJS/Forward.h b/Libraries/LibJS/Forward.h index beed9e05553..ef6bffcdd6e 100644 --- a/Libraries/LibJS/Forward.h +++ b/Libraries/LibJS/Forward.h @@ -159,6 +159,7 @@ class BigInt; class BoundFunction; struct CachedSourceRange; class Cell; +class CellImpl; class CellAllocator; class ClassExpression; struct ClassFieldDefinition; diff --git a/Libraries/LibJS/Heap/Cell.cpp b/Libraries/LibJS/Heap/Cell.cpp index c3970ab2c2d..ad142977df8 100644 --- a/Libraries/LibJS/Heap/Cell.cpp +++ b/Libraries/LibJS/Heap/Cell.cpp @@ -5,19 +5,11 @@ */ #include -#include -#include namespace JS { -void JS::Cell::initialize(JS::Realm&) +void Cell::initialize(Realm&) { } -void JS::Cell::Visitor::visit(NanBoxedValue const& value) -{ - if (value.is_cell()) - visit_impl(value.as_cell()); -} - } diff --git a/Libraries/LibJS/Heap/Cell.h b/Libraries/LibJS/Heap/Cell.h index c2989e0f238..84427ca1697 100644 --- a/Libraries/LibJS/Heap/Cell.h +++ b/Libraries/LibJS/Heap/Cell.h @@ -6,200 +6,17 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace JS { -// This instrumentation tells analysis tooling to ignore a potentially mis-wrapped GC-allocated member variable -// It should only be used when the lifetime of the GC-allocated member is always longer than the object -#if defined(AK_COMPILER_CLANG) -# define IGNORE_GC [[clang::annotate("serenity::ignore_gc")]] -#else -# define IGNORE_GC -#endif - -#define JS_CELL(class_, base_class) \ -public: \ - using Base = base_class; \ - virtual StringView class_name() const override \ - { \ - return #class_##sv; \ - } \ - friend class JS::Heap; - -class Cell : public Weakable { - AK_MAKE_NONCOPYABLE(Cell); - AK_MAKE_NONMOVABLE(Cell); +class Cell : public CellImpl { + JS_CELL(Cell, CellImpl); public: virtual void initialize(Realm&); - virtual ~Cell() = default; - bool is_marked() const { return m_mark; } - void set_marked(bool b) { m_mark = b; } - - enum class State : bool { - Live, - Dead, - }; - - State state() const { return m_state; } - void set_state(State state) { m_state = state; } - - virtual StringView class_name() const = 0; - - class Visitor { - public: - void visit(Cell* cell) - { - if (cell) - visit_impl(*cell); - } - - void visit(Cell& cell) - { - visit_impl(cell); - } - - void visit(Cell const* cell) - { - visit(const_cast(cell)); - } - - void visit(Cell const& cell) - { - visit(const_cast(cell)); - } - - template - void visit(GCPtr cell) - { - if (cell) - visit_impl(const_cast&>(*cell.ptr())); - } - - template - void visit(NonnullGCPtr cell) - { - visit_impl(const_cast&>(*cell.ptr())); - } - - template - void visit(ReadonlySpan span) - { - for (auto& value : span) - visit(value); - } - - template - void visit(Span span) - { - for (auto& value : span) - visit(value); - } - - template - void visit(Vector const& vector) - { - for (auto& value : vector) - visit(value); - } - - template - void visit(HashTable const& table) - { - for (auto& value : table) - visit(value); - } - - template - void visit(OrderedHashTable const& table) - { - for (auto& value : table) - visit(value); - } - - template - void visit(HashMap const& map) - { - for (auto& it : map) { - if constexpr (requires { visit(it.key); }) - visit(it.key); - if constexpr (requires { visit(it.value); }) - visit(it.value); - } - } - - template - void visit(OrderedHashMap const& map) - { - for (auto& it : map) { - if constexpr (requires { visit(it.key); }) - visit(it.key); - if constexpr (requires { visit(it.value); }) - visit(it.value); - } - } - - void visit(NanBoxedValue const& value); - - // Allow explicitly ignoring a GC-allocated member in a visit_edges implementation instead - // of just not using it. - template - void ignore(T const&) - { - } - - virtual void visit_possible_values(ReadonlyBytes) = 0; - - protected: - virtual void visit_impl(Cell&) = 0; - virtual ~Visitor() = default; - }; - - virtual void visit_edges(Visitor&) { } - - // This will be called on unmarked objects by the garbage collector in a separate pass before destruction. - virtual void finalize() { } - - // This allows cells to survive GC by choice, even if nothing points to them. - // It's used to implement special rules in the web platform. - // NOTE: Cells must call set_overrides_must_survive_garbage_collection() for this to be honored. - virtual bool must_survive_garbage_collection() const { return false; } - - bool overrides_must_survive_garbage_collection(Badge) const { return m_overrides_must_survive_garbage_collection; } - - ALWAYS_INLINE Heap& heap() const { return HeapBlockBase::from_cell(this)->heap(); } - ALWAYS_INLINE VM& vm() const { return bit_cast(&heap())->vm(); } - -protected: - Cell() = default; - - void set_overrides_must_survive_garbage_collection(bool b) { m_overrides_must_survive_garbage_collection = b; } - -private: - bool m_mark : 1 { false }; - bool m_overrides_must_survive_garbage_collection : 1 { false }; - State m_state : 1 { State::Live }; + ALWAYS_INLINE VM& vm() const { return *reinterpret_cast(private_data()); } }; } - -template<> -struct AK::Formatter : AK::Formatter { - ErrorOr format(FormatBuilder& builder, JS::Cell const* cell) - { - if (!cell) - return builder.put_string("Cell{nullptr}"sv); - return Formatter::format(builder, "{}({})"sv, cell->class_name(), cell); - } -}; diff --git a/Libraries/LibJS/Heap/CellAllocator.cpp b/Libraries/LibJS/Heap/CellAllocator.cpp index 6a5726b7ab0..fe8d00578dc 100644 --- a/Libraries/LibJS/Heap/CellAllocator.cpp +++ b/Libraries/LibJS/Heap/CellAllocator.cpp @@ -18,7 +18,7 @@ CellAllocator::CellAllocator(size_t cell_size, char const* class_name) { } -Cell* CellAllocator::allocate_cell(Heap& heap) +CellImpl* CellAllocator::allocate_cell(Heap& heap) { if (!m_list_node.is_in_list()) heap.register_cell_allocator({}, *this); diff --git a/Libraries/LibJS/Heap/CellAllocator.h b/Libraries/LibJS/Heap/CellAllocator.h index b63fb19813b..beece07829f 100644 --- a/Libraries/LibJS/Heap/CellAllocator.h +++ b/Libraries/LibJS/Heap/CellAllocator.h @@ -28,7 +28,7 @@ public: size_t cell_size() const { return m_cell_size; } - Cell* allocate_cell(Heap&); + CellImpl* allocate_cell(Heap&); template IterationDecision for_each_block(Callback callback) diff --git a/Libraries/LibJS/Heap/CellImpl.cpp b/Libraries/LibJS/Heap/CellImpl.cpp new file mode 100644 index 00000000000..13673de8f57 --- /dev/null +++ b/Libraries/LibJS/Heap/CellImpl.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020-2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace JS { + +void JS::CellImpl::Visitor::visit(NanBoxedValue const& value) +{ + if (value.is_cell()) + visit_impl(value.as_cell()); +} + +} diff --git a/Libraries/LibJS/Heap/CellImpl.h b/Libraries/LibJS/Heap/CellImpl.h new file mode 100644 index 00000000000..14c42add160 --- /dev/null +++ b/Libraries/LibJS/Heap/CellImpl.h @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2020-2024, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace JS { + +// This instrumentation tells analysis tooling to ignore a potentially mis-wrapped GC-allocated member variable +// It should only be used when the lifetime of the GC-allocated member is always longer than the object +#if defined(AK_COMPILER_CLANG) +# define IGNORE_GC [[clang::annotate("serenity::ignore_gc")]] +#else +# define IGNORE_GC +#endif + +#define JS_CELL(class_, base_class) \ +public: \ + using Base = base_class; \ + virtual StringView class_name() const override \ + { \ + return #class_##sv; \ + } \ + friend class JS::Heap; + +class CellImpl : public Weakable { + AK_MAKE_NONCOPYABLE(CellImpl); + AK_MAKE_NONMOVABLE(CellImpl); + +public: + virtual ~CellImpl() = default; + + bool is_marked() const { return m_mark; } + void set_marked(bool b) { m_mark = b; } + + enum class State : bool { + Live, + Dead, + }; + + State state() const { return m_state; } + void set_state(State state) { m_state = state; } + + virtual StringView class_name() const = 0; + + class Visitor { + public: + void visit(CellImpl* cell) + { + if (cell) + visit_impl(*cell); + } + + void visit(CellImpl& cell) + { + visit_impl(cell); + } + + void visit(CellImpl const* cell) + { + visit(const_cast(cell)); + } + + void visit(CellImpl const& cell) + { + visit(const_cast(cell)); + } + + template + void visit(GCPtr cell) + { + if (cell) + visit_impl(const_cast&>(*cell.ptr())); + } + + template + void visit(NonnullGCPtr cell) + { + visit_impl(const_cast&>(*cell.ptr())); + } + + template + void visit(ReadonlySpan span) + { + for (auto& value : span) + visit(value); + } + + template + void visit(Span span) + { + for (auto& value : span) + visit(value); + } + + template + void visit(Vector const& vector) + { + for (auto& value : vector) + visit(value); + } + + template + void visit(HashTable const& table) + { + for (auto& value : table) + visit(value); + } + + template + void visit(OrderedHashTable const& table) + { + for (auto& value : table) + visit(value); + } + + template + void visit(HashMap const& map) + { + for (auto& it : map) { + if constexpr (requires { visit(it.key); }) + visit(it.key); + if constexpr (requires { visit(it.value); }) + visit(it.value); + } + } + + template + void visit(OrderedHashMap const& map) + { + for (auto& it : map) { + if constexpr (requires { visit(it.key); }) + visit(it.key); + if constexpr (requires { visit(it.value); }) + visit(it.value); + } + } + + void visit(NanBoxedValue const& value); + + // Allow explicitly ignoring a GC-allocated member in a visit_edges implementation instead + // of just not using it. + template + void ignore(T const&) + { + } + + virtual void visit_possible_values(ReadonlyBytes) = 0; + + protected: + virtual void visit_impl(CellImpl&) = 0; + virtual ~Visitor() = default; + }; + + virtual void visit_edges(Visitor&) { } + + // This will be called on unmarked objects by the garbage collector in a separate pass before destruction. + virtual void finalize() { } + + // This allows cells to survive GC by choice, even if nothing points to them. + // It's used to implement special rules in the web platform. + // NOTE: Cells must call set_overrides_must_survive_garbage_collection() for this to be honored. + virtual bool must_survive_garbage_collection() const { return false; } + + bool overrides_must_survive_garbage_collection(Badge) const { return m_overrides_must_survive_garbage_collection; } + + ALWAYS_INLINE Heap& heap() const { return HeapBlockBase::from_cell(this)->heap(); } + +protected: + CellImpl() = default; + + ALWAYS_INLINE void* private_data() const { return bit_cast(&heap())->private_data(); } + + void set_overrides_must_survive_garbage_collection(bool b) { m_overrides_must_survive_garbage_collection = b; } + +private: + bool m_mark : 1 { false }; + bool m_overrides_must_survive_garbage_collection : 1 { false }; + State m_state : 1 { State::Live }; +}; + +} + +template<> +struct AK::Formatter : AK::Formatter { + ErrorOr format(FormatBuilder& builder, JS::CellImpl const* cell) + { + if (!cell) + return builder.put_string("Cell{nullptr}"sv); + return Formatter::format(builder, "{}({})"sv, cell->class_name(), cell); + } +}; diff --git a/Libraries/LibJS/Heap/ConservativeVector.h b/Libraries/LibJS/Heap/ConservativeVector.h index cb23bd20930..066dcf37edd 100644 --- a/Libraries/LibJS/Heap/ConservativeVector.h +++ b/Libraries/LibJS/Heap/ConservativeVector.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include namespace JS { diff --git a/Libraries/LibJS/Heap/Handle.cpp b/Libraries/LibJS/Heap/Handle.cpp index 06c151639d8..e80b56bfb6b 100644 --- a/Libraries/LibJS/Heap/Handle.cpp +++ b/Libraries/LibJS/Heap/Handle.cpp @@ -4,13 +4,13 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include namespace JS { -HandleImpl::HandleImpl(Cell* cell, SourceLocation location) +HandleImpl::HandleImpl(CellImpl* cell, SourceLocation location) : m_cell(cell) , m_location(location) { diff --git a/Libraries/LibJS/Heap/Handle.h b/Libraries/LibJS/Heap/Handle.h index 2b95c3370a2..3dc99894e3a 100644 --- a/Libraries/LibJS/Heap/Handle.h +++ b/Libraries/LibJS/Heap/Handle.h @@ -24,8 +24,8 @@ class HandleImpl : public RefCounted { public: ~HandleImpl(); - Cell* cell() { return m_cell; } - Cell const* cell() const { return m_cell; } + CellImpl* cell() { return m_cell; } + CellImpl const* cell() const { return m_cell; } SourceLocation const& source_location() const { return m_location; } @@ -33,8 +33,8 @@ private: template friend class Handle; - explicit HandleImpl(Cell*, SourceLocation location); - GCPtr m_cell; + explicit HandleImpl(CellImpl*, SourceLocation location); + GCPtr m_cell; SourceLocation m_location; IntrusiveListNode m_list_node; diff --git a/Libraries/LibJS/Heap/Heap.cpp b/Libraries/LibJS/Heap/Heap.cpp index 47c92c425b7..e7d2698267e 100644 --- a/Libraries/LibJS/Heap/Heap.cpp +++ b/Libraries/LibJS/Heap/Heap.cpp @@ -28,8 +28,8 @@ namespace JS { -Heap::Heap(VM& vm, Function&)> gather_embedder_roots) - : HeapBase(vm) +Heap::Heap(void* private_data, Function&)> gather_embedder_roots) + : HeapBase(private_data) , m_gather_embedder_roots(move(gather_embedder_roots)) { static_assert(HeapBlock::min_possible_cell_size <= 32, "Heap Cell tracking uses too much data!"); @@ -100,7 +100,7 @@ static void for_each_cell_among_possible_pointers(HashTable const& a for (auto possible_pointer : possible_pointers.keys()) { if (!possible_pointer) continue; - auto* possible_heap_block = HeapBlock::from_cell(reinterpret_cast(possible_pointer)); + auto* possible_heap_block = HeapBlock::from_cell(reinterpret_cast(possible_pointer)); if (!all_live_heap_blocks.contains(possible_heap_block)) continue; if (auto* cell = possible_heap_block->cell_from_possible_pointer(possible_pointer)) { @@ -109,9 +109,9 @@ static void for_each_cell_among_possible_pointers(HashTable const& a } } -class GraphConstructorVisitor final : public Cell::Visitor { +class GraphConstructorVisitor final : public CellImpl::Visitor { public: - explicit GraphConstructorVisitor(Heap& heap, HashMap const& roots) + explicit GraphConstructorVisitor(Heap& heap, HashMap const& roots) : m_heap(heap) { m_heap.find_min_and_max_block_addresses(m_min_block_address, m_max_block_address); @@ -129,7 +129,7 @@ public: } } - virtual void visit_impl(Cell& cell) override + virtual void visit_impl(CellImpl& cell) override { if (m_node_being_visited) m_node_being_visited->edges.set(reinterpret_cast(&cell)); @@ -148,7 +148,7 @@ public: for (size_t i = 0; i < (bytes.size() / sizeof(FlatPtr)); ++i) add_possible_value(possible_pointers, raw_pointer_sized_values[i], HeapRoot { .type = HeapRoot::Type::HeapFunctionCapturedPointer }, m_min_block_address, m_max_block_address); - for_each_cell_among_possible_pointers(m_all_live_heap_blocks, possible_pointers, [&](Cell* cell, FlatPtr) { + for_each_cell_among_possible_pointers(m_all_live_heap_blocks, possible_pointers, [&](CellImpl* cell, FlatPtr) { if (m_node_being_visited) m_node_being_visited->edges.set(reinterpret_cast(cell)); @@ -218,7 +218,7 @@ private: }; GraphNode* m_node_being_visited { nullptr }; - Vector> m_work_queue; + Vector> m_work_queue; HashMap m_graph; Heap& m_heap; @@ -229,7 +229,7 @@ private: AK::JsonObject Heap::dump_graph() { - HashMap roots; + HashMap roots; gather_roots(roots); GraphConstructorVisitor visitor(*this, roots); visitor.visit_all_cells(); @@ -250,7 +250,7 @@ void Heap::collect_garbage(CollectionType collection_type, bool print_report) m_should_gc_when_deferral_ends = true; return; } - HashMap roots; + HashMap roots; gather_roots(roots); mark_live_cells(roots); } @@ -258,7 +258,7 @@ void Heap::collect_garbage(CollectionType collection_type, bool print_report) sweep_dead_cells(print_report, collection_measurement_timer); } -void Heap::gather_roots(HashMap& roots) +void Heap::gather_roots(HashMap& roots) { m_gather_embedder_roots(roots); gather_conservative_roots(roots); @@ -298,7 +298,7 @@ void Heap::gather_asan_fake_stack_roots(HashMap&, FlatPtr, Fl } #endif -NO_SANITIZE_ADDRESS void Heap::gather_conservative_roots(HashMap& roots) +NO_SANITIZE_ADDRESS void Heap::gather_conservative_roots(HashMap& roots) { FlatPtr dummy; @@ -337,8 +337,8 @@ NO_SANITIZE_ADDRESS void Heap::gather_conservative_roots(HashMapstate() == Cell::State::Live) { + for_each_cell_among_possible_pointers(all_live_heap_blocks, possible_pointers, [&](CellImpl* cell, FlatPtr possible_pointer) { + if (cell->state() == CellImpl::State::Live) { dbgln_if(HEAP_DEBUG, " ?-> {}", (void const*)cell); roots.set(cell, *possible_pointers.get(possible_pointer)); } else { @@ -347,9 +347,9 @@ NO_SANITIZE_ADDRESS void Heap::gather_conservative_roots(HashMap const& roots) + explicit MarkingVisitor(Heap& heap, HashMap const& roots) : m_heap(heap) { m_heap.find_min_and_max_block_addresses(m_min_block_address, m_max_block_address); @@ -363,7 +363,7 @@ public: } } - virtual void visit_impl(Cell& cell) override + virtual void visit_impl(CellImpl& cell) override { if (cell.is_marked()) return; @@ -381,10 +381,10 @@ public: for (size_t i = 0; i < (bytes.size() / sizeof(FlatPtr)); ++i) add_possible_value(possible_pointers, raw_pointer_sized_values[i], HeapRoot { .type = HeapRoot::Type::HeapFunctionCapturedPointer }, m_min_block_address, m_max_block_address); - for_each_cell_among_possible_pointers(m_all_live_heap_blocks, possible_pointers, [&](Cell* cell, FlatPtr) { + for_each_cell_among_possible_pointers(m_all_live_heap_blocks, possible_pointers, [&](CellImpl* cell, FlatPtr) { if (cell->is_marked()) return; - if (cell->state() != Cell::State::Live) + if (cell->state() != CellImpl::State::Live) return; cell->set_marked(true); m_work_queue.append(*cell); @@ -400,13 +400,13 @@ public: private: Heap& m_heap; - Vector> m_work_queue; + Vector> m_work_queue; HashTable m_all_live_heap_blocks; FlatPtr m_min_block_address; FlatPtr m_max_block_address; }; -void Heap::mark_live_cells(HashMap const& roots) +void Heap::mark_live_cells(HashMap const& roots) { dbgln_if(HEAP_DEBUG, "mark_live_cells:"); @@ -420,7 +420,7 @@ void Heap::mark_live_cells(HashMap const& roots) m_uprooted_cells.clear(); } -bool Heap::cell_must_survive_garbage_collection(Cell const& cell) +bool Heap::cell_must_survive_garbage_collection(CellImpl const& cell) { if (!cell.overrides_must_survive_garbage_collection({})) return false; @@ -430,7 +430,7 @@ bool Heap::cell_must_survive_garbage_collection(Cell const& cell) void Heap::finalize_unmarked_cells() { for_each_block([&](auto& block) { - block.template for_each_cell_in_state([](Cell* cell) { + block.template for_each_cell_in_state([](CellImpl* cell) { if (!cell->is_marked() && !cell_must_survive_garbage_collection(*cell)) cell->finalize(); }); @@ -452,7 +452,7 @@ void Heap::sweep_dead_cells(bool print_report, Core::ElapsedTimer const& measure for_each_block([&](auto& block) { bool block_has_live_cells = false; bool block_was_full = block.is_full(); - block.template for_each_cell_in_state([&](Cell* cell) { + block.template for_each_cell_in_state([&](CellImpl* cell) { if (!cell->is_marked() && !cell_must_survive_garbage_collection(*cell)) { dbgln_if(HEAP_DEBUG, " ~ {}", cell); block.deallocate(cell); @@ -530,7 +530,7 @@ void Heap::undefer_gc() } } -void Heap::uproot_cell(Cell* cell) +void Heap::uproot_cell(CellImpl* cell) { m_uprooted_cells.append(cell); } diff --git a/Libraries/LibJS/Heap/Heap.h b/Libraries/LibJS/Heap/Heap.h index 694a70d81a5..79851307c45 100644 --- a/Libraries/LibJS/Heap/Heap.h +++ b/Libraries/LibJS/Heap/Heap.h @@ -17,8 +17,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -33,7 +33,7 @@ class Heap : public HeapBase { AK_MAKE_NONMOVABLE(Heap); public: - explicit Heap(VM&, Function&)> gather_embedder_roots); + explicit Heap(void* private_data, Function&)> gather_embedder_roots); ~Heap(); template @@ -71,7 +71,7 @@ public: void register_cell_allocator(Badge, CellAllocator&); - void uproot_cell(Cell* cell); + void uproot_cell(CellImpl* cell); private: friend class MarkingVisitor; @@ -81,10 +81,10 @@ private: void defer_gc(); void undefer_gc(); - static bool cell_must_survive_garbage_collection(Cell const&); + static bool cell_must_survive_garbage_collection(CellImpl const&); template - Cell* allocate_cell() + CellImpl* allocate_cell() { will_allocate(sizeof(T)); if constexpr (requires { T::cell_allocator.allocator.get().allocate_cell(*this); }) { @@ -98,10 +98,10 @@ private: void will_allocate(size_t); void find_min_and_max_block_addresses(FlatPtr& min_address, FlatPtr& max_address); - void gather_roots(HashMap&); - void gather_conservative_roots(HashMap&); + void gather_roots(HashMap&); + void gather_conservative_roots(HashMap&); void gather_asan_fake_stack_roots(HashMap&, FlatPtr, FlatPtr min_block_address, FlatPtr max_block_address); - void mark_live_cells(HashMap const& live_cells); + void mark_live_cells(HashMap const& live_cells); void finalize_unmarked_cells(); void sweep_dead_cells(bool print_report, Core::ElapsedTimer const&); @@ -139,14 +139,14 @@ private: ConservativeVectorBase::List m_conservative_vectors; WeakContainer::List m_weak_containers; - Vector> m_uprooted_cells; + Vector> m_uprooted_cells; size_t m_gc_deferrals { 0 }; bool m_should_gc_when_deferral_ends { false }; bool m_collecting_garbage { false }; StackInfo m_stack_info; - Function&)> m_gather_embedder_roots; + Function&)> m_gather_embedder_roots; }; inline void Heap::did_create_handle(Badge, HandleImpl& impl) diff --git a/Libraries/LibJS/Heap/HeapBlock.cpp b/Libraries/LibJS/Heap/HeapBlock.cpp index ccbe0bbbdae..f7587cc04ea 100644 --- a/Libraries/LibJS/Heap/HeapBlock.cpp +++ b/Libraries/LibJS/Heap/HeapBlock.cpp @@ -37,16 +37,16 @@ HeapBlock::HeapBlock(Heap& heap, CellAllocator& cell_allocator, size_t cell_size ASAN_POISON_MEMORY_REGION(m_storage, block_size - sizeof(HeapBlock)); } -void HeapBlock::deallocate(Cell* cell) +void HeapBlock::deallocate(CellImpl* cell) { VERIFY(is_valid_cell_pointer(cell)); VERIFY(!m_freelist || is_valid_cell_pointer(m_freelist)); - VERIFY(cell->state() == Cell::State::Live); + VERIFY(cell->state() == CellImpl::State::Live); VERIFY(!cell->is_marked()); - cell->~Cell(); + cell->~CellImpl(); auto* freelist_entry = new (cell) FreelistEntry(); - freelist_entry->set_state(Cell::State::Dead); + freelist_entry->set_state(CellImpl::State::Dead); freelist_entry->next = m_freelist; m_freelist = freelist_entry; diff --git a/Libraries/LibJS/Heap/HeapBlock.h b/Libraries/LibJS/Heap/HeapBlock.h index 51ce3e87417..44d1c89e682 100644 --- a/Libraries/LibJS/Heap/HeapBlock.h +++ b/Libraries/LibJS/Heap/HeapBlock.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #ifdef HAS_ADDRESS_SANITIZER @@ -32,9 +32,9 @@ public: size_t cell_count() const { return (block_size - sizeof(HeapBlock)) / m_cell_size; } bool is_full() const { return !has_lazy_freelist() && !m_freelist; } - ALWAYS_INLINE Cell* allocate() + ALWAYS_INLINE CellImpl* allocate() { - Cell* allocated_cell = nullptr; + CellImpl* allocated_cell = nullptr; if (m_freelist) { VERIFY(is_valid_cell_pointer(m_freelist)); allocated_cell = exchange(m_freelist, m_freelist->next); @@ -48,7 +48,7 @@ public: return allocated_cell; } - void deallocate(Cell*); + void deallocate(CellImpl*); template void for_each_cell(Callback callback) @@ -58,7 +58,7 @@ public: callback(cell(i)); } - template + template void for_each_cell_in_state(Callback callback) { for_each_cell([&](auto* cell) { @@ -67,12 +67,12 @@ public: }); } - static HeapBlock* from_cell(Cell const* cell) + static HeapBlock* from_cell(CellImpl const* cell) { return static_cast(HeapBlockBase::from_cell(cell)); } - Cell* cell_from_possible_pointer(FlatPtr pointer) + CellImpl* cell_from_possible_pointer(FlatPtr pointer) { if (pointer < reinterpret_cast(m_storage)) return nullptr; @@ -83,7 +83,7 @@ public: return cell(cell_index); } - bool is_valid_cell_pointer(Cell const* cell) + bool is_valid_cell_pointer(CellImpl const* cell) { return cell_from_possible_pointer((FlatPtr)cell); } @@ -97,15 +97,15 @@ private: bool has_lazy_freelist() const { return m_next_lazy_freelist_index < cell_count(); } - struct FreelistEntry final : public Cell { - JS_CELL(FreelistEntry, Cell); + struct FreelistEntry final : public CellImpl { + JS_CELL(FreelistEntry, CellImpl); RawGCPtr next; }; - Cell* cell(size_t index) + CellImpl* cell(size_t index) { - return reinterpret_cast(&m_storage[index * cell_size()]); + return reinterpret_cast(&m_storage[index * cell_size()]); } CellAllocator& m_cell_allocator; diff --git a/Libraries/LibJS/Heap/HeapFunction.h b/Libraries/LibJS/Heap/HeapFunction.h index d541026ea25..e4909f7ee7b 100644 --- a/Libraries/LibJS/Heap/HeapFunction.h +++ b/Libraries/LibJS/Heap/HeapFunction.h @@ -7,14 +7,14 @@ #pragma once #include -#include +#include #include namespace JS { template -class HeapFunction final : public Cell { - JS_CELL(HeapFunction, Cell); +class HeapFunction final : public CellImpl { + JS_CELL(HeapFunction, CellImpl); public: static NonnullGCPtr create(Heap& heap, Function function) diff --git a/Libraries/LibJS/Heap/Internals.h b/Libraries/LibJS/Heap/Internals.h index 2bb809bb908..f3ec8a8ee55 100644 --- a/Libraries/LibJS/Heap/Internals.h +++ b/Libraries/LibJS/Heap/Internals.h @@ -17,15 +17,15 @@ class HeapBase { AK_MAKE_NONMOVABLE(HeapBase); public: - VM& vm() { return m_vm; } + void* private_data() { return m_private_data; } protected: - HeapBase(VM& vm) - : m_vm(vm) + explicit HeapBase(void* private_data) + : m_private_data(private_data) { } - VM& m_vm; + void* m_private_data; }; class HeapBlockBase { @@ -34,7 +34,7 @@ class HeapBlockBase { public: static size_t block_size; - static HeapBlockBase* from_cell(Cell const* cell) + static HeapBlockBase* from_cell(CellImpl const* cell) { return reinterpret_cast(bit_cast(cell) & ~(HeapBlockBase::block_size - 1)); } diff --git a/Libraries/LibJS/Heap/MarkedVector.h b/Libraries/LibJS/Heap/MarkedVector.h index e4d32ee0dba..4be1bdeafe3 100644 --- a/Libraries/LibJS/Heap/MarkedVector.h +++ b/Libraries/LibJS/Heap/MarkedVector.h @@ -11,14 +11,14 @@ #include #include #include -#include +#include #include namespace JS { class MarkedVectorBase { public: - virtual void gather_roots(HashMap&) const = 0; + virtual void gather_roots(HashMap&) const = 0; protected: explicit MarkedVectorBase(Heap&); @@ -65,7 +65,7 @@ public: return *this; } - virtual void gather_roots(HashMap& roots) const override + virtual void gather_roots(HashMap& roots) const override { for (auto& value : *this) { if constexpr (IsSame) { diff --git a/Libraries/LibJS/Heap/NanBoxedValue.h b/Libraries/LibJS/Heap/NanBoxedValue.h index 6c3a32794ff..3bf95351158 100644 --- a/Libraries/LibJS/Heap/NanBoxedValue.h +++ b/Libraries/LibJS/Heap/NanBoxedValue.h @@ -86,16 +86,16 @@ public: return reinterpret_cast(extract_pointer_bits(m_value.encoded)); } - Cell& as_cell() + CellImpl& as_cell() { VERIFY(is_cell()); - return *extract_pointer(); + return *extract_pointer(); } - Cell& as_cell() const + CellImpl& as_cell() const { VERIFY(is_cell()); - return *extract_pointer(); + return *extract_pointer(); } bool is_nan() const diff --git a/Libraries/LibJS/Runtime/VM.cpp b/Libraries/LibJS/Runtime/VM.cpp index afc5538bc49..ff432517807 100644 --- a/Libraries/LibJS/Runtime/VM.cpp +++ b/Libraries/LibJS/Runtime/VM.cpp @@ -62,7 +62,7 @@ static constexpr auto make_single_ascii_character_strings(IndexSequence()); VM::VM(OwnPtr custom_data, ErrorMessages error_messages) - : m_heap(*this, [this](HashMap& roots) { + : m_heap(this, [this](HashMap& roots) { gather_roots(roots); }) , m_error_messages(move(error_messages)) @@ -204,7 +204,7 @@ Bytecode::Interpreter& VM::bytecode_interpreter() } struct ExecutionContextRootsCollector : public Cell::Visitor { - virtual void visit_impl(Cell& cell) override + virtual void visit_impl(CellImpl& cell) override { roots.set(&cell); } @@ -214,10 +214,10 @@ struct ExecutionContextRootsCollector : public Cell::Visitor { VERIFY_NOT_REACHED(); } - HashTable> roots; + HashTable> roots; }; -void VM::gather_roots(HashMap& roots) +void VM::gather_roots(HashMap& roots) { roots.set(m_empty_string, HeapRoot { .type = HeapRoot::Type::VM }); for (auto string : m_single_ascii_character_strings) diff --git a/Libraries/LibJS/Runtime/VM.h b/Libraries/LibJS/Runtime/VM.h index dbc14701879..d1941f667e1 100644 --- a/Libraries/LibJS/Runtime/VM.h +++ b/Libraries/LibJS/Runtime/VM.h @@ -60,7 +60,7 @@ public: void dump_backtrace() const; - void gather_roots(HashMap&); + void gather_roots(HashMap&); #define __JS_ENUMERATE(SymbolName, snake_name) \ NonnullGCPtr well_known_symbol_##snake_name() const \ diff --git a/Libraries/LibJS/Runtime/Value.h b/Libraries/LibJS/Runtime/Value.h index 562c982f4df..9a37dc3d69b 100644 --- a/Libraries/LibJS/Runtime/Value.h +++ b/Libraries/LibJS/Runtime/Value.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -256,6 +257,18 @@ public: { } + Cell& as_cell() + { + VERIFY(is_cell()); + return *extract_pointer(); + } + + Cell& as_cell() const + { + VERIFY(is_cell()); + return *extract_pointer(); + } + double as_double() const { VERIFY(is_number()); @@ -661,14 +674,14 @@ private: { } - explicit Handle(Value value, Cell* cell, SourceLocation location) + explicit Handle(Value value, CellImpl* cell, SourceLocation location) : m_value(value) - , m_handle(Handle::create(cell, location)) + , m_handle(Handle::create(cell, location)) { } Optional m_value; - Handle m_handle; + Handle m_handle; }; inline Handle make_handle(Value value, SourceLocation location = SourceLocation::current()) diff --git a/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h b/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h index a16293df48c..04634e3894f 100644 --- a/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h +++ b/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Headers.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/Libraries/LibWeb/HTML/AnimationFrameCallbackDriver.h b/Libraries/LibWeb/HTML/AnimationFrameCallbackDriver.h index 85f2e4e144e..dfdb6a00f7b 100644 --- a/Libraries/LibWeb/HTML/AnimationFrameCallbackDriver.h +++ b/Libraries/LibWeb/HTML/AnimationFrameCallbackDriver.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include diff --git a/Libraries/LibWeb/WebDriver/HeapTimer.h b/Libraries/LibWeb/WebDriver/HeapTimer.h index 3a5800cf20c..a7ca3e6c78f 100644 --- a/Libraries/LibWeb/WebDriver/HeapTimer.h +++ b/Libraries/LibWeb/WebDriver/HeapTimer.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include diff --git a/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.cpp b/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.cpp index d3db0519e02..1d6d3602213 100644 --- a/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.cpp +++ b/Meta/Lagom/ClangPlugins/LibJSGCPluginAction.cpp @@ -39,9 +39,9 @@ static bool record_inherits_from_cell(clang::CXXRecordDecl const& record) if (!record.isCompleteDefinition()) return false; - bool inherits_from_cell = record.getQualifiedNameAsString() == "JS::Cell"; + bool inherits_from_cell = record.getQualifiedNameAsString() == "JS::CellImpl"; record.forallBases([&](clang::CXXRecordDecl const* base) -> bool { - if (base->getQualifiedNameAsString() == "JS::Cell") { + if (base->getQualifiedNameAsString() == "JS::CellImpl") { inherits_from_cell = true; return false; } @@ -173,7 +173,7 @@ bool LibJSGCVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* record) // Cell triggers a bunch of warnings for its empty visit_edges implementation, but // it doesn't have any members anyways so it's fine to just ignore. auto qualified_name = record->getQualifiedNameAsString(); - if (qualified_name == "JS::Cell") + if (qualified_name == "JS::CellImpl") return true; auto& diag_engine = m_context.getDiagnostics(); @@ -192,7 +192,7 @@ bool LibJSGCVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* record) if (outer_type == OuterType::Ptr || outer_type == OuterType::Ref) { if (base_type_inherits_from_cell) { - auto diag_id = diag_engine.getCustomDiagID(clang::DiagnosticsEngine::Error, "%0 to JS::Cell type should be wrapped in %1"); + auto diag_id = diag_engine.getCustomDiagID(clang::DiagnosticsEngine::Error, "%0 to JS::CellImpl type should be wrapped in %1"); auto builder = diag_engine.Report(field->getLocation(), diag_id); if (outer_type == OuterType::Ref) { builder << "reference" @@ -204,7 +204,7 @@ bool LibJSGCVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* record) } } else if (outer_type == OuterType::GCPtr || outer_type == OuterType::RawGCPtr) { if (!base_type_inherits_from_cell) { - auto diag_id = diag_engine.getCustomDiagID(clang::DiagnosticsEngine::Error, "Specialization type must inherit from JS::Cell"); + auto diag_id = diag_engine.getCustomDiagID(clang::DiagnosticsEngine::Error, "Specialization type must inherit from JS::CellImpl"); diag_engine.Report(field->getLocation(), diag_id); } else if (outer_type == OuterType::GCPtr) { fields_that_need_visiting.push_back(field); @@ -212,7 +212,7 @@ bool LibJSGCVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* record) } else if (outer_type == OuterType::Handle) { if (record_is_cell && m_detect_invalid_function_members) { // FIXME: Change this to an Error when all of the use cases get addressed and remove the plugin argument - auto diag_id = diag_engine.getCustomDiagID(clang::DiagnosticsEngine::Warning, "Types inheriting from JS::Cell should not have %0 fields"); + auto diag_id = diag_engine.getCustomDiagID(clang::DiagnosticsEngine::Warning, "Types inheriting from JS::CellImpl should not have %0 fields"); auto builder = diag_engine.Report(field->getLocation(), diag_id); builder << "JS::Handle"; } @@ -311,7 +311,7 @@ static std::optional find_cell_type_with_origin(clang::CXXRe if (auto const* base_record = base.getType()->getAsCXXRecordDecl()) { auto base_name = base_record->getQualifiedNameAsString(); - if (base_name == "JS::Cell") + if (base_name == "JS::CellImpl") return CellTypeWithOrigin { *base_record, LibJSCellMacro::Type::JSCell }; if (base_name == "JS::Object") diff --git a/Tests/ClangPlugins/LibJSGCTests/cell_member_not_wrapped.cpp b/Tests/ClangPlugins/LibJSGCTests/cell_member_not_wrapped.cpp index bd66f08964d..1c01200d016 100644 --- a/Tests/ClangPlugins/LibJSGCTests/cell_member_not_wrapped.cpp +++ b/Tests/ClangPlugins/LibJSGCTests/cell_member_not_wrapped.cpp @@ -30,15 +30,15 @@ private: visitor.visit(m_object_ptr); } - // expected-error@+1 {{reference to JS::Cell type should be wrapped in JS::NonnullGCPtr}} + // expected-error@+1 {{reference to JS::CellImpl type should be wrapped in JS::NonnullGCPtr}} JS::Object& m_object_ref; - // expected-error@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}} + // expected-error@+1 {{pointer to JS::CellImpl type should be wrapped in JS::GCPtr}} JS::Object* m_object_ptr; - // expected-error@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}} + // expected-error@+1 {{pointer to JS::CellImpl type should be wrapped in JS::GCPtr}} Vector m_objects; - // expected-error@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}} + // expected-error@+1 {{pointer to JS::CellImpl type should be wrapped in JS::GCPtr}} NewType1* m_newtype_1; - // expected-error@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}} + // expected-error@+1 {{pointer to JS::CellImpl type should be wrapped in JS::GCPtr}} NewType2* m_newtype_2; }; @@ -50,14 +50,14 @@ public: } private: - // expected-error@+1 {{reference to JS::Cell type should be wrapped in JS::NonnullGCPtr}} + // expected-error@+1 {{reference to JS::CellImpl type should be wrapped in JS::NonnullGCPtr}} JS::Object& m_object_ref; - // expected-error@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}} + // expected-error@+1 {{pointer to JS::CellImpl type should be wrapped in JS::GCPtr}} JS::Object* m_object_ptr; - // expected-error@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}} + // expected-error@+1 {{pointer to JS::CellImpl type should be wrapped in JS::GCPtr}} Vector m_objects; - // expected-error@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}} + // expected-error@+1 {{pointer to JS::CellImpl type should be wrapped in JS::GCPtr}} NewType1* m_newtype_1; - // expected-error@+1 {{pointer to JS::Cell type should be wrapped in JS::GCPtr}} + // expected-error@+1 {{pointer to JS::CellImpl type should be wrapped in JS::GCPtr}} NewType2* m_newtype_2; };