mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 02:27:35 +00:00
Revert "LibJS: Add bytecode instruction handles"
This reverts commit a01bd35c67
.
This broke simple programs like:
function sum(a, b) { return a + b; }
console.log(sum(1, 2));
This commit is contained in:
parent
a01bd35c67
commit
b8a5ea1f8d
8 changed files with 79 additions and 81 deletions
|
@ -119,16 +119,16 @@ void LogicalExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||||
{
|
{
|
||||||
m_lhs->generate_bytecode(generator);
|
m_lhs->generate_bytecode(generator);
|
||||||
|
|
||||||
Bytecode::InstructionHandle<Bytecode::Op::Jump> test_instr;
|
Bytecode::Op::Jump* test_instr;
|
||||||
switch (m_op) {
|
switch (m_op) {
|
||||||
case LogicalOp::And:
|
case LogicalOp::And:
|
||||||
test_instr = generator.emit<Bytecode::Op::JumpIfFalse>();
|
test_instr = &generator.emit<Bytecode::Op::JumpIfFalse>();
|
||||||
break;
|
break;
|
||||||
case LogicalOp::Or:
|
case LogicalOp::Or:
|
||||||
test_instr = generator.emit<Bytecode::Op::JumpIfTrue>();
|
test_instr = &generator.emit<Bytecode::Op::JumpIfTrue>();
|
||||||
break;
|
break;
|
||||||
case LogicalOp::NullishCoalescing:
|
case LogicalOp::NullishCoalescing:
|
||||||
test_instr = generator.emit<Bytecode::Op::JumpIfNotNullish>();
|
test_instr = &generator.emit<Bytecode::Op::JumpIfNotNullish>();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
|
@ -285,10 +285,10 @@ void WhileStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||||
auto result_reg = generator.allocate_register();
|
auto result_reg = generator.allocate_register();
|
||||||
generator.emit<Bytecode::Op::Store>(result_reg);
|
generator.emit<Bytecode::Op::Store>(result_reg);
|
||||||
m_test->generate_bytecode(generator);
|
m_test->generate_bytecode(generator);
|
||||||
auto test_jump = generator.emit<Bytecode::Op::JumpIfFalse>();
|
auto& test_jump = generator.emit<Bytecode::Op::JumpIfFalse>();
|
||||||
m_body->generate_bytecode(generator);
|
m_body->generate_bytecode(generator);
|
||||||
generator.emit<Bytecode::Op::Jump>(test_label);
|
generator.emit<Bytecode::Op::Jump>(test_label);
|
||||||
test_jump->set_target(generator.make_label());
|
test_jump.set_target(generator.make_label());
|
||||||
generator.end_continuable_scope();
|
generator.end_continuable_scope();
|
||||||
generator.emit<Bytecode::Op::Load>(result_reg);
|
generator.emit<Bytecode::Op::Load>(result_reg);
|
||||||
}
|
}
|
||||||
|
@ -309,7 +309,7 @@ void DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||||
|
|
||||||
void ForStatement::generate_bytecode(Bytecode::Generator& generator) const
|
void ForStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||||
{
|
{
|
||||||
Bytecode::InstructionHandle<Bytecode::Op::Jump> test_jump;
|
Bytecode::Op::Jump* test_jump { nullptr };
|
||||||
|
|
||||||
if (m_init)
|
if (m_init)
|
||||||
m_init->generate_bytecode(generator);
|
m_init->generate_bytecode(generator);
|
||||||
|
@ -321,7 +321,7 @@ void ForStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||||
generator.emit<Bytecode::Op::Store>(result_reg);
|
generator.emit<Bytecode::Op::Store>(result_reg);
|
||||||
if (m_test) {
|
if (m_test) {
|
||||||
m_test->generate_bytecode(generator);
|
m_test->generate_bytecode(generator);
|
||||||
test_jump = generator.emit<Bytecode::Op::JumpIfFalse>();
|
test_jump = &generator.emit<Bytecode::Op::JumpIfFalse>();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_body->generate_bytecode(generator);
|
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
|
void IfStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||||
{
|
{
|
||||||
m_predicate->generate_bytecode(generator);
|
m_predicate->generate_bytecode(generator);
|
||||||
auto else_jump = generator.emit<Bytecode::Op::JumpIfFalse>();
|
auto& else_jump = generator.emit<Bytecode::Op::JumpIfFalse>();
|
||||||
|
|
||||||
m_consequent->generate_bytecode(generator);
|
m_consequent->generate_bytecode(generator);
|
||||||
if (m_alternate) {
|
if (m_alternate) {
|
||||||
auto if_jump = generator.emit<Bytecode::Op::Jump>();
|
auto& if_jump = generator.emit<Bytecode::Op::Jump>();
|
||||||
else_jump->set_target(generator.make_label());
|
else_jump.set_target(generator.make_label());
|
||||||
m_alternate->generate_bytecode(generator);
|
m_alternate->generate_bytecode(generator);
|
||||||
if_jump->set_target(generator.make_label());
|
if_jump.set_target(generator.make_label());
|
||||||
} else {
|
} 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
|
void ConditionalExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||||
{
|
{
|
||||||
m_test->generate_bytecode(generator);
|
m_test->generate_bytecode(generator);
|
||||||
auto alternate_jump = generator.emit<Bytecode::Op::JumpIfFalse>();
|
auto& alternate_jump = generator.emit<Bytecode::Op::JumpIfFalse>();
|
||||||
|
|
||||||
m_consequent->generate_bytecode(generator);
|
m_consequent->generate_bytecode(generator);
|
||||||
auto end_jump = generator.emit<Bytecode::Op::Jump>();
|
auto& end_jump = generator.emit<Bytecode::Op::Jump>();
|
||||||
|
|
||||||
alternate_jump->set_target(generator.make_label());
|
alternate_jump.set_target(generator.make_label());
|
||||||
m_alternate->generate_bytecode(generator);
|
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
|
void SequenceExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||||
|
|
|
@ -4,8 +4,10 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/String.h>
|
||||||
#include <LibJS/Bytecode/Block.h>
|
#include <LibJS/Bytecode/Block.h>
|
||||||
#include <LibJS/Bytecode/Op.h>
|
#include <LibJS/Bytecode/Op.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
namespace JS::Bytecode {
|
namespace JS::Bytecode {
|
||||||
|
|
||||||
|
@ -14,6 +16,16 @@ NonnullOwnPtr<Block> Block::create()
|
||||||
return adopt_own(*new Block);
|
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()
|
Block::~Block()
|
||||||
{
|
{
|
||||||
Bytecode::InstructionStreamIterator it(instruction_stream());
|
Bytecode::InstructionStreamIterator it(instruction_stream());
|
||||||
|
@ -22,6 +34,16 @@ Block::~Block()
|
||||||
++it;
|
++it;
|
||||||
Instruction::destroy(const_cast<Instruction&>(to_destroy));
|
Instruction::destroy(const_cast<Instruction&>(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
|
void Block::dump() const
|
||||||
|
@ -33,6 +55,12 @@ 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++()
|
void InstructionStreamIterator::operator++()
|
||||||
{
|
{
|
||||||
m_offset += dereference().length();
|
m_offset += dereference().length();
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include <AK/Badge.h>
|
#include <AK/Badge.h>
|
||||||
#include <AK/NonnullOwnPtrVector.h>
|
#include <AK/NonnullOwnPtrVector.h>
|
||||||
#include <LibJS/Bytecode/Register.h>
|
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
|
|
||||||
namespace JS::Bytecode {
|
namespace JS::Bytecode {
|
||||||
|
@ -43,20 +42,25 @@ public:
|
||||||
static NonnullOwnPtr<Block> create();
|
static NonnullOwnPtr<Block> create();
|
||||||
~Block();
|
~Block();
|
||||||
|
|
||||||
|
void seal();
|
||||||
|
|
||||||
void dump() const;
|
void dump() const;
|
||||||
ReadonlyBytes instruction_stream() const { return m_buffer.span(); }
|
ReadonlyBytes instruction_stream() const { return ReadonlyBytes { m_buffer, m_buffer_size }; }
|
||||||
|
|
||||||
size_t register_count() const { return m_register_count; }
|
size_t register_count() const { return m_register_count; }
|
||||||
|
|
||||||
void set_register_count(Badge<Bytecode::Generator>, size_t count) { m_register_count = count; }
|
void set_register_count(Badge<Bytecode::Generator>, size_t count) { m_register_count = count; }
|
||||||
|
|
||||||
Vector<u8>& buffer() { return m_buffer; }
|
void* next_slot() { return m_buffer + m_buffer_size; }
|
||||||
|
void grow(size_t additional_size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Block() = default;
|
Block();
|
||||||
|
|
||||||
size_t m_register_count { 0 };
|
size_t m_register_count { 0 };
|
||||||
Vector<u8> m_buffer;
|
u8* m_buffer { nullptr };
|
||||||
|
size_t m_buffer_capacity { 0 };
|
||||||
|
size_t m_buffer_size { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <LibJS/Bytecode/Generator.h>
|
#include <LibJS/Bytecode/Generator.h>
|
||||||
#include <LibJS/Bytecode/Instruction.h>
|
#include <LibJS/Bytecode/Instruction.h>
|
||||||
#include <LibJS/Bytecode/Register.h>
|
#include <LibJS/Bytecode/Register.h>
|
||||||
|
#include <LibJS/Forward.h>
|
||||||
|
|
||||||
namespace JS::Bytecode {
|
namespace JS::Bytecode {
|
||||||
|
|
||||||
|
@ -27,9 +28,20 @@ OwnPtr<Block> Generator::generate(ASTNode const& node)
|
||||||
Generator generator;
|
Generator generator;
|
||||||
node.generate_bytecode(generator);
|
node.generate_bytecode(generator);
|
||||||
generator.m_block->set_register_count({}, generator.m_next_register);
|
generator.m_block->set_register_count({}, generator.m_next_register);
|
||||||
|
generator.m_block->seal();
|
||||||
return move(generator.m_block);
|
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()
|
Register Generator::allocate_register()
|
||||||
{
|
{
|
||||||
VERIFY(m_next_register != NumericLimits<u32>::max());
|
VERIFY(m_next_register != NumericLimits<u32>::max());
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/OwnPtr.h>
|
#include <AK/OwnPtr.h>
|
||||||
#include <LibJS/Bytecode/Block.h>
|
|
||||||
#include <LibJS/Bytecode/Label.h>
|
#include <LibJS/Bytecode/Label.h>
|
||||||
|
#include <LibJS/Bytecode/Register.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
|
|
||||||
namespace JS::Bytecode {
|
namespace JS::Bytecode {
|
||||||
|
@ -20,15 +20,21 @@ public:
|
||||||
Register allocate_register();
|
Register allocate_register();
|
||||||
|
|
||||||
template<typename OpType, typename... Args>
|
template<typename OpType, typename... Args>
|
||||||
InstructionHandle<OpType> emit(Args&&... args)
|
OpType& emit(Args&&... args)
|
||||||
{
|
{
|
||||||
return make_instruction<OpType>(0, forward<Args>(args)...);
|
void* slot = next_slot();
|
||||||
|
grow(sizeof(OpType));
|
||||||
|
new (slot) OpType(forward<Args>(args)...);
|
||||||
|
return *static_cast<OpType*>(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename OpType, typename... Args>
|
template<typename OpType, typename... Args>
|
||||||
InstructionHandle<OpType> emit_with_extra_register_slots(size_t extra_register_slots, Args&&... args)
|
OpType& emit_with_extra_register_slots(size_t extra_register_slots, Args&&... args)
|
||||||
{
|
{
|
||||||
return make_instruction<OpType>(extra_register_slots, forward<Args>(args)...);
|
void* slot = next_slot();
|
||||||
|
grow(sizeof(OpType) + extra_register_slots * sizeof(Register));
|
||||||
|
new (slot) OpType(forward<Args>(args)...);
|
||||||
|
return *static_cast<OpType*>(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
Label make_label() const;
|
Label make_label() const;
|
||||||
|
@ -42,15 +48,8 @@ private:
|
||||||
Generator();
|
Generator();
|
||||||
~Generator();
|
~Generator();
|
||||||
|
|
||||||
template<typename OpType, typename... Args>
|
void grow(size_t);
|
||||||
InstructionHandle<OpType> make_instruction(size_t extra_register_slots, Args&&... args)
|
void* next_slot();
|
||||||
{
|
|
||||||
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>(args)...);
|
|
||||||
return InstructionHandle<OpType>(offset, m_block);
|
|
||||||
}
|
|
||||||
|
|
||||||
OwnPtr<Block> m_block;
|
OwnPtr<Block> m_block;
|
||||||
u32 m_next_register { 1 };
|
u32 m_next_register { 1 };
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <LibJS/Bytecode/Block.h>
|
|
||||||
#include <LibJS/Bytecode/Instruction.h>
|
#include <LibJS/Bytecode/Instruction.h>
|
||||||
#include <LibJS/Bytecode/Op.h>
|
#include <LibJS/Bytecode/Op.h>
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
#include <LibJS/Bytecode/Block.h>
|
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
|
|
||||||
#define ENUMERATE_BYTECODE_OPS(O) \
|
#define ENUMERATE_BYTECODE_OPS(O) \
|
||||||
|
@ -84,45 +83,4 @@ private:
|
||||||
Type m_type {};
|
Type m_type {};
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename OpType>
|
|
||||||
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<OpType*>(m_block->buffer().data() + m_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
OpType& operator*() const
|
|
||||||
{
|
|
||||||
VERIFY(m_block);
|
|
||||||
return *reinterpret_cast<OpType*>(m_block->buffer().data() + m_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
InstructionHandle<OpType>& operator=(InstructionHandle<T> const& other) requires(IsBaseOf<OpType, T>)
|
|
||||||
{
|
|
||||||
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 };
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,8 +166,6 @@ namespace Bytecode {
|
||||||
class Block;
|
class Block;
|
||||||
class Generator;
|
class Generator;
|
||||||
class Instruction;
|
class Instruction;
|
||||||
template<typename OpType>
|
|
||||||
class InstructionHandle;
|
|
||||||
class Interpreter;
|
class Interpreter;
|
||||||
class Register;
|
class Register;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue