mirror of
https://github.com/RGBCube/serenity
synced 2025-05-22 16:55:09 +00:00
LibJS: Introduce an accumulator register to Bytecode::Interpreter
This commit introduces the concept of an accumulator register to LibJS's bytecode interpreter. The accumulator register is always register 0, and most simple instructions use it for reading and writing. Not only does this slim down the AST, but it also simplifies a lot of the code. For example, the generate_bytecode methods no longer need to return an Optional<Register>, as any opcode which has a "return" value will always put it into the accumulator. This also renames the old Op::Load to Op::LoadImmediate, and uses Op::Load to load from a register into the accumulator. There is also an Op::Store to put the value in the accumulator into another register.
This commit is contained in:
parent
6c256bb400
commit
9bed2e4f4a
8 changed files with 377 additions and 432 deletions
|
@ -37,7 +37,7 @@ class ASTNode : public RefCounted<ASTNode> {
|
|||
public:
|
||||
virtual ~ASTNode() { }
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const = 0;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const;
|
||||
virtual void dump(int indent) const;
|
||||
|
||||
const SourceRange& source_range() const { return m_source_range; }
|
||||
|
@ -76,7 +76,7 @@ public:
|
|||
{
|
||||
}
|
||||
Value execute(Interpreter&, GlobalObject&) const override { return {}; }
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
};
|
||||
|
||||
class ErrorStatement final : public Statement {
|
||||
|
@ -98,7 +98,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
const Expression& expression() const { return m_expression; };
|
||||
|
||||
|
@ -123,7 +123,7 @@ public:
|
|||
const NonnullRefPtrVector<Statement>& children() const { return m_children; }
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
void add_variables(NonnullRefPtrVector<VariableDeclaration>);
|
||||
void add_functions(NonnullRefPtrVector<FunctionDeclaration>);
|
||||
|
@ -273,7 +273,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
};
|
||||
|
||||
class FunctionExpression final
|
||||
|
@ -330,7 +330,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
RefPtr<Expression> m_argument;
|
||||
|
@ -352,7 +352,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
NonnullRefPtr<Expression> m_predicate;
|
||||
|
@ -374,7 +374,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
NonnullRefPtr<Expression> m_test;
|
||||
|
@ -395,7 +395,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
NonnullRefPtr<Expression> m_test;
|
||||
|
@ -440,7 +440,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
RefPtr<ASTNode> m_init;
|
||||
|
@ -532,7 +532,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
BinaryOp m_op;
|
||||
|
@ -558,7 +558,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
LogicalOp m_op;
|
||||
|
@ -587,7 +587,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
UnaryOp m_op;
|
||||
|
@ -605,7 +605,7 @@ public:
|
|||
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
NonnullRefPtrVector<Expression> m_expressions;
|
||||
|
@ -629,7 +629,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
bool m_value { false };
|
||||
|
@ -645,7 +645,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
Value m_value;
|
||||
|
@ -661,7 +661,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
String m_value;
|
||||
|
@ -678,7 +678,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
StringView value() const { return m_value; }
|
||||
bool is_use_strict_directive() const { return m_is_use_strict_directive; };
|
||||
|
@ -697,7 +697,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
};
|
||||
|
||||
class RegExpLiteral final : public Literal {
|
||||
|
@ -733,7 +733,7 @@ public:
|
|||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Reference to_reference(Interpreter&, GlobalObject&) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
FlyString m_string;
|
||||
|
@ -860,7 +860,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
struct ThisAndCallee {
|
||||
|
@ -912,7 +912,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
AssignmentOp m_op;
|
||||
|
@ -1052,7 +1052,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
NonnullRefPtrVector<ObjectProperty> m_properties;
|
||||
|
@ -1092,7 +1092,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
const NonnullRefPtrVector<Expression>& expressions() const { return m_expressions; }
|
||||
const NonnullRefPtrVector<Expression>& raw_strings() const { return m_raw_strings; }
|
||||
|
@ -1132,7 +1132,7 @@ public:
|
|||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Reference to_reference(Interpreter&, GlobalObject&) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
bool is_computed() const { return m_computed; }
|
||||
const Expression& object() const { return *m_object; }
|
||||
|
@ -1180,7 +1180,7 @@ public:
|
|||
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
NonnullRefPtr<Expression> m_test;
|
||||
|
@ -1310,7 +1310,7 @@ public:
|
|||
}
|
||||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
const FlyString& target_label() const { return m_target_label; }
|
||||
|
||||
|
@ -1326,7 +1326,7 @@ public:
|
|||
}
|
||||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
virtual void generate_bytecode(Bytecode::Generator&) const override;
|
||||
};
|
||||
|
||||
template<typename C>
|
||||
|
|
|
@ -13,489 +13,422 @@
|
|||
|
||||
namespace JS {
|
||||
|
||||
Optional<Bytecode::Register> ASTNode::generate_bytecode(Bytecode::Generator&) const
|
||||
void ASTNode::generate_bytecode(Bytecode::Generator&) const
|
||||
{
|
||||
dbgln("Missing generate_bytecode()");
|
||||
TODO();
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> ScopeNode::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void ScopeNode::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
generator.emit<Bytecode::Op::EnterScope>(*this);
|
||||
Optional<Bytecode::Register> last_value_reg;
|
||||
for (auto& child : children()) {
|
||||
last_value_reg = child.generate_bytecode(generator);
|
||||
}
|
||||
return last_value_reg;
|
||||
for (auto& child : children())
|
||||
child.generate_bytecode(generator);
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> EmptyStatement::generate_bytecode(Bytecode::Generator&) const
|
||||
void EmptyStatement::generate_bytecode(Bytecode::Generator&) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> ExpressionStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void ExpressionStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
return m_expression->generate_bytecode(generator);
|
||||
m_expression->generate_bytecode(generator);
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> BinaryExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void BinaryExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto lhs_reg = m_lhs->generate_bytecode(generator);
|
||||
auto rhs_reg = m_rhs->generate_bytecode(generator);
|
||||
m_lhs->generate_bytecode(generator);
|
||||
auto lhs_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Store>(lhs_reg);
|
||||
|
||||
VERIFY(lhs_reg.has_value());
|
||||
VERIFY(rhs_reg.has_value());
|
||||
|
||||
auto dst_reg = generator.allocate_register();
|
||||
m_rhs->generate_bytecode(generator);
|
||||
|
||||
switch (m_op) {
|
||||
case BinaryOp::Addition:
|
||||
generator.emit<Bytecode::Op::Add>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::Add>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::Subtraction:
|
||||
generator.emit<Bytecode::Op::Sub>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::Sub>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::Multiplication:
|
||||
generator.emit<Bytecode::Op::Mul>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::Mul>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::Division:
|
||||
generator.emit<Bytecode::Op::Div>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::Div>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::Modulo:
|
||||
generator.emit<Bytecode::Op::Mod>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::Mod>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::Exponentiation:
|
||||
generator.emit<Bytecode::Op::Exp>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::Exp>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::GreaterThan:
|
||||
generator.emit<Bytecode::Op::GreaterThan>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::GreaterThan>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::GreaterThanEquals:
|
||||
generator.emit<Bytecode::Op::GreaterThanEquals>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::GreaterThanEquals>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::LessThan:
|
||||
generator.emit<Bytecode::Op::LessThan>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::LessThan>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::LessThanEquals:
|
||||
generator.emit<Bytecode::Op::LessThanEquals>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::LessThanEquals>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::AbstractInequals:
|
||||
generator.emit<Bytecode::Op::AbstractInequals>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::AbstractInequals>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::AbstractEquals:
|
||||
generator.emit<Bytecode::Op::AbstractEquals>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::AbstractEquals>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::TypedInequals:
|
||||
generator.emit<Bytecode::Op::TypedInequals>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::TypedInequals>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::TypedEquals:
|
||||
generator.emit<Bytecode::Op::TypedEquals>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::TypedEquals>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::BitwiseAnd:
|
||||
generator.emit<Bytecode::Op::BitwiseAnd>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::BitwiseAnd>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::BitwiseOr:
|
||||
generator.emit<Bytecode::Op::BitwiseOr>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::BitwiseOr>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::BitwiseXor:
|
||||
generator.emit<Bytecode::Op::BitwiseXor>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::BitwiseXor>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::LeftShift:
|
||||
generator.emit<Bytecode::Op::LeftShift>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::LeftShift>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::RightShift:
|
||||
generator.emit<Bytecode::Op::RightShift>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::RightShift>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::UnsignedRightShift:
|
||||
generator.emit<Bytecode::Op::UnsignedRightShift>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::UnsignedRightShift>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::In:
|
||||
generator.emit<Bytecode::Op::In>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::In>(lhs_reg);
|
||||
break;
|
||||
case BinaryOp::InstanceOf:
|
||||
generator.emit<Bytecode::Op::InstanceOf>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::InstanceOf>(lhs_reg);
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> LogicalExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void LogicalExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto result_reg = generator.allocate_register();
|
||||
auto lhs_reg = m_lhs->generate_bytecode(generator);
|
||||
m_lhs->generate_bytecode(generator);
|
||||
|
||||
Bytecode::Op::Jump* test_instr;
|
||||
switch (m_op) {
|
||||
case LogicalOp::And:
|
||||
test_instr = &generator.emit<Bytecode::Op::JumpIfTrue>(*lhs_reg);
|
||||
test_instr = &generator.emit<Bytecode::Op::JumpIfFalse>();
|
||||
break;
|
||||
case LogicalOp::Or:
|
||||
test_instr = &generator.emit<Bytecode::Op::JumpIfFalse>(*lhs_reg);
|
||||
test_instr = &generator.emit<Bytecode::Op::JumpIfTrue>();
|
||||
break;
|
||||
case LogicalOp::NullishCoalescing:
|
||||
test_instr = &generator.emit<Bytecode::Op::JumpIfNullish>(*lhs_reg);
|
||||
test_instr = &generator.emit<Bytecode::Op::JumpIfNotNullish>();
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
generator.emit<Bytecode::Op::LoadRegister>(result_reg, *lhs_reg);
|
||||
auto& end_jump = generator.emit<Bytecode::Op::Jump>();
|
||||
|
||||
auto rhs_label = generator.make_label();
|
||||
test_instr->set_target(rhs_label);
|
||||
|
||||
auto rhs_reg = m_rhs->generate_bytecode(generator);
|
||||
generator.emit<Bytecode::Op::LoadRegister>(result_reg, *rhs_reg);
|
||||
|
||||
end_jump.set_target(generator.make_label());
|
||||
|
||||
return result_reg;
|
||||
m_rhs->generate_bytecode(generator);
|
||||
test_instr->set_target(generator.make_label());
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> UnaryExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void UnaryExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto lhs_reg = m_lhs->generate_bytecode(generator);
|
||||
|
||||
VERIFY(lhs_reg.has_value());
|
||||
|
||||
auto dst_reg = generator.allocate_register();
|
||||
m_lhs->generate_bytecode(generator);
|
||||
|
||||
switch (m_op) {
|
||||
case UnaryOp::BitwiseNot:
|
||||
generator.emit<Bytecode::Op::BitwiseNot>(dst_reg, *lhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::BitwiseNot>();
|
||||
break;
|
||||
case UnaryOp::Not:
|
||||
generator.emit<Bytecode::Op::Not>(dst_reg, *lhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::Not>();
|
||||
break;
|
||||
case UnaryOp::Plus:
|
||||
generator.emit<Bytecode::Op::UnaryPlus>(dst_reg, *lhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::UnaryPlus>();
|
||||
break;
|
||||
case UnaryOp::Minus:
|
||||
generator.emit<Bytecode::Op::UnaryMinus>(dst_reg, *lhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::UnaryMinus>();
|
||||
break;
|
||||
case UnaryOp::Typeof:
|
||||
generator.emit<Bytecode::Op::Typeof>(dst_reg, *lhs_reg);
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::Typeof>();
|
||||
break;
|
||||
case UnaryOp::Void:
|
||||
generator.emit<Bytecode::Op::Load>(dst_reg, js_undefined());
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
|
||||
break;
|
||||
default:
|
||||
TODO();
|
||||
}
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> NumericLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void NumericLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto dst = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Load>(dst, m_value);
|
||||
return dst;
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(m_value);
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> BooleanLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void BooleanLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto dst = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Load>(dst, Value(m_value));
|
||||
return dst;
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(Value(m_value));
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> NullLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void NullLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto dst = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Load>(dst, js_null());
|
||||
return dst;
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(js_null());
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> BigIntLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void BigIntLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto dst = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::NewBigInt>(dst, Crypto::SignedBigInteger::from_base10(m_value.substring(0, m_value.length() - 1)));
|
||||
return dst;
|
||||
generator.emit<Bytecode::Op::NewBigInt>(Crypto::SignedBigInteger::from_base10(m_value.substring(0, m_value.length() - 1)));
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> StringLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void StringLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto dst = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::NewString>(dst, m_value);
|
||||
return dst;
|
||||
generator.emit<Bytecode::Op::NewString>(m_value);
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> Identifier::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void Identifier::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::GetVariable>(reg, m_string);
|
||||
return reg;
|
||||
generator.emit<Bytecode::Op::GetVariable>(m_string);
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
if (is<Identifier>(*m_lhs)) {
|
||||
auto& identifier = static_cast<Identifier const&>(*m_lhs);
|
||||
auto rhs_reg = m_rhs->generate_bytecode(generator);
|
||||
VERIFY(rhs_reg.has_value());
|
||||
|
||||
if (m_op == AssignmentOp::Assignment) {
|
||||
generator.emit<Bytecode::Op::SetVariable>(identifier.string(), *rhs_reg);
|
||||
return rhs_reg;
|
||||
m_rhs->generate_bytecode(generator);
|
||||
generator.emit<Bytecode::Op::SetVariable>(identifier.string());
|
||||
return;
|
||||
}
|
||||
|
||||
auto lhs_reg = m_lhs->generate_bytecode(generator);
|
||||
auto dst_reg = generator.allocate_register();
|
||||
m_lhs->generate_bytecode(generator);
|
||||
auto lhs_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Store>(lhs_reg);
|
||||
m_rhs->generate_bytecode(generator);
|
||||
|
||||
switch (m_op) {
|
||||
case AssignmentOp::AdditionAssignment:
|
||||
generator.emit<Bytecode::Op::Add>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
generator.emit<Bytecode::Op::Add>(lhs_reg);
|
||||
break;
|
||||
case AssignmentOp::SubtractionAssignment:
|
||||
generator.emit<Bytecode::Op::Sub>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
generator.emit<Bytecode::Op::Sub>(lhs_reg);
|
||||
break;
|
||||
case AssignmentOp::MultiplicationAssignment:
|
||||
generator.emit<Bytecode::Op::Mul>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
generator.emit<Bytecode::Op::Mul>(lhs_reg);
|
||||
break;
|
||||
case AssignmentOp::DivisionAssignment:
|
||||
generator.emit<Bytecode::Op::Div>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
generator.emit<Bytecode::Op::Div>(lhs_reg);
|
||||
break;
|
||||
case AssignmentOp::ModuloAssignment:
|
||||
generator.emit<Bytecode::Op::Mod>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
generator.emit<Bytecode::Op::Mod>(lhs_reg);
|
||||
break;
|
||||
case AssignmentOp::ExponentiationAssignment:
|
||||
generator.emit<Bytecode::Op::Exp>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
generator.emit<Bytecode::Op::Exp>(lhs_reg);
|
||||
break;
|
||||
case AssignmentOp::BitwiseAndAssignment:
|
||||
generator.emit<Bytecode::Op::BitwiseAnd>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
generator.emit<Bytecode::Op::BitwiseAnd>(lhs_reg);
|
||||
break;
|
||||
case AssignmentOp::BitwiseOrAssignment:
|
||||
generator.emit<Bytecode::Op::BitwiseOr>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
generator.emit<Bytecode::Op::BitwiseOr>(lhs_reg);
|
||||
break;
|
||||
case AssignmentOp::BitwiseXorAssignment:
|
||||
generator.emit<Bytecode::Op::BitwiseXor>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
generator.emit<Bytecode::Op::BitwiseXor>(lhs_reg);
|
||||
break;
|
||||
case AssignmentOp::LeftShiftAssignment:
|
||||
generator.emit<Bytecode::Op::LeftShift>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
generator.emit<Bytecode::Op::LeftShift>(lhs_reg);
|
||||
break;
|
||||
case AssignmentOp::RightShiftAssignment:
|
||||
generator.emit<Bytecode::Op::RightShift>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
generator.emit<Bytecode::Op::RightShift>(lhs_reg);
|
||||
break;
|
||||
case AssignmentOp::UnsignedRightShiftAssignment:
|
||||
generator.emit<Bytecode::Op::UnsignedRightShift>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
generator.emit<Bytecode::Op::UnsignedRightShift>(lhs_reg);
|
||||
break;
|
||||
default:
|
||||
TODO();
|
||||
}
|
||||
|
||||
generator.emit<Bytecode::Op::SetVariable>(identifier.string(), dst_reg);
|
||||
generator.emit<Bytecode::Op::SetVariable>(identifier.string());
|
||||
|
||||
return dst_reg;
|
||||
return;
|
||||
}
|
||||
|
||||
if (is<MemberExpression>(*m_lhs)) {
|
||||
auto& expression = static_cast<MemberExpression const&>(*m_lhs);
|
||||
auto object_reg = expression.object().generate_bytecode(generator);
|
||||
expression.object().generate_bytecode(generator);
|
||||
auto object_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Store>(object_reg);
|
||||
|
||||
if (expression.is_computed()) {
|
||||
TODO();
|
||||
} else {
|
||||
VERIFY(is<Identifier>(expression.property()));
|
||||
auto rhs_reg = m_rhs->generate_bytecode(generator);
|
||||
generator.emit<Bytecode::Op::PutById>(*object_reg, static_cast<Identifier const&>(expression.property()).string(), *rhs_reg);
|
||||
return rhs_reg;
|
||||
m_rhs->generate_bytecode(generator);
|
||||
generator.emit<Bytecode::Op::PutById>(object_reg, static_cast<Identifier const&>(expression.property()).string());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TODO();
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> WhileStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void WhileStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
generator.begin_continuable_scope();
|
||||
auto test_label = generator.make_label();
|
||||
auto test_result_reg = m_test->generate_bytecode(generator);
|
||||
VERIFY(test_result_reg.has_value());
|
||||
auto& test_jump = generator.emit<Bytecode::Op::JumpIfFalse>(*test_result_reg);
|
||||
auto body_result_reg = m_body->generate_bytecode(generator);
|
||||
m_test->generate_bytecode(generator);
|
||||
auto& test_jump = generator.emit<Bytecode::Op::JumpIfFalse>();
|
||||
m_body->generate_bytecode(generator);
|
||||
generator.emit<Bytecode::Op::Jump>(test_label);
|
||||
test_jump.set_target(generator.make_label());
|
||||
generator.end_continuable_scope();
|
||||
return body_result_reg;
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
generator.begin_continuable_scope();
|
||||
auto head_label = generator.make_label();
|
||||
auto body_result_reg = m_body->generate_bytecode(generator);
|
||||
m_body->generate_bytecode(generator);
|
||||
generator.end_continuable_scope();
|
||||
auto test_result_reg = m_test->generate_bytecode(generator);
|
||||
VERIFY(test_result_reg.has_value());
|
||||
generator.emit<Bytecode::Op::JumpIfTrue>(*test_result_reg, head_label);
|
||||
return body_result_reg;
|
||||
m_test->generate_bytecode(generator);
|
||||
generator.emit<Bytecode::Op::JumpIfTrue>(head_label);
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> ForStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void ForStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Bytecode::Op::Jump* test_jump { nullptr };
|
||||
|
||||
if (m_init) {
|
||||
[[maybe_unused]] auto init_result_reg = m_init->generate_bytecode(generator);
|
||||
}
|
||||
if (m_init)
|
||||
m_init->generate_bytecode(generator);
|
||||
|
||||
generator.begin_continuable_scope();
|
||||
auto jump_label = generator.make_label();
|
||||
if (m_test) {
|
||||
auto test_result_reg = m_test->generate_bytecode(generator);
|
||||
VERIFY(test_result_reg.has_value());
|
||||
test_jump = &generator.emit<Bytecode::Op::JumpIfFalse>(*test_result_reg);
|
||||
}
|
||||
auto body_result_reg = m_body->generate_bytecode(generator);
|
||||
if (m_update) {
|
||||
[[maybe_unused]] auto update_result_reg = m_update->generate_bytecode(generator);
|
||||
m_test->generate_bytecode(generator);
|
||||
test_jump = &generator.emit<Bytecode::Op::JumpIfFalse>();
|
||||
}
|
||||
|
||||
m_body->generate_bytecode(generator);
|
||||
if (m_update)
|
||||
m_update->generate_bytecode(generator);
|
||||
generator.emit<Bytecode::Op::Jump>(jump_label);
|
||||
if (m_test)
|
||||
test_jump->set_target(generator.make_label());
|
||||
generator.end_continuable_scope();
|
||||
return body_result_reg;
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> ObjectExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void ObjectExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::NewObject>(reg);
|
||||
generator.emit<Bytecode::Op::NewObject>();
|
||||
|
||||
if (!m_properties.is_empty()) {
|
||||
if (!m_properties.is_empty())
|
||||
TODO();
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> MemberExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void MemberExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto object_reg = object().generate_bytecode(generator);
|
||||
object().generate_bytecode(generator);
|
||||
|
||||
if (is_computed()) {
|
||||
TODO();
|
||||
} else {
|
||||
VERIFY(is<Identifier>(property()));
|
||||
auto dst_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::GetById>(dst_reg, *object_reg, static_cast<Identifier const&>(property()).string());
|
||||
return dst_reg;
|
||||
generator.emit<Bytecode::Op::GetById>(static_cast<Identifier const&>(property()).string());
|
||||
}
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> FunctionDeclaration::generate_bytecode(Bytecode::Generator&) const
|
||||
void FunctionDeclaration::generate_bytecode(Bytecode::Generator&) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> CallExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void CallExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto callee_reg = m_callee->generate_bytecode(generator);
|
||||
m_callee->generate_bytecode(generator);
|
||||
auto callee_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Store>(callee_reg);
|
||||
|
||||
// FIXME: Load the correct 'this' value into 'this_reg'.
|
||||
auto this_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Load>(this_reg, js_undefined());
|
||||
generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
|
||||
generator.emit<Bytecode::Op::Store>(this_reg);
|
||||
|
||||
Vector<Bytecode::Register> argument_registers;
|
||||
for (auto& arg : m_arguments)
|
||||
argument_registers.append(*arg.value->generate_bytecode(generator));
|
||||
auto dst_reg = generator.allocate_register();
|
||||
generator.emit_with_extra_register_slots<Bytecode::Op::Call>(argument_registers.size(), dst_reg, *callee_reg, this_reg, argument_registers);
|
||||
return dst_reg;
|
||||
for (auto& arg : m_arguments) {
|
||||
arg.value->generate_bytecode(generator);
|
||||
auto arg_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Store>(arg_reg);
|
||||
argument_registers.append(arg_reg);
|
||||
}
|
||||
generator.emit_with_extra_register_slots<Bytecode::Op::Call>(argument_registers.size(), callee_reg, this_reg, argument_registers);
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> ReturnStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void ReturnStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Optional<Bytecode::Register> argument_reg;
|
||||
if (m_argument)
|
||||
argument_reg = m_argument->generate_bytecode(generator);
|
||||
|
||||
generator.emit<Bytecode::Op::Return>(argument_reg);
|
||||
return argument_reg;
|
||||
generator.emit<Bytecode::Op::Return>();
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> IfStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void IfStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto result_reg = generator.allocate_register();
|
||||
auto predicate_reg = m_predicate->generate_bytecode(generator);
|
||||
auto& else_jump = generator.emit<Bytecode::Op::JumpIfFalse>(*predicate_reg);
|
||||
m_predicate->generate_bytecode(generator);
|
||||
auto& else_jump = generator.emit<Bytecode::Op::JumpIfFalse>();
|
||||
|
||||
auto consequent_reg = m_consequent->generate_bytecode(generator);
|
||||
generator.emit<Bytecode::Op::LoadRegister>(result_reg, *consequent_reg);
|
||||
auto& end_jump = generator.emit<Bytecode::Op::Jump>();
|
||||
|
||||
else_jump.set_target(generator.make_label());
|
||||
m_consequent->generate_bytecode(generator);
|
||||
if (m_alternate) {
|
||||
auto alternative_reg = m_alternate->generate_bytecode(generator);
|
||||
generator.emit<Bytecode::Op::LoadRegister>(result_reg, *alternative_reg);
|
||||
auto& if_jump = generator.emit<Bytecode::Op::Jump>();
|
||||
else_jump.set_target(generator.make_label());
|
||||
m_alternate->generate_bytecode(generator);
|
||||
if_jump.set_target(generator.make_label());
|
||||
} else {
|
||||
generator.emit<Bytecode::Op::Load>(result_reg, js_undefined());
|
||||
else_jump.set_target(generator.make_label());
|
||||
}
|
||||
}
|
||||
|
||||
end_jump.set_target(generator.make_label());
|
||||
|
||||
return result_reg;
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> ContinueStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void ContinueStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
generator.emit<Bytecode::Op::Jump>(generator.nearest_continuable_scope());
|
||||
return {};
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> DebuggerStatement::generate_bytecode(Bytecode::Generator&) const
|
||||
void DebuggerStatement::generate_bytecode(Bytecode::Generator&) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> ConditionalExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void ConditionalExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto result_reg = generator.allocate_register();
|
||||
auto test_reg = m_test->generate_bytecode(generator);
|
||||
auto& alternate_jump = generator.emit<Bytecode::Op::JumpIfFalse>(*test_reg);
|
||||
m_test->generate_bytecode(generator);
|
||||
auto& alternate_jump = generator.emit<Bytecode::Op::JumpIfFalse>();
|
||||
|
||||
auto consequent_reg = m_consequent->generate_bytecode(generator);
|
||||
generator.emit<Bytecode::Op::LoadRegister>(result_reg, *consequent_reg);
|
||||
m_consequent->generate_bytecode(generator);
|
||||
auto& end_jump = generator.emit<Bytecode::Op::Jump>();
|
||||
|
||||
alternate_jump.set_target(generator.make_label());
|
||||
auto alternative_reg = m_alternate->generate_bytecode(generator);
|
||||
generator.emit<Bytecode::Op::LoadRegister>(result_reg, *alternative_reg);
|
||||
m_alternate->generate_bytecode(generator);
|
||||
|
||||
end_jump.set_target(generator.make_label());
|
||||
|
||||
return result_reg;
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> SequenceExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void SequenceExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Optional<Bytecode::Register> last_reg;
|
||||
|
||||
for (auto& expression : m_expressions)
|
||||
last_reg = expression.generate_bytecode(generator);
|
||||
|
||||
return last_reg;
|
||||
expression.generate_bytecode(generator);
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> TemplateLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
void TemplateLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
Optional<Bytecode::Register> result_reg;
|
||||
auto string_reg = generator.allocate_register();
|
||||
|
||||
for (auto& expression : m_expressions) {
|
||||
auto expr_reg = expression.generate_bytecode(generator);
|
||||
if (!result_reg.has_value())
|
||||
result_reg = expr_reg;
|
||||
else
|
||||
generator.emit<Bytecode::Op::Add>(*result_reg, *result_reg, *expr_reg);
|
||||
for (size_t i = 0; i < m_expressions.size(); i++) {
|
||||
m_expressions[i].generate_bytecode(generator);
|
||||
if (i == 0) {
|
||||
generator.emit<Bytecode::Op::Store>(string_reg);
|
||||
} else {
|
||||
generator.emit<Bytecode::Op::ConcatString>(string_reg);
|
||||
}
|
||||
|
||||
if (!result_reg.has_value()) {
|
||||
result_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::NewString>(*result_reg, "");
|
||||
}
|
||||
|
||||
return result_reg;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ Generator::~Generator()
|
|||
OwnPtr<Block> Generator::generate(ASTNode const& node)
|
||||
{
|
||||
Generator generator;
|
||||
[[maybe_unused]] auto dummy = node.generate_bytecode(generator);
|
||||
node.generate_bytecode(generator);
|
||||
generator.m_block->set_register_count({}, generator.m_next_register);
|
||||
generator.m_block->seal();
|
||||
return move(generator.m_block);
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
|
||||
#define ENUMERATE_BYTECODE_OPS(O) \
|
||||
O(Load) \
|
||||
O(LoadRegister) \
|
||||
O(LoadImmediate) \
|
||||
O(Store) \
|
||||
O(Add) \
|
||||
O(Sub) \
|
||||
O(Mul) \
|
||||
|
@ -36,7 +37,7 @@
|
|||
O(Jump) \
|
||||
O(JumpIfFalse) \
|
||||
O(JumpIfTrue) \
|
||||
O(JumpIfNullish) \
|
||||
O(JumpIfNotNullish) \
|
||||
O(Call) \
|
||||
O(EnterScope) \
|
||||
O(Return) \
|
||||
|
@ -52,7 +53,8 @@
|
|||
O(RightShift) \
|
||||
O(UnsignedRightShift) \
|
||||
O(In) \
|
||||
O(InstanceOf)
|
||||
O(InstanceOf) \
|
||||
O(ConcatString)
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
|
||||
Value run(Bytecode::Block const&);
|
||||
|
||||
ALWAYS_INLINE Value& accumulator() { return reg(Register::accumulator()); }
|
||||
Value& reg(Register const& r) { return registers()[r.index()]; }
|
||||
|
||||
void jump(Label const& label) { m_pending_jump = label.address(); }
|
||||
|
|
|
@ -51,12 +51,17 @@ namespace JS::Bytecode::Op {
|
|||
|
||||
void Load::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.reg(m_dst) = m_value;
|
||||
interpreter.accumulator() = interpreter.reg(m_src);
|
||||
}
|
||||
|
||||
void LoadRegister::execute(Bytecode::Interpreter& interpreter) const
|
||||
void LoadImmediate::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.reg(m_dst) = interpreter.reg(m_src);
|
||||
interpreter.accumulator() = m_value;
|
||||
}
|
||||
|
||||
void Store::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.reg(m_dst) = interpreter.accumulator();
|
||||
}
|
||||
|
||||
static Value abstract_inequals(GlobalObject& global_object, Value src1, Value src2)
|
||||
|
@ -82,11 +87,13 @@ static Value typed_equals(GlobalObject&, Value src1, Value src2)
|
|||
#define JS_DEFINE_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \
|
||||
void OpTitleCase::execute(Bytecode::Interpreter& interpreter) const \
|
||||
{ \
|
||||
interpreter.reg(m_dst) = op_snake_case(interpreter.global_object(), interpreter.reg(m_src1), interpreter.reg(m_src2)); \
|
||||
auto lhs = interpreter.reg(m_lhs_reg); \
|
||||
auto rhs = interpreter.accumulator(); \
|
||||
interpreter.accumulator() = op_snake_case(interpreter.global_object(), lhs, rhs); \
|
||||
} \
|
||||
String OpTitleCase::to_string() const \
|
||||
{ \
|
||||
return String::formatted(#OpTitleCase " dst:{}, src1:{}, src2:{}", m_dst, m_src1, m_src2); \
|
||||
return String::formatted(#OpTitleCase " lhs:{}", m_lhs_reg); \
|
||||
}
|
||||
|
||||
JS_ENUMERATE_COMMON_BINARY_OPS(JS_DEFINE_COMMON_BINARY_OP)
|
||||
|
@ -104,50 +111,55 @@ static Value typeof_(GlobalObject& global_object, Value value)
|
|||
#define JS_DEFINE_COMMON_UNARY_OP(OpTitleCase, op_snake_case) \
|
||||
void OpTitleCase::execute(Bytecode::Interpreter& interpreter) const \
|
||||
{ \
|
||||
interpreter.reg(m_dst) = op_snake_case(interpreter.global_object(), interpreter.reg(m_src)); \
|
||||
interpreter.accumulator() = op_snake_case(interpreter.global_object(), interpreter.accumulator()); \
|
||||
} \
|
||||
String OpTitleCase::to_string() const \
|
||||
{ \
|
||||
return String::formatted(#OpTitleCase " dst:{}, src:{}", m_dst, m_src); \
|
||||
return #OpTitleCase; \
|
||||
}
|
||||
|
||||
JS_ENUMERATE_COMMON_UNARY_OPS(JS_DEFINE_COMMON_UNARY_OP)
|
||||
|
||||
void NewBigInt::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.reg(m_dst) = js_bigint(interpreter.vm().heap(), m_bigint);
|
||||
interpreter.accumulator() = js_bigint(interpreter.vm().heap(), m_bigint);
|
||||
}
|
||||
|
||||
void NewString::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.reg(m_dst) = js_string(interpreter.vm(), m_string);
|
||||
interpreter.accumulator() = js_string(interpreter.vm(), m_string);
|
||||
}
|
||||
|
||||
void NewObject::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.reg(m_dst) = Object::create_empty(interpreter.global_object());
|
||||
interpreter.accumulator() = Object::create_empty(interpreter.global_object());
|
||||
}
|
||||
|
||||
void ConcatString::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.reg(m_lhs) = add(interpreter.global_object(), interpreter.reg(m_lhs), interpreter.accumulator());
|
||||
}
|
||||
|
||||
void GetVariable::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.reg(m_dst) = interpreter.vm().get_variable(m_identifier, interpreter.global_object());
|
||||
interpreter.accumulator() = interpreter.vm().get_variable(m_identifier, interpreter.global_object());
|
||||
}
|
||||
|
||||
void SetVariable::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.vm().set_variable(m_identifier, interpreter.reg(m_src), interpreter.global_object());
|
||||
interpreter.vm().set_variable(m_identifier, interpreter.accumulator(), interpreter.global_object());
|
||||
}
|
||||
|
||||
void GetById::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
if (auto* object = interpreter.reg(m_base).to_object(interpreter.global_object()))
|
||||
interpreter.reg(m_dst) = object->get(m_property);
|
||||
if (auto* object = interpreter.accumulator().to_object(interpreter.global_object()))
|
||||
interpreter.accumulator() = object->get(m_property);
|
||||
}
|
||||
|
||||
void PutById::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
if (auto* object = interpreter.reg(m_base).to_object(interpreter.global_object()))
|
||||
object->put(m_property, interpreter.reg(m_src));
|
||||
object->put(m_property, interpreter.accumulator());
|
||||
}
|
||||
|
||||
void Jump::execute(Bytecode::Interpreter& interpreter) const
|
||||
|
@ -158,7 +170,7 @@ void Jump::execute(Bytecode::Interpreter& interpreter) const
|
|||
void JumpIfFalse::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
VERIFY(m_target.has_value());
|
||||
auto result = interpreter.reg(m_result);
|
||||
auto result = interpreter.accumulator();
|
||||
if (!result.to_boolean())
|
||||
interpreter.jump(m_target.value());
|
||||
}
|
||||
|
@ -166,16 +178,16 @@ void JumpIfFalse::execute(Bytecode::Interpreter& interpreter) const
|
|||
void JumpIfTrue::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
VERIFY(m_target.has_value());
|
||||
auto result = interpreter.reg(m_result);
|
||||
auto result = interpreter.accumulator();
|
||||
if (result.to_boolean())
|
||||
interpreter.jump(m_target.value());
|
||||
}
|
||||
|
||||
void JumpIfNullish::execute(Bytecode::Interpreter& interpreter) const
|
||||
void JumpIfNotNullish::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
VERIFY(m_target.has_value());
|
||||
auto result = interpreter.reg(m_result);
|
||||
if (result.is_nullish())
|
||||
auto result = interpreter.accumulator();
|
||||
if (!result.is_nullish())
|
||||
interpreter.jump(m_target.value());
|
||||
}
|
||||
|
||||
|
@ -201,7 +213,7 @@ void Call::execute(Bytecode::Interpreter& interpreter) const
|
|||
return_value = interpreter.vm().call(function, this_value, move(argument_values));
|
||||
}
|
||||
|
||||
interpreter.reg(m_dst) = return_value;
|
||||
interpreter.accumulator() = return_value;
|
||||
}
|
||||
|
||||
void EnterScope::execute(Bytecode::Interpreter& interpreter) const
|
||||
|
@ -223,53 +235,62 @@ void EnterScope::execute(Bytecode::Interpreter& interpreter) const
|
|||
|
||||
void Return::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto return_value = m_argument.has_value() ? interpreter.reg(m_argument.value()) : js_undefined();
|
||||
interpreter.do_return(return_value);
|
||||
interpreter.do_return(interpreter.accumulator().value_or(js_undefined()));
|
||||
}
|
||||
|
||||
String Load::to_string() const
|
||||
{
|
||||
return String::formatted("Load dst:{}, value:{}", m_dst, m_value.to_string_without_side_effects());
|
||||
return String::formatted("Load src:{}", m_src);
|
||||
}
|
||||
|
||||
String LoadRegister::to_string() const
|
||||
String LoadImmediate::to_string() const
|
||||
{
|
||||
return String::formatted("LoadRegister dst:{}, src:{}", m_dst, m_src);
|
||||
return String::formatted("LoadImmediate value:{}", m_value);
|
||||
}
|
||||
|
||||
String Store::to_string() const
|
||||
{
|
||||
return String::formatted("Store dst:{}", m_dst);
|
||||
}
|
||||
|
||||
String NewBigInt::to_string() const
|
||||
{
|
||||
return String::formatted("NewBigInt dst:{}, bigint:\"{}\"", m_dst, m_bigint.to_base10());
|
||||
return String::formatted("NewBigInt bigint:\"{}\"", m_bigint.to_base10());
|
||||
}
|
||||
|
||||
String NewString::to_string() const
|
||||
{
|
||||
return String::formatted("NewString dst:{}, string:\"{}\"", m_dst, m_string);
|
||||
return String::formatted("NewString string:\"{}\"", m_string);
|
||||
}
|
||||
|
||||
String NewObject::to_string() const
|
||||
{
|
||||
return String::formatted("NewObject dst:{}", m_dst);
|
||||
return "NewObject";
|
||||
}
|
||||
|
||||
String ConcatString::to_string() const
|
||||
{
|
||||
return String::formatted("ConcatString lhs:{}", m_lhs);
|
||||
}
|
||||
|
||||
String GetVariable::to_string() const
|
||||
{
|
||||
return String::formatted("GetVariable dst:{}, identifier:{}", m_dst, m_identifier);
|
||||
return String::formatted("GetVariable identifier:{}", m_identifier);
|
||||
}
|
||||
|
||||
String SetVariable::to_string() const
|
||||
{
|
||||
return String::formatted("SetVariable identifier:{}, src:{}", m_identifier, m_src);
|
||||
return String::formatted("SetVariable identifier:{}", m_identifier);
|
||||
}
|
||||
|
||||
String PutById::to_string() const
|
||||
{
|
||||
return String::formatted("PutById base:{}, property:{}, src:{}", m_base, m_property, m_src);
|
||||
return String::formatted("PutById base:{}, property:{}", m_base, m_property);
|
||||
}
|
||||
|
||||
String GetById::to_string() const
|
||||
{
|
||||
return String::formatted("GetById dst:{}, base:{}, property:{}", m_dst, m_base, m_property);
|
||||
return String::formatted("GetById property:{}", m_property);
|
||||
}
|
||||
|
||||
String Jump::to_string() const
|
||||
|
@ -280,28 +301,28 @@ String Jump::to_string() const
|
|||
String JumpIfFalse::to_string() const
|
||||
{
|
||||
if (m_target.has_value())
|
||||
return String::formatted("JumpIfFalse result:{}, target:{}", m_result, m_target.value());
|
||||
return String::formatted("JumpIfFalse result:{}, target:<empty>", m_result);
|
||||
return String::formatted("JumpIfFalse target:{}", m_target.value());
|
||||
return "JumpIfFalse target:<empty>";
|
||||
}
|
||||
|
||||
String JumpIfTrue::to_string() const
|
||||
{
|
||||
if (m_target.has_value())
|
||||
return String::formatted("JumpIfTrue result:{}, target:{}", m_result, m_target.value());
|
||||
return String::formatted("JumpIfTrue result:{}, target:<empty>", m_result);
|
||||
return String::formatted("JumpIfTrue target:{}", m_target.value());
|
||||
return "JumpIfTrue result:{}, target:<empty>";
|
||||
}
|
||||
|
||||
String JumpIfNullish::to_string() const
|
||||
String JumpIfNotNullish::to_string() const
|
||||
{
|
||||
if (m_target.has_value())
|
||||
return String::formatted("JumpIfNullish result:{}, target:{}", m_result, m_target.value());
|
||||
return String::formatted("JumpIfNullish result:{}, target:<empty>", m_result);
|
||||
return String::formatted("JumpIfNotNullish target:{}", m_target.value());
|
||||
return "JumpIfNotNullish target:<empty>";
|
||||
}
|
||||
|
||||
String Call::to_string() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
builder.appendff("Call dst:{}, callee:{}, this:{}", m_dst, m_callee, m_this_value);
|
||||
builder.appendff("Call callee:{}, this:{}", m_callee, m_this_value);
|
||||
if (m_argument_count != 0) {
|
||||
builder.append(", arguments:[");
|
||||
for (size_t i = 0; i < m_argument_count; ++i) {
|
||||
|
@ -321,8 +342,6 @@ String EnterScope::to_string() const
|
|||
|
||||
String Return::to_string() const
|
||||
{
|
||||
if (m_argument.has_value())
|
||||
return String::formatted("Return {}", m_argument.value());
|
||||
return "Return";
|
||||
}
|
||||
|
||||
|
|
|
@ -19,26 +19,8 @@ namespace JS::Bytecode::Op {
|
|||
|
||||
class Load final : public Instruction {
|
||||
public:
|
||||
Load(Register dst, Value value)
|
||||
Load(Register src)
|
||||
: Instruction(Type::Load)
|
||||
, m_dst(dst)
|
||||
, m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
void execute(Bytecode::Interpreter&) const;
|
||||
String to_string() const;
|
||||
|
||||
private:
|
||||
Register m_dst;
|
||||
Value m_value;
|
||||
};
|
||||
|
||||
class LoadRegister final : public Instruction {
|
||||
public:
|
||||
LoadRegister(Register dst, Register src)
|
||||
: Instruction(Type::LoadRegister)
|
||||
, m_dst(dst)
|
||||
, m_src(src)
|
||||
{
|
||||
}
|
||||
|
@ -47,10 +29,39 @@ public:
|
|||
String to_string() const;
|
||||
|
||||
private:
|
||||
Register m_dst;
|
||||
Register m_src;
|
||||
};
|
||||
|
||||
class LoadImmediate final : public Instruction {
|
||||
public:
|
||||
LoadImmediate(Value value)
|
||||
: Instruction(Type::LoadImmediate)
|
||||
, m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
void execute(Bytecode::Interpreter&) const;
|
||||
String to_string() const;
|
||||
|
||||
private:
|
||||
Value m_value;
|
||||
};
|
||||
|
||||
class Store final : public Instruction {
|
||||
public:
|
||||
Store(Register dst)
|
||||
: Instruction(Type::Store)
|
||||
, m_dst(dst)
|
||||
{
|
||||
}
|
||||
|
||||
void execute(Bytecode::Interpreter&) const;
|
||||
String to_string() const;
|
||||
|
||||
private:
|
||||
Register m_dst;
|
||||
};
|
||||
|
||||
#define JS_ENUMERATE_COMMON_BINARY_OPS(O) \
|
||||
O(Add, add) \
|
||||
O(Sub, sub) \
|
||||
|
@ -78,11 +89,9 @@ private:
|
|||
#define JS_DECLARE_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \
|
||||
class OpTitleCase final : public Instruction { \
|
||||
public: \
|
||||
OpTitleCase(Register dst, Register src1, Register src2) \
|
||||
OpTitleCase(Register lhs_reg) \
|
||||
: Instruction(Type::OpTitleCase) \
|
||||
, m_dst(dst) \
|
||||
, m_src1(src1) \
|
||||
, m_src2(src2) \
|
||||
, m_lhs_reg(lhs_reg) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
|
@ -90,9 +99,7 @@ private:
|
|||
String to_string() const; \
|
||||
\
|
||||
private: \
|
||||
Register m_dst; \
|
||||
Register m_src1; \
|
||||
Register m_src2; \
|
||||
Register m_lhs_reg; \
|
||||
};
|
||||
|
||||
JS_ENUMERATE_COMMON_BINARY_OPS(JS_DECLARE_COMMON_BINARY_OP)
|
||||
|
@ -108,19 +115,13 @@ JS_ENUMERATE_COMMON_BINARY_OPS(JS_DECLARE_COMMON_BINARY_OP)
|
|||
#define JS_DECLARE_COMMON_UNARY_OP(OpTitleCase, op_snake_case) \
|
||||
class OpTitleCase final : public Instruction { \
|
||||
public: \
|
||||
OpTitleCase(Register dst, Register src) \
|
||||
OpTitleCase() \
|
||||
: Instruction(Type::OpTitleCase) \
|
||||
, m_dst(dst) \
|
||||
, m_src(src) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
void execute(Bytecode::Interpreter&) const; \
|
||||
String to_string() const; \
|
||||
\
|
||||
private: \
|
||||
Register m_dst; \
|
||||
Register m_src; \
|
||||
};
|
||||
|
||||
JS_ENUMERATE_COMMON_UNARY_OPS(JS_DECLARE_COMMON_UNARY_OP)
|
||||
|
@ -128,9 +129,8 @@ JS_ENUMERATE_COMMON_UNARY_OPS(JS_DECLARE_COMMON_UNARY_OP)
|
|||
|
||||
class NewString final : public Instruction {
|
||||
public:
|
||||
NewString(Register dst, String string)
|
||||
NewString(String string)
|
||||
: Instruction(Type::NewString)
|
||||
, m_dst(dst)
|
||||
, m_string(move(string))
|
||||
{
|
||||
}
|
||||
|
@ -139,30 +139,24 @@ public:
|
|||
String to_string() const;
|
||||
|
||||
private:
|
||||
Register m_dst;
|
||||
String m_string;
|
||||
};
|
||||
|
||||
class NewObject final : public Instruction {
|
||||
public:
|
||||
explicit NewObject(Register dst)
|
||||
NewObject()
|
||||
: Instruction(Type::NewObject)
|
||||
, m_dst(dst)
|
||||
{
|
||||
}
|
||||
|
||||
void execute(Bytecode::Interpreter&) const;
|
||||
String to_string() const;
|
||||
|
||||
private:
|
||||
Register m_dst;
|
||||
};
|
||||
|
||||
class NewBigInt final : public Instruction {
|
||||
public:
|
||||
explicit NewBigInt(Register dst, Crypto::SignedBigInteger bigint)
|
||||
explicit NewBigInt(Crypto::SignedBigInteger bigint)
|
||||
: Instruction(Type::NewBigInt)
|
||||
, m_dst(dst)
|
||||
, m_bigint(move(bigint))
|
||||
{
|
||||
}
|
||||
|
@ -171,16 +165,29 @@ public:
|
|||
String to_string() const;
|
||||
|
||||
private:
|
||||
Register m_dst;
|
||||
Crypto::SignedBigInteger m_bigint;
|
||||
};
|
||||
|
||||
class ConcatString final : public Instruction {
|
||||
public:
|
||||
ConcatString(Register lhs)
|
||||
: Instruction(Type::ConcatString)
|
||||
, m_lhs(lhs)
|
||||
{
|
||||
}
|
||||
|
||||
void execute(Bytecode::Interpreter&) const;
|
||||
String to_string() const;
|
||||
|
||||
private:
|
||||
Register m_lhs;
|
||||
};
|
||||
|
||||
class SetVariable final : public Instruction {
|
||||
public:
|
||||
SetVariable(FlyString identifier, Register src)
|
||||
SetVariable(FlyString identifier)
|
||||
: Instruction(Type::SetVariable)
|
||||
, m_identifier(move(identifier))
|
||||
, m_src(src)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -189,14 +196,12 @@ public:
|
|||
|
||||
private:
|
||||
FlyString m_identifier;
|
||||
Register m_src;
|
||||
};
|
||||
|
||||
class GetVariable final : public Instruction {
|
||||
public:
|
||||
GetVariable(Register dst, FlyString identifier)
|
||||
GetVariable(FlyString identifier)
|
||||
: Instruction(Type::GetVariable)
|
||||
, m_dst(dst)
|
||||
, m_identifier(move(identifier))
|
||||
{
|
||||
}
|
||||
|
@ -205,16 +210,13 @@ public:
|
|||
String to_string() const;
|
||||
|
||||
private:
|
||||
Register m_dst;
|
||||
FlyString m_identifier;
|
||||
};
|
||||
|
||||
class GetById final : public Instruction {
|
||||
public:
|
||||
GetById(Register dst, Register base, FlyString property)
|
||||
GetById(FlyString property)
|
||||
: Instruction(Type::GetById)
|
||||
, m_dst(dst)
|
||||
, m_base(base)
|
||||
, m_property(move(property))
|
||||
{
|
||||
}
|
||||
|
@ -223,18 +225,15 @@ public:
|
|||
String to_string() const;
|
||||
|
||||
private:
|
||||
Register m_dst;
|
||||
Register m_base;
|
||||
FlyString m_property;
|
||||
};
|
||||
|
||||
class PutById final : public Instruction {
|
||||
public:
|
||||
PutById(Register base, FlyString property, Register src)
|
||||
PutById(Register base, FlyString property)
|
||||
: Instruction(Type::PutById)
|
||||
, m_base(base)
|
||||
, m_property(move(property))
|
||||
, m_src(src)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -244,7 +243,6 @@ public:
|
|||
private:
|
||||
Register m_base;
|
||||
FlyString m_property;
|
||||
Register m_src;
|
||||
};
|
||||
|
||||
class Jump : public Instruction {
|
||||
|
@ -272,55 +270,42 @@ protected:
|
|||
|
||||
class JumpIfFalse final : public Jump {
|
||||
public:
|
||||
explicit JumpIfFalse(Register result, Optional<Label> target = {})
|
||||
explicit JumpIfFalse(Optional<Label> target = {})
|
||||
: Jump(Type::JumpIfFalse, move(target))
|
||||
, m_result(result)
|
||||
{
|
||||
}
|
||||
|
||||
void execute(Bytecode::Interpreter&) const;
|
||||
String to_string() const;
|
||||
|
||||
private:
|
||||
Register m_result;
|
||||
};
|
||||
|
||||
class JumpIfTrue : public Jump {
|
||||
public:
|
||||
explicit JumpIfTrue(Register result, Optional<Label> target = {})
|
||||
explicit JumpIfTrue(Optional<Label> target = {})
|
||||
: Jump(Type::JumpIfTrue, move(target))
|
||||
, m_result(result)
|
||||
{
|
||||
}
|
||||
|
||||
void execute(Bytecode::Interpreter&) const;
|
||||
String to_string() const;
|
||||
|
||||
private:
|
||||
Register m_result;
|
||||
};
|
||||
|
||||
class JumpIfNullish final : public Jump {
|
||||
class JumpIfNotNullish final : public Jump {
|
||||
public:
|
||||
explicit JumpIfNullish(Register result, Optional<Label> target = {})
|
||||
: Jump(Type::JumpIfNullish, move(target))
|
||||
, m_result(result)
|
||||
explicit JumpIfNotNullish(Optional<Label> target = {})
|
||||
: Jump(Type::JumpIfNotNullish, move(target))
|
||||
{
|
||||
}
|
||||
|
||||
void execute(Bytecode::Interpreter&) const;
|
||||
String to_string() const;
|
||||
|
||||
private:
|
||||
Register m_result;
|
||||
};
|
||||
|
||||
// NOTE: This instruction is variable-width depending on the number of arguments!
|
||||
class Call final : public Instruction {
|
||||
public:
|
||||
Call(Register dst, Register callee, Register this_value, Vector<Register> const& arguments)
|
||||
Call(Register callee, Register this_value, Vector<Register> const& arguments)
|
||||
: Instruction(Type::Call)
|
||||
, m_dst(dst)
|
||||
, m_callee(callee)
|
||||
, m_this_value(this_value)
|
||||
, m_argument_count(arguments.size())
|
||||
|
@ -335,7 +320,6 @@ public:
|
|||
size_t length() const { return sizeof(*this) + sizeof(Register) * m_argument_count; }
|
||||
|
||||
private:
|
||||
Register m_dst;
|
||||
Register m_callee;
|
||||
Register m_this_value;
|
||||
size_t m_argument_count { 0 };
|
||||
|
@ -359,17 +343,13 @@ private:
|
|||
|
||||
class Return final : public Instruction {
|
||||
public:
|
||||
explicit Return(Optional<Register> argument)
|
||||
Return()
|
||||
: Instruction(Type::Return)
|
||||
, m_argument(move(argument))
|
||||
{
|
||||
}
|
||||
|
||||
void execute(Bytecode::Interpreter&) const;
|
||||
String to_string() const;
|
||||
|
||||
private:
|
||||
Optional<Register> m_argument;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,14 @@ namespace JS::Bytecode {
|
|||
|
||||
class Register {
|
||||
public:
|
||||
constexpr static u32 accumulator_index = 0;
|
||||
|
||||
static Register accumulator()
|
||||
{
|
||||
static Register accumulator(accumulator_index);
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
explicit Register(u32 index)
|
||||
: m_index(index)
|
||||
{
|
||||
|
@ -20,7 +28,7 @@ public:
|
|||
u32 index() const { return m_index; }
|
||||
|
||||
private:
|
||||
u32 m_index { 0 };
|
||||
u32 m_index;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -29,6 +37,8 @@ template<>
|
|||
struct AK::Formatter<JS::Bytecode::Register> : AK::Formatter<FormatString> {
|
||||
void format(FormatBuilder& builder, JS::Bytecode::Register const& value)
|
||||
{
|
||||
if (value.index() == JS::Bytecode::Register::accumulator_index)
|
||||
return AK::Formatter<FormatString>::format(builder, "acc");
|
||||
return AK::Formatter<FormatString>::format(builder, "${}", value.index());
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue