diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index dd92c4a196..ad24e32e50 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -119,16 +119,16 @@ void LogicalExpression::generate_bytecode(Bytecode::Generator& generator) const { m_lhs->generate_bytecode(generator); - Bytecode::Op::Jump* test_instr; + Bytecode::InstructionHandle test_instr; switch (m_op) { case LogicalOp::And: - test_instr = &generator.emit(); + test_instr = generator.emit(); break; case LogicalOp::Or: - test_instr = &generator.emit(); + test_instr = generator.emit(); break; case LogicalOp::NullishCoalescing: - test_instr = &generator.emit(); + test_instr = generator.emit(); break; default: VERIFY_NOT_REACHED(); @@ -285,10 +285,10 @@ void WhileStatement::generate_bytecode(Bytecode::Generator& generator) const auto result_reg = generator.allocate_register(); generator.emit(result_reg); m_test->generate_bytecode(generator); - auto& test_jump = generator.emit(); + auto test_jump = generator.emit(); m_body->generate_bytecode(generator); generator.emit(test_label); - test_jump.set_target(generator.make_label()); + test_jump->set_target(generator.make_label()); generator.end_continuable_scope(); generator.emit(result_reg); } @@ -309,7 +309,7 @@ void DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const void ForStatement::generate_bytecode(Bytecode::Generator& generator) const { - Bytecode::Op::Jump* test_jump { nullptr }; + Bytecode::InstructionHandle test_jump; if (m_init) m_init->generate_bytecode(generator); @@ -321,7 +321,7 @@ void ForStatement::generate_bytecode(Bytecode::Generator& generator) const generator.emit(result_reg); if (m_test) { m_test->generate_bytecode(generator); - test_jump = &generator.emit(); + test_jump = generator.emit(); } m_body->generate_bytecode(generator); @@ -387,16 +387,16 @@ void ReturnStatement::generate_bytecode(Bytecode::Generator& generator) const void IfStatement::generate_bytecode(Bytecode::Generator& generator) const { m_predicate->generate_bytecode(generator); - auto& else_jump = generator.emit(); + auto else_jump = generator.emit(); m_consequent->generate_bytecode(generator); if (m_alternate) { - auto& if_jump = generator.emit(); - else_jump.set_target(generator.make_label()); + auto if_jump = generator.emit(); + else_jump->set_target(generator.make_label()); m_alternate->generate_bytecode(generator); - if_jump.set_target(generator.make_label()); + if_jump->set_target(generator.make_label()); } else { - else_jump.set_target(generator.make_label()); + else_jump->set_target(generator.make_label()); } } @@ -412,15 +412,15 @@ void DebuggerStatement::generate_bytecode(Bytecode::Generator&) const void ConditionalExpression::generate_bytecode(Bytecode::Generator& generator) const { m_test->generate_bytecode(generator); - auto& alternate_jump = generator.emit(); + auto alternate_jump = generator.emit(); m_consequent->generate_bytecode(generator); - auto& end_jump = generator.emit(); + auto end_jump = generator.emit(); - alternate_jump.set_target(generator.make_label()); + alternate_jump->set_target(generator.make_label()); m_alternate->generate_bytecode(generator); - end_jump.set_target(generator.make_label()); + end_jump->set_target(generator.make_label()); } void SequenceExpression::generate_bytecode(Bytecode::Generator& generator) const diff --git a/Userland/Libraries/LibJS/Bytecode/Block.cpp b/Userland/Libraries/LibJS/Bytecode/Block.cpp index ef0add31a1..7ca1a43ec0 100644 --- a/Userland/Libraries/LibJS/Bytecode/Block.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Block.cpp @@ -4,10 +4,8 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include #include #include -#include namespace JS::Bytecode { @@ -16,16 +14,6 @@ NonnullOwnPtr Block::create() return adopt_own(*new Block); } -Block::Block() -{ - // 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 = 64 * KiB; - m_buffer = (u8*)mmap(nullptr, m_buffer_capacity, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); - VERIFY(m_buffer != MAP_FAILED); -} - Block::~Block() { Bytecode::InstructionStreamIterator it(instruction_stream()); @@ -34,16 +22,6 @@ Block::~Block() ++it; Instruction::destroy(const_cast(to_destroy)); } - - munmap(m_buffer, m_buffer_capacity); -} - -void Block::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 Block::dump() const @@ -55,12 +33,6 @@ void Block::dump() const } } -void Block::grow(size_t additional_size) -{ - m_buffer_size += additional_size; - VERIFY(m_buffer_size <= m_buffer_capacity); -} - void InstructionStreamIterator::operator++() { m_offset += dereference().length(); diff --git a/Userland/Libraries/LibJS/Bytecode/Block.h b/Userland/Libraries/LibJS/Bytecode/Block.h index 4e81d2b1d3..09dca9461a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Block.h +++ b/Userland/Libraries/LibJS/Bytecode/Block.h @@ -8,6 +8,7 @@ #include #include +#include #include namespace JS::Bytecode { @@ -42,25 +43,20 @@ public: static NonnullOwnPtr create(); ~Block(); - void seal(); - void dump() const; - ReadonlyBytes instruction_stream() const { return ReadonlyBytes { m_buffer, m_buffer_size }; } + ReadonlyBytes instruction_stream() const { return m_buffer.span(); } size_t register_count() const { return m_register_count; } void set_register_count(Badge, size_t count) { m_register_count = count; } - void* next_slot() { return m_buffer + m_buffer_size; } - void grow(size_t additional_size); + Vector& buffer() { return m_buffer; } private: - Block(); + Block() = default; size_t m_register_count { 0 }; - u8* m_buffer { nullptr }; - size_t m_buffer_capacity { 0 }; - size_t m_buffer_size { 0 }; + Vector m_buffer; }; } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 2d2ad73520..822da0ebfa 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -10,7 +10,6 @@ #include #include #include -#include namespace JS::Bytecode { @@ -28,20 +27,9 @@ OwnPtr Generator::generate(ASTNode const& node) Generator generator; node.generate_bytecode(generator); generator.m_block->set_register_count({}, generator.m_next_register); - generator.m_block->seal(); return move(generator.m_block); } -void Generator::grow(size_t additional_size) -{ - m_block->grow(additional_size); -} - -void* Generator::next_slot() -{ - return m_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 88bac76ebe..110ad25ac5 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -7,8 +7,8 @@ #pragma once #include +#include #include -#include #include namespace JS::Bytecode { @@ -20,21 +20,15 @@ public: Register allocate_register(); template - OpType& emit(Args&&... args) + InstructionHandle emit(Args&&... args) { - void* slot = next_slot(); - grow(sizeof(OpType)); - new (slot) OpType(forward(args)...); - return *static_cast(slot); + return make_instruction(0, forward(args)...); } template - OpType& emit_with_extra_register_slots(size_t extra_register_slots, Args&&... args) + InstructionHandle emit_with_extra_register_slots(size_t extra_register_slots, Args&&... args) { - void* slot = next_slot(); - grow(sizeof(OpType) + extra_register_slots * sizeof(Register)); - new (slot) OpType(forward(args)...); - return *static_cast(slot); + return make_instruction(extra_register_slots, forward(args)...); } Label make_label() const; @@ -48,8 +42,15 @@ private: Generator(); ~Generator(); - void grow(size_t); - void* next_slot(); + template + InstructionHandle make_instruction(size_t extra_register_slots, Args&&... args) + { + auto& buffer = m_block->buffer(); + auto offset = buffer.size(); + buffer.resize(buffer.size() + sizeof(OpType) + extra_register_slots * sizeof(Register)); + new (buffer.data() + offset) OpType(forward(args)...); + return InstructionHandle(offset, m_block); + } OwnPtr m_block; u32 m_next_register { 1 }; diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.cpp b/Userland/Libraries/LibJS/Bytecode/Instruction.cpp index 899229607d..7c85efec48 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index 1b7286eea8..b38ed0b804 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #define ENUMERATE_BYTECODE_OPS(O) \ @@ -83,4 +84,45 @@ private: Type m_type {}; }; +template +class InstructionHandle { +public: + InstructionHandle() = default; + + InstructionHandle(size_t offset, Block* block) + : m_offset(offset) + , m_block(block) + { + } + + OpType* operator->() const + { + VERIFY(m_block); + return reinterpret_cast(m_block->buffer().data() + m_offset); + } + + OpType& operator*() const + { + VERIFY(m_block); + return *reinterpret_cast(m_block->buffer().data() + m_offset); + } + + template + InstructionHandle& operator=(InstructionHandle const& other) requires(IsBaseOf) + { + m_offset = other.offset(); + m_block = other.block(); + return *this; + } + + size_t offset() const { return m_offset; } + Block* block() const { return m_block; } + +private: + friend class Block; + + size_t m_offset { 0 }; + Block* m_block { nullptr }; +}; + } diff --git a/Userland/Libraries/LibJS/Forward.h b/Userland/Libraries/LibJS/Forward.h index 0a2665cc42..a4fd02fb08 100644 --- a/Userland/Libraries/LibJS/Forward.h +++ b/Userland/Libraries/LibJS/Forward.h @@ -166,6 +166,8 @@ namespace Bytecode { class Block; class Generator; class Instruction; +template +class InstructionHandle; class Interpreter; class Register; }