From 9bed2e4f4a90ce2d82d8f6122db2d0cfbad48b49 Mon Sep 17 00:00:00 2001 From: Matthew Olsson Date: Mon, 7 Jun 2021 20:58:36 -0700 Subject: [PATCH] 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, 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. --- Userland/Libraries/LibJS/AST.h | 56 +-- .../Libraries/LibJS/Bytecode/ASTCodegen.cpp | 453 ++++++++---------- .../Libraries/LibJS/Bytecode/Generator.cpp | 2 +- .../Libraries/LibJS/Bytecode/Instruction.h | 8 +- .../Libraries/LibJS/Bytecode/Interpreter.h | 1 + Userland/Libraries/LibJS/Bytecode/Op.cpp | 129 ++--- Userland/Libraries/LibJS/Bytecode/Op.h | 148 +++--- Userland/Libraries/LibJS/Bytecode/Register.h | 12 +- 8 files changed, 377 insertions(+), 432 deletions(-) diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index a2efbcdea9..f35122cabb 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -37,7 +37,7 @@ class ASTNode : public RefCounted { public: virtual ~ASTNode() { } virtual Value execute(Interpreter&, GlobalObject&) const = 0; - virtual Optional 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 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 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& children() const { return m_children; } virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual Optional generate_bytecode(Bytecode::Generator&) const override; + virtual void generate_bytecode(Bytecode::Generator&) const override; void add_variables(NonnullRefPtrVector); void add_functions(NonnullRefPtrVector); @@ -273,7 +273,7 @@ public: virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual Optional 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 generate_bytecode(Bytecode::Generator&) const override; + virtual void generate_bytecode(Bytecode::Generator&) const override; private: RefPtr m_argument; @@ -352,7 +352,7 @@ public: virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual Optional generate_bytecode(Bytecode::Generator&) const override; + virtual void generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr m_predicate; @@ -374,7 +374,7 @@ public: virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual Optional generate_bytecode(Bytecode::Generator&) const override; + virtual void generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr m_test; @@ -395,7 +395,7 @@ public: virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual Optional generate_bytecode(Bytecode::Generator&) const override; + virtual void generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr m_test; @@ -440,7 +440,7 @@ public: virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual Optional generate_bytecode(Bytecode::Generator&) const override; + virtual void generate_bytecode(Bytecode::Generator&) const override; private: RefPtr m_init; @@ -532,7 +532,7 @@ public: virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual Optional 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 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 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 generate_bytecode(Bytecode::Generator&) const override; + virtual void generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtrVector m_expressions; @@ -629,7 +629,7 @@ public: virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual Optional 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 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 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 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 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 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 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 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 generate_bytecode(Bytecode::Generator&) const override; + virtual void generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtrVector m_properties; @@ -1092,7 +1092,7 @@ public: virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual Optional generate_bytecode(Bytecode::Generator&) const override; + virtual void generate_bytecode(Bytecode::Generator&) const override; const NonnullRefPtrVector& expressions() const { return m_expressions; } const NonnullRefPtrVector& 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 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 generate_bytecode(Bytecode::Generator&) const override; + virtual void generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr m_test; @@ -1310,7 +1310,7 @@ public: } virtual Value execute(Interpreter&, GlobalObject&) const override; - virtual Optional 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 generate_bytecode(Bytecode::Generator&) const override; + virtual void generate_bytecode(Bytecode::Generator&) const override; }; template diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 5a26fa6cdf..68d6d7d4d5 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -13,489 +13,422 @@ namespace JS { -Optional ASTNode::generate_bytecode(Bytecode::Generator&) const +void ASTNode::generate_bytecode(Bytecode::Generator&) const { dbgln("Missing generate_bytecode()"); TODO(); } -Optional ScopeNode::generate_bytecode(Bytecode::Generator& generator) const +void ScopeNode::generate_bytecode(Bytecode::Generator& generator) const { generator.emit(*this); - Optional 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 EmptyStatement::generate_bytecode(Bytecode::Generator&) const +void EmptyStatement::generate_bytecode(Bytecode::Generator&) const { - return {}; } -Optional 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 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(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(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::Subtraction: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::Multiplication: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::Division: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::Modulo: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::Exponentiation: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::GreaterThan: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::GreaterThanEquals: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::LessThan: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::LessThanEquals: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::AbstractInequals: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::AbstractEquals: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::TypedInequals: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::TypedEquals: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::BitwiseAnd: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::BitwiseOr: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::BitwiseXor: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::LeftShift: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::RightShift: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::UnsignedRightShift: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::In: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; case BinaryOp::InstanceOf: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); - return dst_reg; + generator.emit(lhs_reg); + break; default: VERIFY_NOT_REACHED(); } } -Optional 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(*lhs_reg); + test_instr = &generator.emit(); break; case LogicalOp::Or: - test_instr = &generator.emit(*lhs_reg); + test_instr = &generator.emit(); break; case LogicalOp::NullishCoalescing: - test_instr = &generator.emit(*lhs_reg); + test_instr = &generator.emit(); break; default: VERIFY_NOT_REACHED(); } - generator.emit(result_reg, *lhs_reg); - auto& end_jump = generator.emit(); - - auto rhs_label = generator.make_label(); - test_instr->set_target(rhs_label); - - auto rhs_reg = m_rhs->generate_bytecode(generator); - generator.emit(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 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(dst_reg, *lhs_reg); - return dst_reg; + generator.emit(); + break; case UnaryOp::Not: - generator.emit(dst_reg, *lhs_reg); - return dst_reg; + generator.emit(); + break; case UnaryOp::Plus: - generator.emit(dst_reg, *lhs_reg); - return dst_reg; + generator.emit(); + break; case UnaryOp::Minus: - generator.emit(dst_reg, *lhs_reg); - return dst_reg; + generator.emit(); + break; case UnaryOp::Typeof: - generator.emit(dst_reg, *lhs_reg); - return dst_reg; + generator.emit(); + break; case UnaryOp::Void: - generator.emit(dst_reg, js_undefined()); - return dst_reg; + generator.emit(js_undefined()); + break; default: TODO(); } } -Optional NumericLiteral::generate_bytecode(Bytecode::Generator& generator) const +void NumericLiteral::generate_bytecode(Bytecode::Generator& generator) const { - auto dst = generator.allocate_register(); - generator.emit(dst, m_value); - return dst; + generator.emit(m_value); } -Optional BooleanLiteral::generate_bytecode(Bytecode::Generator& generator) const +void BooleanLiteral::generate_bytecode(Bytecode::Generator& generator) const { - auto dst = generator.allocate_register(); - generator.emit(dst, Value(m_value)); - return dst; + generator.emit(Value(m_value)); } -Optional NullLiteral::generate_bytecode(Bytecode::Generator& generator) const +void NullLiteral::generate_bytecode(Bytecode::Generator& generator) const { - auto dst = generator.allocate_register(); - generator.emit(dst, js_null()); - return dst; + generator.emit(js_null()); } -Optional BigIntLiteral::generate_bytecode(Bytecode::Generator& generator) const +void BigIntLiteral::generate_bytecode(Bytecode::Generator& generator) const { - auto dst = generator.allocate_register(); - generator.emit(dst, Crypto::SignedBigInteger::from_base10(m_value.substring(0, m_value.length() - 1))); - return dst; + generator.emit(Crypto::SignedBigInteger::from_base10(m_value.substring(0, m_value.length() - 1))); } -Optional StringLiteral::generate_bytecode(Bytecode::Generator& generator) const +void StringLiteral::generate_bytecode(Bytecode::Generator& generator) const { - auto dst = generator.allocate_register(); - generator.emit(dst, m_value); - return dst; + generator.emit(m_value); } -Optional Identifier::generate_bytecode(Bytecode::Generator& generator) const +void Identifier::generate_bytecode(Bytecode::Generator& generator) const { - auto reg = generator.allocate_register(); - generator.emit(reg, m_string); - return reg; + generator.emit(m_string); } -Optional AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) const +void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) const { if (is(*m_lhs)) { auto& identifier = static_cast(*m_lhs); - auto rhs_reg = m_rhs->generate_bytecode(generator); - VERIFY(rhs_reg.has_value()); if (m_op == AssignmentOp::Assignment) { - generator.emit(identifier.string(), *rhs_reg); - return rhs_reg; + m_rhs->generate_bytecode(generator); + generator.emit(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(lhs_reg); + m_rhs->generate_bytecode(generator); switch (m_op) { case AssignmentOp::AdditionAssignment: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); + generator.emit(lhs_reg); break; case AssignmentOp::SubtractionAssignment: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); + generator.emit(lhs_reg); break; case AssignmentOp::MultiplicationAssignment: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); + generator.emit(lhs_reg); break; case AssignmentOp::DivisionAssignment: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); + generator.emit(lhs_reg); break; case AssignmentOp::ModuloAssignment: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); + generator.emit(lhs_reg); break; case AssignmentOp::ExponentiationAssignment: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); + generator.emit(lhs_reg); break; case AssignmentOp::BitwiseAndAssignment: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); + generator.emit(lhs_reg); break; case AssignmentOp::BitwiseOrAssignment: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); + generator.emit(lhs_reg); break; case AssignmentOp::BitwiseXorAssignment: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); + generator.emit(lhs_reg); break; case AssignmentOp::LeftShiftAssignment: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); + generator.emit(lhs_reg); break; case AssignmentOp::RightShiftAssignment: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); + generator.emit(lhs_reg); break; case AssignmentOp::UnsignedRightShiftAssignment: - generator.emit(dst_reg, *lhs_reg, *rhs_reg); + generator.emit(lhs_reg); break; default: TODO(); } - generator.emit(identifier.string(), dst_reg); + generator.emit(identifier.string()); - return dst_reg; + return; } if (is(*m_lhs)) { auto& expression = static_cast(*m_lhs); - auto object_reg = expression.object().generate_bytecode(generator); + expression.object().generate_bytecode(generator); + auto object_reg = generator.allocate_register(); + generator.emit(object_reg); if (expression.is_computed()) { TODO(); } else { VERIFY(is(expression.property())); - auto rhs_reg = m_rhs->generate_bytecode(generator); - generator.emit(*object_reg, static_cast(expression.property()).string(), *rhs_reg); - return rhs_reg; + m_rhs->generate_bytecode(generator); + generator.emit(object_reg, static_cast(expression.property()).string()); + return; } } TODO(); } -Optional 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(*test_result_reg); - auto body_result_reg = m_body->generate_bytecode(generator); + m_test->generate_bytecode(generator); + auto& test_jump = generator.emit(); + m_body->generate_bytecode(generator); generator.emit(test_label); test_jump.set_target(generator.make_label()); generator.end_continuable_scope(); - return body_result_reg; } -Optional 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(*test_result_reg, head_label); - return body_result_reg; + m_test->generate_bytecode(generator); + generator.emit(head_label); } -Optional 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(*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(); } + + m_body->generate_bytecode(generator); + if (m_update) + m_update->generate_bytecode(generator); generator.emit(jump_label); if (m_test) test_jump->set_target(generator.make_label()); generator.end_continuable_scope(); - return body_result_reg; } -Optional ObjectExpression::generate_bytecode(Bytecode::Generator& generator) const +void ObjectExpression::generate_bytecode(Bytecode::Generator& generator) const { - auto reg = generator.allocate_register(); - generator.emit(reg); + generator.emit(); - if (!m_properties.is_empty()) { + if (!m_properties.is_empty()) TODO(); - } - - return reg; } -Optional 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(property())); - auto dst_reg = generator.allocate_register(); - generator.emit(dst_reg, *object_reg, static_cast(property()).string()); - return dst_reg; + generator.emit(static_cast(property()).string()); } } -Optional FunctionDeclaration::generate_bytecode(Bytecode::Generator&) const +void FunctionDeclaration::generate_bytecode(Bytecode::Generator&) const { - return {}; } -Optional 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(callee_reg); // FIXME: Load the correct 'this' value into 'this_reg'. auto this_reg = generator.allocate_register(); - generator.emit(this_reg, js_undefined()); + generator.emit(js_undefined()); + generator.emit(this_reg); Vector 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(argument_registers.size(), dst_reg, *callee_reg, this_reg, argument_registers); - return dst_reg; -} - -Optional ReturnStatement::generate_bytecode(Bytecode::Generator& generator) const -{ - Optional argument_reg; - if (m_argument) - argument_reg = m_argument->generate_bytecode(generator); - - generator.emit(argument_reg); - return argument_reg; -} - -Optional 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(*predicate_reg); - - auto consequent_reg = m_consequent->generate_bytecode(generator); - generator.emit(result_reg, *consequent_reg); - auto& end_jump = generator.emit(); - - else_jump.set_target(generator.make_label()); - if (m_alternate) { - auto alternative_reg = m_alternate->generate_bytecode(generator); - generator.emit(result_reg, *alternative_reg); - } else { - generator.emit(result_reg, js_undefined()); + for (auto& arg : m_arguments) { + arg.value->generate_bytecode(generator); + auto arg_reg = generator.allocate_register(); + generator.emit(arg_reg); + argument_registers.append(arg_reg); } - - end_jump.set_target(generator.make_label()); - - return result_reg; + generator.emit_with_extra_register_slots(argument_registers.size(), callee_reg, this_reg, argument_registers); } -Optional ContinueStatement::generate_bytecode(Bytecode::Generator& generator) const +void ReturnStatement::generate_bytecode(Bytecode::Generator& generator) const +{ + generator.emit(); +} + +void IfStatement::generate_bytecode(Bytecode::Generator& generator) const +{ + m_predicate->generate_bytecode(generator); + 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()); + m_alternate->generate_bytecode(generator); + if_jump.set_target(generator.make_label()); + } else { + else_jump.set_target(generator.make_label()); + } +} + +void ContinueStatement::generate_bytecode(Bytecode::Generator& generator) const { generator.emit(generator.nearest_continuable_scope()); - return {}; } -Optional DebuggerStatement::generate_bytecode(Bytecode::Generator&) const +void DebuggerStatement::generate_bytecode(Bytecode::Generator&) const { - return {}; } -Optional 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(*test_reg); + m_test->generate_bytecode(generator); + auto& alternate_jump = generator.emit(); - auto consequent_reg = m_consequent->generate_bytecode(generator); - generator.emit(result_reg, *consequent_reg); + m_consequent->generate_bytecode(generator); auto& end_jump = generator.emit(); alternate_jump.set_target(generator.make_label()); - auto alternative_reg = m_alternate->generate_bytecode(generator); - generator.emit(result_reg, *alternative_reg); + m_alternate->generate_bytecode(generator); end_jump.set_target(generator.make_label()); - - return result_reg; } -Optional SequenceExpression::generate_bytecode(Bytecode::Generator& generator) const +void SequenceExpression::generate_bytecode(Bytecode::Generator& generator) const { - Optional last_reg; - for (auto& expression : m_expressions) - last_reg = expression.generate_bytecode(generator); - - return last_reg; + expression.generate_bytecode(generator); } -Optional TemplateLiteral::generate_bytecode(Bytecode::Generator& generator) const +void TemplateLiteral::generate_bytecode(Bytecode::Generator& generator) const { - Optional 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(*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(string_reg); + } else { + generator.emit(string_reg); + } } - - if (!result_reg.has_value()) { - result_reg = generator.allocate_register(); - generator.emit(*result_reg, ""); - } - - return result_reg; } } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 6b43bf3002..2d2ad73520 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -26,7 +26,7 @@ Generator::~Generator() OwnPtr 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); diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index 6bea827a35..1b7286eea8 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -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 { diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.h b/Userland/Libraries/LibJS/Bytecode/Interpreter.h index f48cce2231..4611bcf0af 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.h +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.h @@ -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(); } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index e2691681ed..ee21957f58 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -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) @@ -79,14 +84,16 @@ static Value typed_equals(GlobalObject&, Value src1, Value src2) return Value(strict_eq(src1, 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)); \ - } \ - String OpTitleCase::to_string() const \ - { \ - return String::formatted(#OpTitleCase " dst:{}, src1:{}, src2:{}", m_dst, m_src1, m_src2); \ +#define JS_DEFINE_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \ + void OpTitleCase::execute(Bytecode::Interpreter& interpreter) const \ + { \ + 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 " lhs:{}", m_lhs_reg); \ } JS_ENUMERATE_COMMON_BINARY_OPS(JS_DEFINE_COMMON_BINARY_OP) @@ -101,53 +108,58 @@ static Value typeof_(GlobalObject& global_object, Value value) return js_string(global_object.vm(), value.typeof()); } -#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)); \ - } \ - String OpTitleCase::to_string() const \ - { \ - return String::formatted(#OpTitleCase " dst:{}, src:{}", m_dst, m_src); \ +#define JS_DEFINE_COMMON_UNARY_OP(OpTitleCase, op_snake_case) \ + void OpTitleCase::execute(Bytecode::Interpreter& interpreter) const \ + { \ + interpreter.accumulator() = op_snake_case(interpreter.global_object(), interpreter.accumulator()); \ + } \ + String OpTitleCase::to_string() const \ + { \ + 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:", m_result); + return String::formatted("JumpIfFalse target:{}", m_target.value()); + return "JumpIfFalse target:"; } 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:", m_result); + return String::formatted("JumpIfTrue target:{}", m_target.value()); + return "JumpIfTrue result:{}, target:"; } -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:", m_result); + return String::formatted("JumpIfNotNullish target:{}", m_target.value()); + return "JumpIfNotNullish target:"; } 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"; } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index fb286ef2fa..73d6f837ba 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -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