mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-30 04:39:06 +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: c2988a7dd5
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
|
CyclicModule.cpp
|
||||||
Heap/BlockAllocator.cpp
|
Heap/BlockAllocator.cpp
|
||||||
Heap/Cell.cpp
|
Heap/Cell.cpp
|
||||||
|
Heap/CellImpl.cpp
|
||||||
Heap/CellAllocator.cpp
|
Heap/CellAllocator.cpp
|
||||||
Heap/ConservativeVector.cpp
|
Heap/ConservativeVector.cpp
|
||||||
Heap/Handle.cpp
|
Heap/Handle.cpp
|
||||||
|
|
|
@ -159,6 +159,7 @@ class BigInt;
|
||||||
class BoundFunction;
|
class BoundFunction;
|
||||||
struct CachedSourceRange;
|
struct CachedSourceRange;
|
||||||
class Cell;
|
class Cell;
|
||||||
|
class CellImpl;
|
||||||
class CellAllocator;
|
class CellAllocator;
|
||||||
class ClassExpression;
|
class ClassExpression;
|
||||||
struct ClassFieldDefinition;
|
struct ClassFieldDefinition;
|
||||||
|
|
|
@ -5,19 +5,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <LibJS/Heap/Cell.h>
|
#include <LibJS/Heap/Cell.h>
|
||||||
#include <LibJS/Heap/Heap.h>
|
|
||||||
#include <LibJS/Heap/NanBoxedValue.h>
|
|
||||||
|
|
||||||
namespace JS {
|
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
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Badge.h>
|
#include <LibJS/Heap/CellImpl.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 {
|
namespace JS {
|
||||||
|
|
||||||
// This instrumentation tells analysis tooling to ignore a potentially mis-wrapped GC-allocated member variable
|
class Cell : public CellImpl {
|
||||||
// It should only be used when the lifetime of the GC-allocated member is always longer than the object
|
JS_CELL(Cell, CellImpl);
|
||||||
#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);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void initialize(Realm&);
|
virtual void initialize(Realm&);
|
||||||
virtual ~Cell() = default;
|
|
||||||
|
|
||||||
bool is_marked() const { return m_mark; }
|
ALWAYS_INLINE VM& vm() const { return *reinterpret_cast<VM*>(private_data()); }
|
||||||
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 };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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())
|
if (!m_list_node.is_in_list())
|
||||||
heap.register_cell_allocator({}, *this);
|
heap.register_cell_allocator({}, *this);
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
|
|
||||||
size_t cell_size() const { return m_cell_size; }
|
size_t cell_size() const { return m_cell_size; }
|
||||||
|
|
||||||
Cell* allocate_cell(Heap&);
|
CellImpl* allocate_cell(Heap&);
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
IterationDecision for_each_block(Callback 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/IntrusiveList.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
#include <LibJS/Heap/Cell.h>
|
#include <LibJS/Heap/CellImpl.h>
|
||||||
#include <LibJS/Heap/HeapRoot.h>
|
#include <LibJS/Heap/HeapRoot.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <LibJS/Heap/Cell.h>
|
#include <LibJS/Heap/CellImpl.h>
|
||||||
#include <LibJS/Heap/Handle.h>
|
#include <LibJS/Heap/Handle.h>
|
||||||
#include <LibJS/Heap/Heap.h>
|
#include <LibJS/Heap/Heap.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
HandleImpl::HandleImpl(Cell* cell, SourceLocation location)
|
HandleImpl::HandleImpl(CellImpl* cell, SourceLocation location)
|
||||||
: m_cell(cell)
|
: m_cell(cell)
|
||||||
, m_location(location)
|
, m_location(location)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,8 +24,8 @@ class HandleImpl : public RefCounted<HandleImpl> {
|
||||||
public:
|
public:
|
||||||
~HandleImpl();
|
~HandleImpl();
|
||||||
|
|
||||||
Cell* cell() { return m_cell; }
|
CellImpl* cell() { return m_cell; }
|
||||||
Cell const* cell() const { return m_cell; }
|
CellImpl const* cell() const { return m_cell; }
|
||||||
|
|
||||||
SourceLocation const& source_location() const { return m_location; }
|
SourceLocation const& source_location() const { return m_location; }
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@ private:
|
||||||
template<class T>
|
template<class T>
|
||||||
friend class Handle;
|
friend class Handle;
|
||||||
|
|
||||||
explicit HandleImpl(Cell*, SourceLocation location);
|
explicit HandleImpl(CellImpl*, SourceLocation location);
|
||||||
GCPtr<Cell> m_cell;
|
GCPtr<CellImpl> m_cell;
|
||||||
SourceLocation m_location;
|
SourceLocation m_location;
|
||||||
|
|
||||||
IntrusiveListNode<HandleImpl> m_list_node;
|
IntrusiveListNode<HandleImpl> m_list_node;
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
Heap::Heap(VM& vm, Function<void(HashMap<Cell*, JS::HeapRoot>&)> gather_embedder_roots)
|
Heap::Heap(void* private_data, Function<void(HashMap<CellImpl*, JS::HeapRoot>&)> gather_embedder_roots)
|
||||||
: HeapBase(vm)
|
: HeapBase(private_data)
|
||||||
, m_gather_embedder_roots(move(gather_embedder_roots))
|
, m_gather_embedder_roots(move(gather_embedder_roots))
|
||||||
{
|
{
|
||||||
static_assert(HeapBlock::min_possible_cell_size <= 32, "Heap Cell tracking uses too much data!");
|
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()) {
|
for (auto possible_pointer : possible_pointers.keys()) {
|
||||||
if (!possible_pointer)
|
if (!possible_pointer)
|
||||||
continue;
|
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))
|
if (!all_live_heap_blocks.contains(possible_heap_block))
|
||||||
continue;
|
continue;
|
||||||
if (auto* cell = possible_heap_block->cell_from_possible_pointer(possible_pointer)) {
|
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:
|
public:
|
||||||
explicit GraphConstructorVisitor(Heap& heap, HashMap<Cell*, HeapRoot> const& roots)
|
explicit GraphConstructorVisitor(Heap& heap, HashMap<CellImpl*, HeapRoot> const& roots)
|
||||||
: m_heap(heap)
|
: m_heap(heap)
|
||||||
{
|
{
|
||||||
m_heap.find_min_and_max_block_addresses(m_min_block_address, m_max_block_address);
|
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)
|
if (m_node_being_visited)
|
||||||
m_node_being_visited->edges.set(reinterpret_cast<FlatPtr>(&cell));
|
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)
|
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);
|
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)
|
if (m_node_being_visited)
|
||||||
m_node_being_visited->edges.set(reinterpret_cast<FlatPtr>(cell));
|
m_node_being_visited->edges.set(reinterpret_cast<FlatPtr>(cell));
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
GraphNode* m_node_being_visited { nullptr };
|
GraphNode* m_node_being_visited { nullptr };
|
||||||
Vector<NonnullGCPtr<Cell>> m_work_queue;
|
Vector<NonnullGCPtr<CellImpl>> m_work_queue;
|
||||||
HashMap<FlatPtr, GraphNode> m_graph;
|
HashMap<FlatPtr, GraphNode> m_graph;
|
||||||
|
|
||||||
Heap& m_heap;
|
Heap& m_heap;
|
||||||
|
@ -229,7 +229,7 @@ private:
|
||||||
|
|
||||||
AK::JsonObject Heap::dump_graph()
|
AK::JsonObject Heap::dump_graph()
|
||||||
{
|
{
|
||||||
HashMap<Cell*, HeapRoot> roots;
|
HashMap<CellImpl*, HeapRoot> roots;
|
||||||
gather_roots(roots);
|
gather_roots(roots);
|
||||||
GraphConstructorVisitor visitor(*this, roots);
|
GraphConstructorVisitor visitor(*this, roots);
|
||||||
visitor.visit_all_cells();
|
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;
|
m_should_gc_when_deferral_ends = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
HashMap<Cell*, HeapRoot> roots;
|
HashMap<CellImpl*, HeapRoot> roots;
|
||||||
gather_roots(roots);
|
gather_roots(roots);
|
||||||
mark_live_cells(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);
|
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);
|
m_gather_embedder_roots(roots);
|
||||||
gather_conservative_roots(roots);
|
gather_conservative_roots(roots);
|
||||||
|
@ -298,7 +298,7 @@ void Heap::gather_asan_fake_stack_roots(HashMap<FlatPtr, HeapRoot>&, FlatPtr, Fl
|
||||||
}
|
}
|
||||||
#endif
|
#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;
|
FlatPtr dummy;
|
||||||
|
|
||||||
|
@ -337,8 +337,8 @@ NO_SANITIZE_ADDRESS void Heap::gather_conservative_roots(HashMap<Cell*, HeapRoot
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
|
|
||||||
for_each_cell_among_possible_pointers(all_live_heap_blocks, possible_pointers, [&](Cell* cell, FlatPtr possible_pointer) {
|
for_each_cell_among_possible_pointers(all_live_heap_blocks, possible_pointers, [&](CellImpl* cell, FlatPtr possible_pointer) {
|
||||||
if (cell->state() == Cell::State::Live) {
|
if (cell->state() == CellImpl::State::Live) {
|
||||||
dbgln_if(HEAP_DEBUG, " ?-> {}", (void const*)cell);
|
dbgln_if(HEAP_DEBUG, " ?-> {}", (void const*)cell);
|
||||||
roots.set(cell, *possible_pointers.get(possible_pointer));
|
roots.set(cell, *possible_pointers.get(possible_pointer));
|
||||||
} else {
|
} 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:
|
public:
|
||||||
explicit MarkingVisitor(Heap& heap, HashMap<Cell*, HeapRoot> const& roots)
|
explicit MarkingVisitor(Heap& heap, HashMap<CellImpl*, HeapRoot> const& roots)
|
||||||
: m_heap(heap)
|
: m_heap(heap)
|
||||||
{
|
{
|
||||||
m_heap.find_min_and_max_block_addresses(m_min_block_address, m_max_block_address);
|
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())
|
if (cell.is_marked())
|
||||||
return;
|
return;
|
||||||
|
@ -381,10 +381,10 @@ public:
|
||||||
for (size_t i = 0; i < (bytes.size() / sizeof(FlatPtr)); ++i)
|
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);
|
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())
|
if (cell->is_marked())
|
||||||
return;
|
return;
|
||||||
if (cell->state() != Cell::State::Live)
|
if (cell->state() != CellImpl::State::Live)
|
||||||
return;
|
return;
|
||||||
cell->set_marked(true);
|
cell->set_marked(true);
|
||||||
m_work_queue.append(*cell);
|
m_work_queue.append(*cell);
|
||||||
|
@ -400,13 +400,13 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Heap& m_heap;
|
Heap& m_heap;
|
||||||
Vector<NonnullGCPtr<Cell>> m_work_queue;
|
Vector<NonnullGCPtr<CellImpl>> m_work_queue;
|
||||||
HashTable<HeapBlock*> m_all_live_heap_blocks;
|
HashTable<HeapBlock*> m_all_live_heap_blocks;
|
||||||
FlatPtr m_min_block_address;
|
FlatPtr m_min_block_address;
|
||||||
FlatPtr m_max_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:");
|
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();
|
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({}))
|
if (!cell.overrides_must_survive_garbage_collection({}))
|
||||||
return false;
|
return false;
|
||||||
|
@ -430,7 +430,7 @@ bool Heap::cell_must_survive_garbage_collection(Cell const& cell)
|
||||||
void Heap::finalize_unmarked_cells()
|
void Heap::finalize_unmarked_cells()
|
||||||
{
|
{
|
||||||
for_each_block([&](auto& block) {
|
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))
|
if (!cell->is_marked() && !cell_must_survive_garbage_collection(*cell))
|
||||||
cell->finalize();
|
cell->finalize();
|
||||||
});
|
});
|
||||||
|
@ -452,7 +452,7 @@ void Heap::sweep_dead_cells(bool print_report, Core::ElapsedTimer const& measure
|
||||||
for_each_block([&](auto& block) {
|
for_each_block([&](auto& block) {
|
||||||
bool block_has_live_cells = false;
|
bool block_has_live_cells = false;
|
||||||
bool block_was_full = block.is_full();
|
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)) {
|
if (!cell->is_marked() && !cell_must_survive_garbage_collection(*cell)) {
|
||||||
dbgln_if(HEAP_DEBUG, " ~ {}", cell);
|
dbgln_if(HEAP_DEBUG, " ~ {}", cell);
|
||||||
block.deallocate(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);
|
m_uprooted_cells.append(cell);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibCore/Forward.h>
|
#include <LibCore/Forward.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
#include <LibJS/Heap/Cell.h>
|
|
||||||
#include <LibJS/Heap/CellAllocator.h>
|
#include <LibJS/Heap/CellAllocator.h>
|
||||||
|
#include <LibJS/Heap/CellImpl.h>
|
||||||
#include <LibJS/Heap/ConservativeVector.h>
|
#include <LibJS/Heap/ConservativeVector.h>
|
||||||
#include <LibJS/Heap/Handle.h>
|
#include <LibJS/Heap/Handle.h>
|
||||||
#include <LibJS/Heap/HeapRoot.h>
|
#include <LibJS/Heap/HeapRoot.h>
|
||||||
|
@ -33,7 +33,7 @@ class Heap : public HeapBase {
|
||||||
AK_MAKE_NONMOVABLE(Heap);
|
AK_MAKE_NONMOVABLE(Heap);
|
||||||
|
|
||||||
public:
|
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();
|
~Heap();
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
template<typename T, typename... Args>
|
||||||
|
@ -71,7 +71,7 @@ public:
|
||||||
|
|
||||||
void register_cell_allocator(Badge<CellAllocator>, CellAllocator&);
|
void register_cell_allocator(Badge<CellAllocator>, CellAllocator&);
|
||||||
|
|
||||||
void uproot_cell(Cell* cell);
|
void uproot_cell(CellImpl* cell);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class MarkingVisitor;
|
friend class MarkingVisitor;
|
||||||
|
@ -81,10 +81,10 @@ private:
|
||||||
void defer_gc();
|
void defer_gc();
|
||||||
void undefer_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>
|
template<typename T>
|
||||||
Cell* allocate_cell()
|
CellImpl* allocate_cell()
|
||||||
{
|
{
|
||||||
will_allocate(sizeof(T));
|
will_allocate(sizeof(T));
|
||||||
if constexpr (requires { T::cell_allocator.allocator.get().allocate_cell(*this); }) {
|
if constexpr (requires { T::cell_allocator.allocator.get().allocate_cell(*this); }) {
|
||||||
|
@ -98,10 +98,10 @@ private:
|
||||||
void will_allocate(size_t);
|
void will_allocate(size_t);
|
||||||
|
|
||||||
void find_min_and_max_block_addresses(FlatPtr& min_address, FlatPtr& max_address);
|
void find_min_and_max_block_addresses(FlatPtr& min_address, FlatPtr& max_address);
|
||||||
void gather_roots(HashMap<Cell*, HeapRoot>&);
|
void gather_roots(HashMap<CellImpl*, HeapRoot>&);
|
||||||
void gather_conservative_roots(HashMap<Cell*, 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 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 finalize_unmarked_cells();
|
||||||
void sweep_dead_cells(bool print_report, Core::ElapsedTimer const&);
|
void sweep_dead_cells(bool print_report, Core::ElapsedTimer const&);
|
||||||
|
|
||||||
|
@ -139,14 +139,14 @@ private:
|
||||||
ConservativeVectorBase::List m_conservative_vectors;
|
ConservativeVectorBase::List m_conservative_vectors;
|
||||||
WeakContainer::List m_weak_containers;
|
WeakContainer::List m_weak_containers;
|
||||||
|
|
||||||
Vector<GCPtr<Cell>> m_uprooted_cells;
|
Vector<GCPtr<CellImpl>> m_uprooted_cells;
|
||||||
|
|
||||||
size_t m_gc_deferrals { 0 };
|
size_t m_gc_deferrals { 0 };
|
||||||
bool m_should_gc_when_deferral_ends { false };
|
bool m_should_gc_when_deferral_ends { false };
|
||||||
|
|
||||||
bool m_collecting_garbage { false };
|
bool m_collecting_garbage { false };
|
||||||
StackInfo m_stack_info;
|
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)
|
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));
|
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(is_valid_cell_pointer(cell));
|
||||||
VERIFY(!m_freelist || is_valid_cell_pointer(m_freelist));
|
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());
|
VERIFY(!cell->is_marked());
|
||||||
|
|
||||||
cell->~Cell();
|
cell->~CellImpl();
|
||||||
auto* freelist_entry = new (cell) FreelistEntry();
|
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;
|
freelist_entry->next = m_freelist;
|
||||||
m_freelist = freelist_entry;
|
m_freelist = freelist_entry;
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <AK/StringView.h>
|
#include <AK/StringView.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
#include <LibJS/Heap/Cell.h>
|
#include <LibJS/Heap/CellImpl.h>
|
||||||
#include <LibJS/Heap/Internals.h>
|
#include <LibJS/Heap/Internals.h>
|
||||||
|
|
||||||
#ifdef HAS_ADDRESS_SANITIZER
|
#ifdef HAS_ADDRESS_SANITIZER
|
||||||
|
@ -32,9 +32,9 @@ public:
|
||||||
size_t cell_count() const { return (block_size - sizeof(HeapBlock)) / m_cell_size; }
|
size_t cell_count() const { return (block_size - sizeof(HeapBlock)) / m_cell_size; }
|
||||||
bool is_full() const { return !has_lazy_freelist() && !m_freelist; }
|
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) {
|
if (m_freelist) {
|
||||||
VERIFY(is_valid_cell_pointer(m_freelist));
|
VERIFY(is_valid_cell_pointer(m_freelist));
|
||||||
allocated_cell = exchange(m_freelist, m_freelist->next);
|
allocated_cell = exchange(m_freelist, m_freelist->next);
|
||||||
|
@ -48,7 +48,7 @@ public:
|
||||||
return allocated_cell;
|
return allocated_cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deallocate(Cell*);
|
void deallocate(CellImpl*);
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void for_each_cell(Callback callback)
|
void for_each_cell(Callback callback)
|
||||||
|
@ -58,7 +58,7 @@ public:
|
||||||
callback(cell(i));
|
callback(cell(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Cell::State state, typename Callback>
|
template<CellImpl::State state, typename Callback>
|
||||||
void for_each_cell_in_state(Callback callback)
|
void for_each_cell_in_state(Callback callback)
|
||||||
{
|
{
|
||||||
for_each_cell([&](auto* cell) {
|
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));
|
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))
|
if (pointer < reinterpret_cast<FlatPtr>(m_storage))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -83,7 +83,7 @@ public:
|
||||||
return cell(cell_index);
|
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);
|
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(); }
|
bool has_lazy_freelist() const { return m_next_lazy_freelist_index < cell_count(); }
|
||||||
|
|
||||||
struct FreelistEntry final : public Cell {
|
struct FreelistEntry final : public CellImpl {
|
||||||
JS_CELL(FreelistEntry, Cell);
|
JS_CELL(FreelistEntry, CellImpl);
|
||||||
|
|
||||||
RawGCPtr<FreelistEntry> next;
|
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;
|
CellAllocator& m_cell_allocator;
|
||||||
|
|
|
@ -7,14 +7,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <LibJS/Heap/Cell.h>
|
#include <LibJS/Heap/CellImpl.h>
|
||||||
#include <LibJS/Heap/Heap.h>
|
#include <LibJS/Heap/Heap.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class HeapFunction final : public Cell {
|
class HeapFunction final : public CellImpl {
|
||||||
JS_CELL(HeapFunction, Cell);
|
JS_CELL(HeapFunction, CellImpl);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static NonnullGCPtr<HeapFunction> create(Heap& heap, Function<T> function)
|
static NonnullGCPtr<HeapFunction> create(Heap& heap, Function<T> function)
|
||||||
|
|
|
@ -17,15 +17,15 @@ class HeapBase {
|
||||||
AK_MAKE_NONMOVABLE(HeapBase);
|
AK_MAKE_NONMOVABLE(HeapBase);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VM& vm() { return m_vm; }
|
void* private_data() { return m_private_data; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HeapBase(VM& vm)
|
explicit HeapBase(void* private_data)
|
||||||
: m_vm(vm)
|
: m_private_data(private_data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
VM& m_vm;
|
void* m_private_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HeapBlockBase {
|
class HeapBlockBase {
|
||||||
|
@ -34,7 +34,7 @@ class HeapBlockBase {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static size_t block_size;
|
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));
|
return reinterpret_cast<HeapBlockBase*>(bit_cast<FlatPtr>(cell) & ~(HeapBlockBase::block_size - 1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,14 @@
|
||||||
#include <AK/IntrusiveList.h>
|
#include <AK/IntrusiveList.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
#include <LibJS/Heap/Cell.h>
|
#include <LibJS/Heap/CellImpl.h>
|
||||||
#include <LibJS/Heap/HeapRoot.h>
|
#include <LibJS/Heap/HeapRoot.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
class MarkedVectorBase {
|
class MarkedVectorBase {
|
||||||
public:
|
public:
|
||||||
virtual void gather_roots(HashMap<Cell*, JS::HeapRoot>&) const = 0;
|
virtual void gather_roots(HashMap<CellImpl*, JS::HeapRoot>&) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit MarkedVectorBase(Heap&);
|
explicit MarkedVectorBase(Heap&);
|
||||||
|
@ -65,7 +65,7 @@ public:
|
||||||
return *this;
|
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) {
|
for (auto& value : *this) {
|
||||||
if constexpr (IsSame<Value, T>) {
|
if constexpr (IsSame<Value, T>) {
|
||||||
|
|
|
@ -86,16 +86,16 @@ public:
|
||||||
return reinterpret_cast<PointerType*>(extract_pointer_bits(m_value.encoded));
|
return reinterpret_cast<PointerType*>(extract_pointer_bits(m_value.encoded));
|
||||||
}
|
}
|
||||||
|
|
||||||
Cell& as_cell()
|
CellImpl& as_cell()
|
||||||
{
|
{
|
||||||
VERIFY(is_cell());
|
VERIFY(is_cell());
|
||||||
return *extract_pointer<Cell>();
|
return *extract_pointer<CellImpl>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Cell& as_cell() const
|
CellImpl& as_cell() const
|
||||||
{
|
{
|
||||||
VERIFY(is_cell());
|
VERIFY(is_cell());
|
||||||
return *extract_pointer<Cell>();
|
return *extract_pointer<CellImpl>();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_nan() const
|
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>());
|
static constexpr auto single_ascii_character_strings = make_single_ascii_character_strings(MakeIndexSequence<128>());
|
||||||
|
|
||||||
VM::VM(OwnPtr<CustomData> custom_data, ErrorMessages error_messages)
|
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);
|
gather_roots(roots);
|
||||||
})
|
})
|
||||||
, m_error_messages(move(error_messages))
|
, m_error_messages(move(error_messages))
|
||||||
|
@ -204,7 +204,7 @@ Bytecode::Interpreter& VM::bytecode_interpreter()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExecutionContextRootsCollector : public Cell::Visitor {
|
struct ExecutionContextRootsCollector : public Cell::Visitor {
|
||||||
virtual void visit_impl(Cell& cell) override
|
virtual void visit_impl(CellImpl& cell) override
|
||||||
{
|
{
|
||||||
roots.set(&cell);
|
roots.set(&cell);
|
||||||
}
|
}
|
||||||
|
@ -214,10 +214,10 @@ struct ExecutionContextRootsCollector : public Cell::Visitor {
|
||||||
VERIFY_NOT_REACHED();
|
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 });
|
roots.set(m_empty_string, HeapRoot { .type = HeapRoot::Type::VM });
|
||||||
for (auto string : m_single_ascii_character_strings)
|
for (auto string : m_single_ascii_character_strings)
|
||||||
|
|
|
@ -60,7 +60,7 @@ public:
|
||||||
|
|
||||||
void dump_backtrace() const;
|
void dump_backtrace() const;
|
||||||
|
|
||||||
void gather_roots(HashMap<Cell*, HeapRoot>&);
|
void gather_roots(HashMap<CellImpl*, HeapRoot>&);
|
||||||
|
|
||||||
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
||||||
NonnullGCPtr<Symbol> well_known_symbol_##snake_name() const \
|
NonnullGCPtr<Symbol> well_known_symbol_##snake_name() const \
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
|
#include <LibJS/Heap/Cell.h>
|
||||||
#include <LibJS/Heap/GCPtr.h>
|
#include <LibJS/Heap/GCPtr.h>
|
||||||
#include <LibJS/Heap/Handle.h>
|
#include <LibJS/Heap/Handle.h>
|
||||||
#include <LibJS/Heap/NanBoxedValue.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
|
double as_double() const
|
||||||
{
|
{
|
||||||
VERIFY(is_number());
|
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_value(value)
|
||||||
, m_handle(Handle<Cell>::create(cell, location))
|
, m_handle(Handle<CellImpl>::create(cell, location))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<Value> m_value;
|
Optional<Value> m_value;
|
||||||
Handle<Cell> m_handle;
|
Handle<CellImpl> m_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Handle<Value> make_handle(Value value, SourceLocation location = SourceLocation::current())
|
inline Handle<Value> make_handle(Value value, SourceLocation location = SourceLocation::current())
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
|
#include <LibJS/Heap/Cell.h>
|
||||||
#include <LibJS/Heap/GCPtr.h>
|
#include <LibJS/Heap/GCPtr.h>
|
||||||
#include <LibJS/Heap/Heap.h>
|
#include <LibJS/Heap/Heap.h>
|
||||||
#include <LibWeb/MimeSniff/MimeType.h>
|
#include <LibWeb/MimeSniff/MimeType.h>
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
|
#include <LibJS/Heap/Cell.h>
|
||||||
#include <LibJS/Heap/GCPtr.h>
|
#include <LibJS/Heap/GCPtr.h>
|
||||||
#include <LibJS/Heap/HeapFunction.h>
|
#include <LibJS/Heap/HeapFunction.h>
|
||||||
#include <LibWeb/WebIDL/Types.h>
|
#include <LibWeb/WebIDL/Types.h>
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LibCore/Forward.h>
|
#include <LibCore/Forward.h>
|
||||||
|
#include <LibJS/Heap/Cell.h>
|
||||||
#include <LibJS/Heap/GCPtr.h>
|
#include <LibJS/Heap/GCPtr.h>
|
||||||
#include <LibJS/Heap/HeapFunction.h>
|
#include <LibJS/Heap/HeapFunction.h>
|
||||||
|
|
||||||
|
|
|
@ -39,9 +39,9 @@ static bool record_inherits_from_cell(clang::CXXRecordDecl const& record)
|
||||||
if (!record.isCompleteDefinition())
|
if (!record.isCompleteDefinition())
|
||||||
return false;
|
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 {
|
record.forallBases([&](clang::CXXRecordDecl const* base) -> bool {
|
||||||
if (base->getQualifiedNameAsString() == "JS::Cell") {
|
if (base->getQualifiedNameAsString() == "JS::CellImpl") {
|
||||||
inherits_from_cell = true;
|
inherits_from_cell = true;
|
||||||
return false;
|
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
|
// 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.
|
// it doesn't have any members anyways so it's fine to just ignore.
|
||||||
auto qualified_name = record->getQualifiedNameAsString();
|
auto qualified_name = record->getQualifiedNameAsString();
|
||||||
if (qualified_name == "JS::Cell")
|
if (qualified_name == "JS::CellImpl")
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
auto& diag_engine = m_context.getDiagnostics();
|
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 (outer_type == OuterType::Ptr || outer_type == OuterType::Ref) {
|
||||||
if (base_type_inherits_from_cell) {
|
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);
|
auto builder = diag_engine.Report(field->getLocation(), diag_id);
|
||||||
if (outer_type == OuterType::Ref) {
|
if (outer_type == OuterType::Ref) {
|
||||||
builder << "reference"
|
builder << "reference"
|
||||||
|
@ -204,7 +204,7 @@ bool LibJSGCVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* record)
|
||||||
}
|
}
|
||||||
} else if (outer_type == OuterType::GCPtr || outer_type == OuterType::RawGCPtr) {
|
} else if (outer_type == OuterType::GCPtr || outer_type == OuterType::RawGCPtr) {
|
||||||
if (!base_type_inherits_from_cell) {
|
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);
|
diag_engine.Report(field->getLocation(), diag_id);
|
||||||
} else if (outer_type == OuterType::GCPtr) {
|
} else if (outer_type == OuterType::GCPtr) {
|
||||||
fields_that_need_visiting.push_back(field);
|
fields_that_need_visiting.push_back(field);
|
||||||
|
@ -212,7 +212,7 @@ bool LibJSGCVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl* record)
|
||||||
} else if (outer_type == OuterType::Handle) {
|
} else if (outer_type == OuterType::Handle) {
|
||||||
if (record_is_cell && m_detect_invalid_function_members) {
|
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
|
// 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);
|
auto builder = diag_engine.Report(field->getLocation(), diag_id);
|
||||||
builder << "JS::Handle";
|
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()) {
|
if (auto const* base_record = base.getType()->getAsCXXRecordDecl()) {
|
||||||
auto base_name = base_record->getQualifiedNameAsString();
|
auto base_name = base_record->getQualifiedNameAsString();
|
||||||
|
|
||||||
if (base_name == "JS::Cell")
|
if (base_name == "JS::CellImpl")
|
||||||
return CellTypeWithOrigin { *base_record, LibJSCellMacro::Type::JSCell };
|
return CellTypeWithOrigin { *base_record, LibJSCellMacro::Type::JSCell };
|
||||||
|
|
||||||
if (base_name == "JS::Object")
|
if (base_name == "JS::Object")
|
||||||
|
|
|
@ -30,15 +30,15 @@ private:
|
||||||
visitor.visit(m_object_ptr);
|
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;
|
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;
|
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;
|
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;
|
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;
|
NewType2* m_newtype_2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,14 +50,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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;
|
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;
|
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;
|
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;
|
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;
|
NewType2* m_newtype_2;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue