mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
LibJS: Don't directly teach the heap about the javascript VM or Realm
Instead, smuggle it in as a `void*` private data and let Javascript aware code cast out that pointer to a VM&. In order to make this split, rename JS::Cell to JS::CellImpl. Once we have a LibGC, this will become GC::Cell. CellImpl then has no specific knowledge of the VM& and Realm&. That knowledge is instead put into JS::Cell, which inherits from CellImpl. JS::Cell is responsible for JavaScript's realm initialization, as well as converting of the void* private data to what it knows should be the VM&.
This commit is contained in:
parent
ae6d105f41
commit
c2988a7dd5
Notes:
github-actions[bot]
2024-11-14 14:39:37 +00:00
Author: https://github.com/shannonbooth Commit: https://github.com/LadybirdBrowser/ladybird/commit/c2988a7dd51 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2334
27 changed files with 346 additions and 296 deletions
|
@ -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
|
||||
|
|
|
@ -159,6 +159,7 @@ class BigInt;
|
|||
class BoundFunction;
|
||||
struct CachedSourceRange;
|
||||
class Cell;
|
||||
class CellImpl;
|
||||
class CellAllocator;
|
||||
class ClassExpression;
|
||||
struct ClassFieldDefinition;
|
||||
|
|
|
@ -5,19 +5,11 @@
|
|||
*/
|
||||
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Heap/Heap.h>
|
||||
#include <LibJS/Heap/NanBoxedValue.h>
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,200 +6,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Badge.h>
|
||||
#include <AK/Format.h>
|
||||
#include <AK/Forward.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/Noncopyable.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Weakable.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/GCPtr.h>
|
||||
#include <LibJS/Heap/Internals.h>
|
||||
#include <LibJS/Heap/CellImpl.h>
|
||||
|
||||
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<Cell> {
|
||||
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*>(cell));
|
||||
}
|
||||
|
||||
void visit(Cell const& cell)
|
||||
{
|
||||
visit(const_cast<Cell&>(cell));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(GCPtr<T> cell)
|
||||
{
|
||||
if (cell)
|
||||
visit_impl(const_cast<RemoveConst<T>&>(*cell.ptr()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(NonnullGCPtr<T> cell)
|
||||
{
|
||||
visit_impl(const_cast<RemoveConst<T>&>(*cell.ptr()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(ReadonlySpan<T> span)
|
||||
{
|
||||
for (auto& value : span)
|
||||
visit(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(Span<T> span)
|
||||
{
|
||||
for (auto& value : span)
|
||||
visit(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(Vector<T> const& vector)
|
||||
{
|
||||
for (auto& value : vector)
|
||||
visit(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(HashTable<T> const& table)
|
||||
{
|
||||
for (auto& value : table)
|
||||
visit(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(OrderedHashTable<T> const& table)
|
||||
{
|
||||
for (auto& value : table)
|
||||
visit(value);
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename T>
|
||||
void visit(HashMap<K, V, T> 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<typename K, typename V, typename T>
|
||||
void visit(OrderedHashMap<K, V, T> 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<typename T>
|
||||
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<Heap>) 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<HeapBase*>(&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<VM*>(private_data()); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct AK::Formatter<JS::Cell> : AK::Formatter<FormatString> {
|
||||
ErrorOr<void> format(FormatBuilder& builder, JS::Cell const* cell)
|
||||
{
|
||||
if (!cell)
|
||||
return builder.put_string("Cell{nullptr}"sv);
|
||||
return Formatter<FormatString>::format(builder, "{}({})"sv, cell->class_name(), cell);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
|
||||
size_t cell_size() const { return m_cell_size; }
|
||||
|
||||
Cell* allocate_cell(Heap&);
|
||||
CellImpl* allocate_cell(Heap&);
|
||||
|
||||
template<typename Callback>
|
||||
IterationDecision for_each_block(Callback callback)
|
||||
|
|
18
Libraries/LibJS/Heap/CellImpl.cpp
Normal file
18
Libraries/LibJS/Heap/CellImpl.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, Andreas Kling <andreas@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Heap/CellImpl.h>
|
||||
#include <LibJS/Heap/NanBoxedValue.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
void JS::CellImpl::Visitor::visit(NanBoxedValue const& value)
|
||||
{
|
||||
if (value.is_cell())
|
||||
visit_impl(value.as_cell());
|
||||
}
|
||||
|
||||
}
|
205
Libraries/LibJS/Heap/CellImpl.h
Normal file
205
Libraries/LibJS/Heap/CellImpl.h
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2024, Andreas Kling <andreas@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Badge.h>
|
||||
#include <AK/Format.h>
|
||||
#include <AK/Forward.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/Noncopyable.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Weakable.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/GCPtr.h>
|
||||
#include <LibJS/Heap/Internals.h>
|
||||
|
||||
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<CellImpl> {
|
||||
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<CellImpl*>(cell));
|
||||
}
|
||||
|
||||
void visit(CellImpl const& cell)
|
||||
{
|
||||
visit(const_cast<CellImpl&>(cell));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(GCPtr<T> cell)
|
||||
{
|
||||
if (cell)
|
||||
visit_impl(const_cast<RemoveConst<T>&>(*cell.ptr()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(NonnullGCPtr<T> cell)
|
||||
{
|
||||
visit_impl(const_cast<RemoveConst<T>&>(*cell.ptr()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(ReadonlySpan<T> span)
|
||||
{
|
||||
for (auto& value : span)
|
||||
visit(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(Span<T> span)
|
||||
{
|
||||
for (auto& value : span)
|
||||
visit(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(Vector<T> const& vector)
|
||||
{
|
||||
for (auto& value : vector)
|
||||
visit(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(HashTable<T> const& table)
|
||||
{
|
||||
for (auto& value : table)
|
||||
visit(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void visit(OrderedHashTable<T> const& table)
|
||||
{
|
||||
for (auto& value : table)
|
||||
visit(value);
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename T>
|
||||
void visit(HashMap<K, V, T> 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<typename K, typename V, typename T>
|
||||
void visit(OrderedHashMap<K, V, T> 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<typename T>
|
||||
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<Heap>) 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<HeapBase*>(&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<JS::CellImpl> : AK::Formatter<FormatString> {
|
||||
ErrorOr<void> format(FormatBuilder& builder, JS::CellImpl const* cell)
|
||||
{
|
||||
if (!cell)
|
||||
return builder.put_string("Cell{nullptr}"sv);
|
||||
return Formatter<FormatString>::format(builder, "{}({})"sv, cell->class_name(), cell);
|
||||
}
|
||||
};
|
|
@ -10,7 +10,7 @@
|
|||
#include <AK/IntrusiveList.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Heap/CellImpl.h>
|
||||
#include <LibJS/Heap/HeapRoot.h>
|
||||
|
||||
namespace JS {
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Heap/CellImpl.h>
|
||||
#include <LibJS/Heap/Handle.h>
|
||||
#include <LibJS/Heap/Heap.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
HandleImpl::HandleImpl(Cell* cell, SourceLocation location)
|
||||
HandleImpl::HandleImpl(CellImpl* cell, SourceLocation location)
|
||||
: m_cell(cell)
|
||||
, m_location(location)
|
||||
{
|
||||
|
|
|
@ -24,8 +24,8 @@ class HandleImpl : public RefCounted<HandleImpl> {
|
|||
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<class T>
|
||||
friend class Handle;
|
||||
|
||||
explicit HandleImpl(Cell*, SourceLocation location);
|
||||
GCPtr<Cell> m_cell;
|
||||
explicit HandleImpl(CellImpl*, SourceLocation location);
|
||||
GCPtr<CellImpl> m_cell;
|
||||
SourceLocation m_location;
|
||||
|
||||
IntrusiveListNode<HandleImpl> m_list_node;
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
|
||||
namespace JS {
|
||||
|
||||
Heap::Heap(VM& vm, Function<void(HashMap<Cell*, JS::HeapRoot>&)> gather_embedder_roots)
|
||||
: HeapBase(vm)
|
||||
Heap::Heap(void* private_data, Function<void(HashMap<CellImpl*, JS::HeapRoot>&)> 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<HeapBlock*> const& a
|
|||
for (auto possible_pointer : possible_pointers.keys()) {
|
||||
if (!possible_pointer)
|
||||
continue;
|
||||
auto* possible_heap_block = HeapBlock::from_cell(reinterpret_cast<Cell const*>(possible_pointer));
|
||||
auto* possible_heap_block = HeapBlock::from_cell(reinterpret_cast<CellImpl const*>(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<HeapBlock*> const& a
|
|||
}
|
||||
}
|
||||
|
||||
class GraphConstructorVisitor final : public Cell::Visitor {
|
||||
class GraphConstructorVisitor final : public CellImpl::Visitor {
|
||||
public:
|
||||
explicit GraphConstructorVisitor(Heap& heap, HashMap<Cell*, HeapRoot> const& roots)
|
||||
explicit GraphConstructorVisitor(Heap& heap, HashMap<CellImpl*, HeapRoot> 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<FlatPtr>(&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<FlatPtr>(cell));
|
||||
|
||||
|
@ -218,7 +218,7 @@ private:
|
|||
};
|
||||
|
||||
GraphNode* m_node_being_visited { nullptr };
|
||||
Vector<NonnullGCPtr<Cell>> m_work_queue;
|
||||
Vector<NonnullGCPtr<CellImpl>> m_work_queue;
|
||||
HashMap<FlatPtr, GraphNode> m_graph;
|
||||
|
||||
Heap& m_heap;
|
||||
|
@ -229,7 +229,7 @@ private:
|
|||
|
||||
AK::JsonObject Heap::dump_graph()
|
||||
{
|
||||
HashMap<Cell*, HeapRoot> roots;
|
||||
HashMap<CellImpl*, HeapRoot> 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<Cell*, HeapRoot> roots;
|
||||
HashMap<CellImpl*, HeapRoot> 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<Cell*, HeapRoot>& roots)
|
||||
void Heap::gather_roots(HashMap<CellImpl*, HeapRoot>& roots)
|
||||
{
|
||||
m_gather_embedder_roots(roots);
|
||||
gather_conservative_roots(roots);
|
||||
|
@ -298,7 +298,7 @@ void Heap::gather_asan_fake_stack_roots(HashMap<FlatPtr, HeapRoot>&, FlatPtr, Fl
|
|||
}
|
||||
#endif
|
||||
|
||||
NO_SANITIZE_ADDRESS void Heap::gather_conservative_roots(HashMap<Cell*, HeapRoot>& roots)
|
||||
NO_SANITIZE_ADDRESS void Heap::gather_conservative_roots(HashMap<CellImpl*, HeapRoot>& roots)
|
||||
{
|
||||
FlatPtr dummy;
|
||||
|
||||
|
@ -337,8 +337,8 @@ NO_SANITIZE_ADDRESS void Heap::gather_conservative_roots(HashMap<Cell*, HeapRoot
|
|||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
for_each_cell_among_possible_pointers(all_live_heap_blocks, possible_pointers, [&](Cell* cell, FlatPtr possible_pointer) {
|
||||
if (cell->state() == 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<Cell*, HeapRoot
|
|||
});
|
||||
}
|
||||
|
||||
class MarkingVisitor final : public Cell::Visitor {
|
||||
class MarkingVisitor final : public CellImpl::Visitor {
|
||||
public:
|
||||
explicit MarkingVisitor(Heap& heap, HashMap<Cell*, HeapRoot> const& roots)
|
||||
explicit MarkingVisitor(Heap& heap, HashMap<CellImpl*, HeapRoot> 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<NonnullGCPtr<Cell>> m_work_queue;
|
||||
Vector<NonnullGCPtr<CellImpl>> m_work_queue;
|
||||
HashTable<HeapBlock*> m_all_live_heap_blocks;
|
||||
FlatPtr m_min_block_address;
|
||||
FlatPtr m_max_block_address;
|
||||
};
|
||||
|
||||
void Heap::mark_live_cells(HashMap<Cell*, HeapRoot> const& roots)
|
||||
void Heap::mark_live_cells(HashMap<CellImpl*, HeapRoot> const& roots)
|
||||
{
|
||||
dbgln_if(HEAP_DEBUG, "mark_live_cells:");
|
||||
|
||||
|
@ -420,7 +420,7 @@ void Heap::mark_live_cells(HashMap<Cell*, HeapRoot> 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::State::Live>([](Cell* cell) {
|
||||
block.template for_each_cell_in_state<CellImpl::State::Live>([](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::State::Live>([&](Cell* cell) {
|
||||
block.template for_each_cell_in_state<CellImpl::State::Live>([&](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);
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
#include <AK/Vector.h>
|
||||
#include <LibCore/Forward.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Heap/CellAllocator.h>
|
||||
#include <LibJS/Heap/CellImpl.h>
|
||||
#include <LibJS/Heap/ConservativeVector.h>
|
||||
#include <LibJS/Heap/Handle.h>
|
||||
#include <LibJS/Heap/HeapRoot.h>
|
||||
|
@ -33,7 +33,7 @@ class Heap : public HeapBase {
|
|||
AK_MAKE_NONMOVABLE(Heap);
|
||||
|
||||
public:
|
||||
explicit Heap(VM&, Function<void(HashMap<Cell*, JS::HeapRoot>&)> gather_embedder_roots);
|
||||
explicit Heap(void* private_data, Function<void(HashMap<CellImpl*, JS::HeapRoot>&)> gather_embedder_roots);
|
||||
~Heap();
|
||||
|
||||
template<typename T, typename... Args>
|
||||
|
@ -71,7 +71,7 @@ public:
|
|||
|
||||
void register_cell_allocator(Badge<CellAllocator>, 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<typename T>
|
||||
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<Cell*, HeapRoot>&);
|
||||
void gather_conservative_roots(HashMap<Cell*, HeapRoot>&);
|
||||
void gather_roots(HashMap<CellImpl*, HeapRoot>&);
|
||||
void gather_conservative_roots(HashMap<CellImpl*, HeapRoot>&);
|
||||
void gather_asan_fake_stack_roots(HashMap<FlatPtr, HeapRoot>&, FlatPtr, FlatPtr min_block_address, FlatPtr max_block_address);
|
||||
void mark_live_cells(HashMap<Cell*, HeapRoot> const& live_cells);
|
||||
void mark_live_cells(HashMap<CellImpl*, HeapRoot> 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<GCPtr<Cell>> m_uprooted_cells;
|
||||
Vector<GCPtr<CellImpl>> 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<void(HashMap<Cell*, JS::HeapRoot>&)> m_gather_embedder_roots;
|
||||
Function<void(HashMap<CellImpl*, JS::HeapRoot>&)> m_gather_embedder_roots;
|
||||
};
|
||||
|
||||
inline void Heap::did_create_handle(Badge<HandleImpl>, HandleImpl& impl)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <AK/StringView.h>
|
||||
#include <AK/Types.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Heap/CellImpl.h>
|
||||
#include <LibJS/Heap/Internals.h>
|
||||
|
||||
#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<typename Callback>
|
||||
void for_each_cell(Callback callback)
|
||||
|
@ -58,7 +58,7 @@ public:
|
|||
callback(cell(i));
|
||||
}
|
||||
|
||||
template<Cell::State state, typename Callback>
|
||||
template<CellImpl::State state, typename Callback>
|
||||
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<HeapBlock*>(HeapBlockBase::from_cell(cell));
|
||||
}
|
||||
|
||||
Cell* cell_from_possible_pointer(FlatPtr pointer)
|
||||
CellImpl* cell_from_possible_pointer(FlatPtr pointer)
|
||||
{
|
||||
if (pointer < reinterpret_cast<FlatPtr>(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<FreelistEntry> next;
|
||||
};
|
||||
|
||||
Cell* cell(size_t index)
|
||||
CellImpl* cell(size_t index)
|
||||
{
|
||||
return reinterpret_cast<Cell*>(&m_storage[index * cell_size()]);
|
||||
return reinterpret_cast<CellImpl*>(&m_storage[index * cell_size()]);
|
||||
}
|
||||
|
||||
CellAllocator& m_cell_allocator;
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Heap/CellImpl.h>
|
||||
#include <LibJS/Heap/Heap.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
template<typename T>
|
||||
class HeapFunction final : public Cell {
|
||||
JS_CELL(HeapFunction, Cell);
|
||||
class HeapFunction final : public CellImpl {
|
||||
JS_CELL(HeapFunction, CellImpl);
|
||||
|
||||
public:
|
||||
static NonnullGCPtr<HeapFunction> create(Heap& heap, Function<T> function)
|
||||
|
|
|
@ -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<HeapBlockBase*>(bit_cast<FlatPtr>(cell) & ~(HeapBlockBase::block_size - 1));
|
||||
}
|
||||
|
|
|
@ -11,14 +11,14 @@
|
|||
#include <AK/IntrusiveList.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Heap/CellImpl.h>
|
||||
#include <LibJS/Heap/HeapRoot.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class MarkedVectorBase {
|
||||
public:
|
||||
virtual void gather_roots(HashMap<Cell*, JS::HeapRoot>&) const = 0;
|
||||
virtual void gather_roots(HashMap<CellImpl*, JS::HeapRoot>&) const = 0;
|
||||
|
||||
protected:
|
||||
explicit MarkedVectorBase(Heap&);
|
||||
|
@ -65,7 +65,7 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
virtual void gather_roots(HashMap<Cell*, JS::HeapRoot>& roots) const override
|
||||
virtual void gather_roots(HashMap<CellImpl*, JS::HeapRoot>& roots) const override
|
||||
{
|
||||
for (auto& value : *this) {
|
||||
if constexpr (IsSame<Value, T>) {
|
||||
|
|
|
@ -86,16 +86,16 @@ public:
|
|||
return reinterpret_cast<PointerType*>(extract_pointer_bits(m_value.encoded));
|
||||
}
|
||||
|
||||
Cell& as_cell()
|
||||
CellImpl& as_cell()
|
||||
{
|
||||
VERIFY(is_cell());
|
||||
return *extract_pointer<Cell>();
|
||||
return *extract_pointer<CellImpl>();
|
||||
}
|
||||
|
||||
Cell& as_cell() const
|
||||
CellImpl& as_cell() const
|
||||
{
|
||||
VERIFY(is_cell());
|
||||
return *extract_pointer<Cell>();
|
||||
return *extract_pointer<CellImpl>();
|
||||
}
|
||||
|
||||
bool is_nan() const
|
||||
|
|
|
@ -62,7 +62,7 @@ static constexpr auto make_single_ascii_character_strings(IndexSequence<code_poi
|
|||
static constexpr auto single_ascii_character_strings = make_single_ascii_character_strings(MakeIndexSequence<128>());
|
||||
|
||||
VM::VM(OwnPtr<CustomData> custom_data, ErrorMessages error_messages)
|
||||
: m_heap(*this, [this](HashMap<Cell*, JS::HeapRoot>& roots) {
|
||||
: m_heap(this, [this](HashMap<CellImpl*, JS::HeapRoot>& 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<GCPtr<Cell>> roots;
|
||||
HashTable<GCPtr<CellImpl>> roots;
|
||||
};
|
||||
|
||||
void VM::gather_roots(HashMap<Cell*, HeapRoot>& roots)
|
||||
void VM::gather_roots(HashMap<CellImpl*, HeapRoot>& roots)
|
||||
{
|
||||
roots.set(m_empty_string, HeapRoot { .type = HeapRoot::Type::VM });
|
||||
for (auto string : m_single_ascii_character_strings)
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
|
||||
void dump_backtrace() const;
|
||||
|
||||
void gather_roots(HashMap<Cell*, HeapRoot>&);
|
||||
void gather_roots(HashMap<CellImpl*, HeapRoot>&);
|
||||
|
||||
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
||||
NonnullGCPtr<Symbol> well_known_symbol_##snake_name() const \
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <AK/String.h>
|
||||
#include <AK/Types.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Heap/GCPtr.h>
|
||||
#include <LibJS/Heap/Handle.h>
|
||||
#include <LibJS/Heap/NanBoxedValue.h>
|
||||
|
@ -256,6 +257,18 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
Cell& as_cell()
|
||||
{
|
||||
VERIFY(is_cell());
|
||||
return *extract_pointer<Cell>();
|
||||
}
|
||||
|
||||
Cell& as_cell() const
|
||||
{
|
||||
VERIFY(is_cell());
|
||||
return *extract_pointer<Cell>();
|
||||
}
|
||||
|
||||
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<Cell>::create(cell, location))
|
||||
, m_handle(Handle<CellImpl>::create(cell, location))
|
||||
{
|
||||
}
|
||||
|
||||
Optional<Value> m_value;
|
||||
Handle<Cell> m_handle;
|
||||
Handle<CellImpl> m_handle;
|
||||
};
|
||||
|
||||
inline Handle<Value> make_handle(Value value, SourceLocation location = SourceLocation::current())
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <AK/String.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Heap/GCPtr.h>
|
||||
#include <LibJS/Heap/Heap.h>
|
||||
#include <LibWeb/MimeSniff/MimeType.h>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Heap/GCPtr.h>
|
||||
#include <LibJS/Heap/HeapFunction.h>
|
||||
#include <LibWeb/WebIDL/Types.h>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibCore/Forward.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Heap/GCPtr.h>
|
||||
#include <LibJS/Heap/HeapFunction.h>
|
||||
|
||||
|
|
|
@ -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<CellTypeWithOrigin> 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")
|
||||
|
|
|
@ -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<JS::Object*> 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<JS::Object*> 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;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue