diff --git a/Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp b/Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp index d9eda3ba9b..fe94e33986 100644 --- a/Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp +++ b/Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp @@ -10,19 +10,14 @@ namespace JS::Bytecode { -NonnullOwnPtr BasicBlock::create(DeprecatedString name, size_t size) +NonnullOwnPtr BasicBlock::create(DeprecatedString name) { - return adopt_own(*new BasicBlock(move(name), max(size, static_cast(4 * KiB)))); + return adopt_own(*new BasicBlock(move(name))); } -BasicBlock::BasicBlock(DeprecatedString name, size_t size) +BasicBlock::BasicBlock(DeprecatedString name) : m_name(move(name)) { - // FIXME: This is not the smartest solution ever. Find something cleverer! - // The main issue we're working around here is that we don't want pointers into the bytecode stream to become invalidated - // during code generation due to dynamic buffer resizing. Otherwise we could just use a Vector. - m_buffer_capacity = size; - m_buffer = new u8[m_buffer_capacity]; } BasicBlock::~BasicBlock() @@ -33,16 +28,6 @@ BasicBlock::~BasicBlock() ++it; Instruction::destroy(const_cast(to_destroy)); } - - delete[] m_buffer; -} - -void BasicBlock::seal() -{ - // FIXME: mprotect the instruction stream as PROT_READ - // This is currently not possible because instructions can have destructors (that clean up strings) - // Instructions should instead be destructor-less and refer to strings in a string table on the Bytecode::Block. - // It also doesn't work because instructions that have String members use RefPtr internally which must be in writable memory. } void BasicBlock::dump(Bytecode::Executable const& executable) const @@ -58,8 +43,7 @@ void BasicBlock::dump(Bytecode::Executable const& executable) const void BasicBlock::grow(size_t additional_size) { - m_buffer_size += additional_size; - VERIFY(m_buffer_size <= m_buffer_capacity); + m_buffer.resize(m_buffer.size() + additional_size); } } diff --git a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h index f2d7ea917c..cb4d6d05f3 100644 --- a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h +++ b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h @@ -27,33 +27,28 @@ class BasicBlock { AK_MAKE_NONCOPYABLE(BasicBlock); public: - static NonnullOwnPtr create(DeprecatedString name, size_t size = 4 * KiB); + static NonnullOwnPtr create(DeprecatedString name); ~BasicBlock(); - void seal(); - void dump(Executable const&) const; - ReadonlyBytes instruction_stream() const { return ReadonlyBytes { m_buffer, m_buffer_size }; } - size_t size() const { return m_buffer_size; } + ReadonlyBytes instruction_stream() const { return m_buffer.span(); } + u8* data() { return m_buffer.data(); } + u8 const* data() const { return m_buffer.data(); } + size_t size() const { return m_buffer.size(); } - void* next_slot() { return m_buffer + m_buffer_size; } - bool can_grow(size_t additional_size) const { return m_buffer_size + additional_size <= m_buffer_capacity; } void grow(size_t additional_size); - void terminate(Badge, Instruction const* terminator) { m_terminator = terminator; } - bool is_terminated() const { return m_terminator != nullptr; } - Instruction const* terminator() const { return m_terminator; } + void terminate(Badge) { m_terminated = true; } + bool is_terminated() const { return m_terminated; } DeprecatedString const& name() const { return m_name; } private: - BasicBlock(DeprecatedString name, size_t size); + explicit BasicBlock(DeprecatedString name); - u8* m_buffer { nullptr }; - Instruction const* m_terminator { nullptr }; - size_t m_buffer_capacity { 0 }; - size_t m_buffer_size { 0 }; + Vector m_buffer; DeprecatedString m_name; + bool m_terminated { false }; }; } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index f7cf70de16..d52533ae83 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -82,12 +82,6 @@ void Generator::grow(size_t additional_size) m_current_basic_block->grow(additional_size); } -void* Generator::next_slot() -{ - VERIFY(m_current_basic_block); - return m_current_basic_block->next_slot(); -} - Register Generator::allocate_register() { VERIFY(m_next_register != NumericLimits::max()); diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index 9a086aed2b..49df3699b1 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -34,18 +34,6 @@ public: Register allocate_register(); - void ensure_enough_space(size_t size) - { - // Make sure there's always enough space for a single jump at the end. - if (!m_current_basic_block->can_grow(size + sizeof(Op::Jump))) { - auto& new_block = make_block(); - emit().set_targets( - Label { new_block }, - {}); - switch_to_basic_block(new_block); - } - } - class SourceLocationScope { public: SourceLocationScope(Generator&, ASTNode const& node); @@ -60,15 +48,12 @@ public: OpType& emit(Args&&... args) { VERIFY(!is_current_block_terminated()); - // If the block doesn't have enough space, switch to another block - if constexpr (!OpType::IsTerminator) - ensure_enough_space(sizeof(OpType)); - - void* slot = next_slot(); + size_t slot_offset = m_current_basic_block->size(); grow(sizeof(OpType)); + void* slot = m_current_basic_block->data() + slot_offset; new (slot) OpType(forward(args)...); if constexpr (OpType::IsTerminator) - m_current_basic_block->terminate({}, static_cast(slot)); + m_current_basic_block->terminate({}); auto* op = static_cast(slot); op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() }); return *op; @@ -80,16 +65,12 @@ public: VERIFY(!is_current_block_terminated()); size_t size_to_allocate = round_up_to_power_of_two(sizeof(OpType) + extra_register_slots * sizeof(Register), alignof(void*)); - - // If the block doesn't have enough space, switch to another block - if constexpr (!OpType::IsTerminator) - ensure_enough_space(size_to_allocate); - - void* slot = next_slot(); + size_t slot_offset = m_current_basic_block->size(); grow(size_to_allocate); + void* slot = m_current_basic_block->data() + slot_offset; new (slot) OpType(forward(args)...); if constexpr (OpType::IsTerminator) - m_current_basic_block->terminate({}, static_cast(slot)); + m_current_basic_block->terminate({}); auto* op = static_cast(slot); op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() }); return *op; @@ -238,7 +219,6 @@ private: ~Generator() = default; void grow(size_t); - void* next_slot(); struct LabelableScope { Label bytecode_target;