mirror of
https://github.com/SerenityOS/serenity
synced 2024-10-15 20:33:10 +00:00
LibJS: Add ASTNodeWithTailArray template to pack AST node + array
This template allows us to allocate an AST node and an array of some arbitrary type T with one allocation instead of two. This can save a lot of memory in some cases. Thanks to Jonathan Müller for suggesting this technique! :^)
This commit is contained in:
parent
c767535ca2
commit
8a8d8ecb35
|
@ -49,6 +49,10 @@ create_ast_node(SourceRange range, Args&&... args)
|
|||
class ASTNode : public RefCounted<ASTNode> {
|
||||
public:
|
||||
virtual ~ASTNode() = default;
|
||||
|
||||
// NOTE: This is here to stop ASAN complaining about mismatch between new/delete sizes in ASTNodeWithTailArray.
|
||||
void operator delete(void* ptr) { ::operator delete(ptr); }
|
||||
|
||||
virtual Completion execute(Interpreter&) const = 0;
|
||||
virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const;
|
||||
virtual void dump(int indent) const;
|
||||
|
@ -97,6 +101,46 @@ private:
|
|||
u32 m_end_offset { 0 };
|
||||
};
|
||||
|
||||
// This is a helper class that packs an array of T after the AST node, all in the same allocation.
|
||||
template<typename Derived, typename Base, typename T>
|
||||
class ASTNodeWithTailArray : public Base {
|
||||
public:
|
||||
virtual ~ASTNodeWithTailArray() override
|
||||
{
|
||||
for (auto& value : tail_span())
|
||||
value.~T();
|
||||
}
|
||||
|
||||
Span<T const> tail_span() const { return { tail_data(), tail_size() }; }
|
||||
|
||||
T const* tail_data() const { return reinterpret_cast<T const*>(reinterpret_cast<uintptr_t>(this) + sizeof(Derived)); }
|
||||
size_t tail_size() const { return m_tail_size; }
|
||||
|
||||
protected:
|
||||
template<typename ActualDerived = Derived, typename... Args>
|
||||
static NonnullRefPtr<ActualDerived> create(size_t tail_size, SourceRange source_range, Args&&... args)
|
||||
{
|
||||
static_assert(sizeof(ActualDerived) == sizeof(Derived), "This leaf class cannot add more members");
|
||||
static_assert(alignof(ActualDerived) % alignof(T) == 0, "Need padding for tail array");
|
||||
auto memory = ::operator new(sizeof(ActualDerived) + tail_size * sizeof(T));
|
||||
return adopt_ref(*::new (memory) ActualDerived(move(source_range), forward<Args>(args)...));
|
||||
}
|
||||
|
||||
ASTNodeWithTailArray(SourceRange source_range, Span<T const> values)
|
||||
: Base(move(source_range))
|
||||
, m_tail_size(values.size())
|
||||
{
|
||||
VERIFY(values.size() <= NumericLimits<u32>::max());
|
||||
for (size_t i = 0; i < values.size(); ++i)
|
||||
new (&tail_data()[i]) T(values[i]);
|
||||
}
|
||||
|
||||
private:
|
||||
T* tail_data() { return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(this) + sizeof(Derived)); }
|
||||
|
||||
u32 m_tail_size { 0 };
|
||||
};
|
||||
|
||||
class Statement : public ASTNode {
|
||||
public:
|
||||
explicit Statement(SourceRange source_range)
|
||||
|
|
Loading…
Reference in a new issue