Browse Source

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.
Matthew Olsson 4 years ago
parent
commit
9bed2e4f4a

+ 28 - 28
Userland/Libraries/LibJS/AST.h

@@ -37,7 +37,7 @@ class ASTNode : public RefCounted<ASTNode> {
 public:
 public:
     virtual ~ASTNode() { }
     virtual ~ASTNode() { }
     virtual Value execute(Interpreter&, GlobalObject&) const = 0;
     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;
     virtual void dump(int indent) const;
 
 
     const SourceRange& source_range() const { return m_source_range; }
     const SourceRange& source_range() const { return m_source_range; }
@@ -76,7 +76,7 @@ public:
     {
     {
     }
     }
     Value execute(Interpreter&, GlobalObject&) const override { return {}; }
     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 {
 class ErrorStatement final : public Statement {
@@ -98,7 +98,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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; };
     const Expression& expression() const { return m_expression; };
 
 
@@ -123,7 +123,7 @@ public:
     const NonnullRefPtrVector<Statement>& children() const { return m_children; }
     const NonnullRefPtrVector<Statement>& children() const { return m_children; }
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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_variables(NonnullRefPtrVector<VariableDeclaration>);
     void add_functions(NonnullRefPtrVector<FunctionDeclaration>);
     void add_functions(NonnullRefPtrVector<FunctionDeclaration>);
@@ -273,7 +273,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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
 class FunctionExpression final
@@ -330,7 +330,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     RefPtr<Expression> m_argument;
     RefPtr<Expression> m_argument;
@@ -352,7 +352,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     NonnullRefPtr<Expression> m_predicate;
     NonnullRefPtr<Expression> m_predicate;
@@ -374,7 +374,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     NonnullRefPtr<Expression> m_test;
     NonnullRefPtr<Expression> m_test;
@@ -395,7 +395,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     NonnullRefPtr<Expression> m_test;
     NonnullRefPtr<Expression> m_test;
@@ -440,7 +440,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     RefPtr<ASTNode> m_init;
     RefPtr<ASTNode> m_init;
@@ -532,7 +532,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     BinaryOp m_op;
     BinaryOp m_op;
@@ -558,7 +558,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     LogicalOp m_op;
     LogicalOp m_op;
@@ -587,7 +587,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     UnaryOp m_op;
     UnaryOp m_op;
@@ -605,7 +605,7 @@ public:
 
 
     virtual void dump(int indent) const override;
     virtual void dump(int indent) const override;
     virtual Value execute(Interpreter&, GlobalObject&) 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:
 private:
     NonnullRefPtrVector<Expression> m_expressions;
     NonnullRefPtrVector<Expression> m_expressions;
@@ -629,7 +629,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     bool m_value { false };
     bool m_value { false };
@@ -645,7 +645,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     Value m_value;
     Value m_value;
@@ -661,7 +661,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     String m_value;
     String m_value;
@@ -678,7 +678,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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; }
     StringView value() const { return m_value; }
     bool is_use_strict_directive() const { return m_is_use_strict_directive; };
     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 Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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 {
 class RegExpLiteral final : public Literal {
@@ -733,7 +733,7 @@ public:
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) const override;
     virtual void dump(int indent) const override;
     virtual Reference to_reference(Interpreter&, GlobalObject&) 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:
 private:
     FlyString m_string;
     FlyString m_string;
@@ -860,7 +860,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     struct ThisAndCallee {
     struct ThisAndCallee {
@@ -912,7 +912,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     AssignmentOp m_op;
     AssignmentOp m_op;
@@ -1052,7 +1052,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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:
 private:
     NonnullRefPtrVector<ObjectProperty> m_properties;
     NonnullRefPtrVector<ObjectProperty> m_properties;
@@ -1092,7 +1092,7 @@ public:
 
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) 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>& expressions() const { return m_expressions; }
     const NonnullRefPtrVector<Expression>& raw_strings() const { return m_raw_strings; }
     const NonnullRefPtrVector<Expression>& raw_strings() const { return m_raw_strings; }
@@ -1132,7 +1132,7 @@ public:
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) const override;
     virtual void dump(int indent) const override;
     virtual Reference to_reference(Interpreter&, GlobalObject&) 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; }
     bool is_computed() const { return m_computed; }
     const Expression& object() const { return *m_object; }
     const Expression& object() const { return *m_object; }
@@ -1180,7 +1180,7 @@ public:
 
 
     virtual void dump(int indent) const override;
     virtual void dump(int indent) const override;
     virtual Value execute(Interpreter&, GlobalObject&) 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:
 private:
     NonnullRefPtr<Expression> m_test;
     NonnullRefPtr<Expression> m_test;
@@ -1310,7 +1310,7 @@ public:
     }
     }
 
 
     virtual Value execute(Interpreter&, GlobalObject&) 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;
 
 
     const FlyString& target_label() const { return m_target_label; }
     const FlyString& target_label() const { return m_target_label; }
 
 
@@ -1326,7 +1326,7 @@ public:
     }
     }
 
 
     virtual Value execute(Interpreter&, GlobalObject&) 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;
 };
 };
 
 
 template<typename C>
 template<typename C>

+ 184 - 251
Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

@@ -13,489 +13,422 @@
 
 
 namespace JS {
 namespace JS {
 
 
-Optional<Bytecode::Register> ASTNode::generate_bytecode(Bytecode::Generator&) const
+void ASTNode::generate_bytecode(Bytecode::Generator&) const
 {
 {
     dbgln("Missing generate_bytecode()");
     dbgln("Missing generate_bytecode()");
     TODO();
     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);
     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);
-
-    VERIFY(lhs_reg.has_value());
-    VERIFY(rhs_reg.has_value());
+    m_lhs->generate_bytecode(generator);
+    auto lhs_reg = generator.allocate_register();
+    generator.emit<Bytecode::Op::Store>(lhs_reg);
 
 
-    auto dst_reg = generator.allocate_register();
+    m_rhs->generate_bytecode(generator);
 
 
     switch (m_op) {
     switch (m_op) {
     case BinaryOp::Addition:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     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:
     default:
         VERIFY_NOT_REACHED();
         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;
     Bytecode::Op::Jump* test_instr;
     switch (m_op) {
     switch (m_op) {
     case LogicalOp::And:
     case LogicalOp::And:
-        test_instr = &generator.emit<Bytecode::Op::JumpIfTrue>(*lhs_reg);
+        test_instr = &generator.emit<Bytecode::Op::JumpIfFalse>();
         break;
         break;
     case LogicalOp::Or:
     case LogicalOp::Or:
-        test_instr = &generator.emit<Bytecode::Op::JumpIfFalse>(*lhs_reg);
+        test_instr = &generator.emit<Bytecode::Op::JumpIfTrue>();
         break;
         break;
     case LogicalOp::NullishCoalescing:
     case LogicalOp::NullishCoalescing:
-        test_instr = &generator.emit<Bytecode::Op::JumpIfNullish>(*lhs_reg);
+        test_instr = &generator.emit<Bytecode::Op::JumpIfNotNullish>();
         break;
         break;
     default:
     default:
         VERIFY_NOT_REACHED();
         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) {
     switch (m_op) {
     case UnaryOp::BitwiseNot:
     case UnaryOp::BitwiseNot:
-        generator.emit<Bytecode::Op::BitwiseNot>(dst_reg, *lhs_reg);
-        return dst_reg;
+        generator.emit<Bytecode::Op::BitwiseNot>();
+        break;
     case UnaryOp::Not:
     case UnaryOp::Not:
-        generator.emit<Bytecode::Op::Not>(dst_reg, *lhs_reg);
-        return dst_reg;
+        generator.emit<Bytecode::Op::Not>();
+        break;
     case UnaryOp::Plus:
     case UnaryOp::Plus:
-        generator.emit<Bytecode::Op::UnaryPlus>(dst_reg, *lhs_reg);
-        return dst_reg;
+        generator.emit<Bytecode::Op::UnaryPlus>();
+        break;
     case UnaryOp::Minus:
     case UnaryOp::Minus:
-        generator.emit<Bytecode::Op::UnaryMinus>(dst_reg, *lhs_reg);
-        return dst_reg;
+        generator.emit<Bytecode::Op::UnaryMinus>();
+        break;
     case UnaryOp::Typeof:
     case UnaryOp::Typeof:
-        generator.emit<Bytecode::Op::Typeof>(dst_reg, *lhs_reg);
-        return dst_reg;
+        generator.emit<Bytecode::Op::Typeof>();
+        break;
     case UnaryOp::Void:
     case UnaryOp::Void:
-        generator.emit<Bytecode::Op::Load>(dst_reg, js_undefined());
-        return dst_reg;
+        generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
+        break;
     default:
     default:
         TODO();
         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)) {
     if (is<Identifier>(*m_lhs)) {
         auto& identifier = static_cast<Identifier const&>(*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) {
         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) {
         switch (m_op) {
         case AssignmentOp::AdditionAssignment:
         case AssignmentOp::AdditionAssignment:
-            generator.emit<Bytecode::Op::Add>(dst_reg, *lhs_reg, *rhs_reg);
+            generator.emit<Bytecode::Op::Add>(lhs_reg);
             break;
             break;
         case AssignmentOp::SubtractionAssignment:
         case AssignmentOp::SubtractionAssignment:
-            generator.emit<Bytecode::Op::Sub>(dst_reg, *lhs_reg, *rhs_reg);
+            generator.emit<Bytecode::Op::Sub>(lhs_reg);
             break;
             break;
         case AssignmentOp::MultiplicationAssignment:
         case AssignmentOp::MultiplicationAssignment:
-            generator.emit<Bytecode::Op::Mul>(dst_reg, *lhs_reg, *rhs_reg);
+            generator.emit<Bytecode::Op::Mul>(lhs_reg);
             break;
             break;
         case AssignmentOp::DivisionAssignment:
         case AssignmentOp::DivisionAssignment:
-            generator.emit<Bytecode::Op::Div>(dst_reg, *lhs_reg, *rhs_reg);
+            generator.emit<Bytecode::Op::Div>(lhs_reg);
             break;
             break;
         case AssignmentOp::ModuloAssignment:
         case AssignmentOp::ModuloAssignment:
-            generator.emit<Bytecode::Op::Mod>(dst_reg, *lhs_reg, *rhs_reg);
+            generator.emit<Bytecode::Op::Mod>(lhs_reg);
             break;
             break;
         case AssignmentOp::ExponentiationAssignment:
         case AssignmentOp::ExponentiationAssignment:
-            generator.emit<Bytecode::Op::Exp>(dst_reg, *lhs_reg, *rhs_reg);
+            generator.emit<Bytecode::Op::Exp>(lhs_reg);
             break;
             break;
         case AssignmentOp::BitwiseAndAssignment:
         case AssignmentOp::BitwiseAndAssignment:
-            generator.emit<Bytecode::Op::BitwiseAnd>(dst_reg, *lhs_reg, *rhs_reg);
+            generator.emit<Bytecode::Op::BitwiseAnd>(lhs_reg);
             break;
             break;
         case AssignmentOp::BitwiseOrAssignment:
         case AssignmentOp::BitwiseOrAssignment:
-            generator.emit<Bytecode::Op::BitwiseOr>(dst_reg, *lhs_reg, *rhs_reg);
+            generator.emit<Bytecode::Op::BitwiseOr>(lhs_reg);
             break;
             break;
         case AssignmentOp::BitwiseXorAssignment:
         case AssignmentOp::BitwiseXorAssignment:
-            generator.emit<Bytecode::Op::BitwiseXor>(dst_reg, *lhs_reg, *rhs_reg);
+            generator.emit<Bytecode::Op::BitwiseXor>(lhs_reg);
             break;
             break;
         case AssignmentOp::LeftShiftAssignment:
         case AssignmentOp::LeftShiftAssignment:
-            generator.emit<Bytecode::Op::LeftShift>(dst_reg, *lhs_reg, *rhs_reg);
+            generator.emit<Bytecode::Op::LeftShift>(lhs_reg);
             break;
             break;
         case AssignmentOp::RightShiftAssignment:
         case AssignmentOp::RightShiftAssignment:
-            generator.emit<Bytecode::Op::RightShift>(dst_reg, *lhs_reg, *rhs_reg);
+            generator.emit<Bytecode::Op::RightShift>(lhs_reg);
             break;
             break;
         case AssignmentOp::UnsignedRightShiftAssignment:
         case AssignmentOp::UnsignedRightShiftAssignment:
-            generator.emit<Bytecode::Op::UnsignedRightShift>(dst_reg, *lhs_reg, *rhs_reg);
+            generator.emit<Bytecode::Op::UnsignedRightShift>(lhs_reg);
             break;
             break;
         default:
         default:
             TODO();
             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)) {
     if (is<MemberExpression>(*m_lhs)) {
         auto& expression = static_cast<MemberExpression const&>(*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()) {
         if (expression.is_computed()) {
             TODO();
             TODO();
         } else {
         } else {
             VERIFY(is<Identifier>(expression.property()));
             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();
     TODO();
 }
 }
 
 
-Optional<Bytecode::Register> WhileStatement::generate_bytecode(Bytecode::Generator& generator) const
+void WhileStatement::generate_bytecode(Bytecode::Generator& generator) const
 {
 {
     generator.begin_continuable_scope();
     generator.begin_continuable_scope();
     auto test_label = generator.make_label();
     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);
     generator.emit<Bytecode::Op::Jump>(test_label);
     test_jump.set_target(generator.make_label());
     test_jump.set_target(generator.make_label());
     generator.end_continuable_scope();
     generator.end_continuable_scope();
-    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();
     generator.begin_continuable_scope();
     auto head_label = generator.make_label();
     auto head_label = generator.make_label();
-    auto body_result_reg = m_body->generate_bytecode(generator);
+    m_body->generate_bytecode(generator);
     generator.end_continuable_scope();
     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 };
     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();
     generator.begin_continuable_scope();
     auto jump_label = generator.make_label();
     auto jump_label = generator.make_label();
     if (m_test) {
     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);
     generator.emit<Bytecode::Op::Jump>(jump_label);
     if (m_test)
     if (m_test)
         test_jump->set_target(generator.make_label());
         test_jump->set_target(generator.make_label());
     generator.end_continuable_scope();
     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();
         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()) {
     if (is_computed()) {
         TODO();
         TODO();
     } else {
     } else {
         VERIFY(is<Identifier>(property()));
         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'.
     // FIXME: Load the correct 'this' value into 'this_reg'.
     auto this_reg = generator.allocate_register();
     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;
     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);
-
-    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>();
+    m_predicate->generate_bytecode(generator);
+    auto& else_jump = generator.emit<Bytecode::Op::JumpIfFalse>();
 
 
-    else_jump.set_target(generator.make_label());
+    m_consequent->generate_bytecode(generator);
     if (m_alternate) {
     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 {
     } 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());
     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>();
     auto& end_jump = generator.emit<Bytecode::Op::Jump>();
 
 
     alternate_jump.set_target(generator.make_label());
     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());
     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)
     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;
-
-    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);
-    }
+    auto string_reg = generator.allocate_register();
 
 
-    if (!result_reg.has_value()) {
-        result_reg = generator.allocate_register();
-        generator.emit<Bytecode::Op::NewString>(*result_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);
+        }
     }
     }
-
-    return result_reg;
 }
 }
 
 
 }
 }

+ 1 - 1
Userland/Libraries/LibJS/Bytecode/Generator.cpp

@@ -26,7 +26,7 @@ Generator::~Generator()
 OwnPtr<Block> Generator::generate(ASTNode const& node)
 OwnPtr<Block> Generator::generate(ASTNode const& node)
 {
 {
     Generator generator;
     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->set_register_count({}, generator.m_next_register);
     generator.m_block->seal();
     generator.m_block->seal();
     return move(generator.m_block);
     return move(generator.m_block);

+ 5 - 3
Userland/Libraries/LibJS/Bytecode/Instruction.h

@@ -11,7 +11,8 @@
 
 
 #define ENUMERATE_BYTECODE_OPS(O) \
 #define ENUMERATE_BYTECODE_OPS(O) \
     O(Load)                       \
     O(Load)                       \
-    O(LoadRegister)               \
+    O(LoadImmediate)              \
+    O(Store)                      \
     O(Add)                        \
     O(Add)                        \
     O(Sub)                        \
     O(Sub)                        \
     O(Mul)                        \
     O(Mul)                        \
@@ -36,7 +37,7 @@
     O(Jump)                       \
     O(Jump)                       \
     O(JumpIfFalse)                \
     O(JumpIfFalse)                \
     O(JumpIfTrue)                 \
     O(JumpIfTrue)                 \
-    O(JumpIfNullish)              \
+    O(JumpIfNotNullish)           \
     O(Call)                       \
     O(Call)                       \
     O(EnterScope)                 \
     O(EnterScope)                 \
     O(Return)                     \
     O(Return)                     \
@@ -52,7 +53,8 @@
     O(RightShift)                 \
     O(RightShift)                 \
     O(UnsignedRightShift)         \
     O(UnsignedRightShift)         \
     O(In)                         \
     O(In)                         \
-    O(InstanceOf)
+    O(InstanceOf)                 \
+    O(ConcatString)
 
 
 namespace JS::Bytecode {
 namespace JS::Bytecode {
 
 

+ 1 - 0
Userland/Libraries/LibJS/Bytecode/Interpreter.h

@@ -30,6 +30,7 @@ public:
 
 
     Value run(Bytecode::Block const&);
     Value run(Bytecode::Block const&);
 
 
+    ALWAYS_INLINE Value& accumulator() { return reg(Register::accumulator()); }
     Value& reg(Register const& r) { return registers()[r.index()]; }
     Value& reg(Register const& r) { return registers()[r.index()]; }
 
 
     void jump(Label const& label) { m_pending_jump = label.address(); }
     void jump(Label const& label) { m_pending_jump = label.address(); }

+ 74 - 55
Userland/Libraries/LibJS/Bytecode/Op.cpp

@@ -51,12 +51,17 @@ namespace JS::Bytecode::Op {
 
 
 void Load::execute(Bytecode::Interpreter& interpreter) const
 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)
 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));
     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)
 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());
     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)
 JS_ENUMERATE_COMMON_UNARY_OPS(JS_DEFINE_COMMON_UNARY_OP)
 
 
 void NewBigInt::execute(Bytecode::Interpreter& interpreter) const
 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
 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
 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
 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
 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
 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
 void PutById::execute(Bytecode::Interpreter& interpreter) const
 {
 {
     if (auto* object = interpreter.reg(m_base).to_object(interpreter.global_object()))
     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
 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
 void JumpIfFalse::execute(Bytecode::Interpreter& interpreter) const
 {
 {
     VERIFY(m_target.has_value());
     VERIFY(m_target.has_value());
-    auto result = interpreter.reg(m_result);
+    auto result = interpreter.accumulator();
     if (!result.to_boolean())
     if (!result.to_boolean())
         interpreter.jump(m_target.value());
         interpreter.jump(m_target.value());
 }
 }
@@ -166,16 +178,16 @@ void JumpIfFalse::execute(Bytecode::Interpreter& interpreter) const
 void JumpIfTrue::execute(Bytecode::Interpreter& interpreter) const
 void JumpIfTrue::execute(Bytecode::Interpreter& interpreter) const
 {
 {
     VERIFY(m_target.has_value());
     VERIFY(m_target.has_value());
-    auto result = interpreter.reg(m_result);
+    auto result = interpreter.accumulator();
     if (result.to_boolean())
     if (result.to_boolean())
         interpreter.jump(m_target.value());
         interpreter.jump(m_target.value());
 }
 }
 
 
-void JumpIfNullish::execute(Bytecode::Interpreter& interpreter) const
+void JumpIfNotNullish::execute(Bytecode::Interpreter& interpreter) const
 {
 {
     VERIFY(m_target.has_value());
     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());
         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));
         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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 String Jump::to_string() const
@@ -280,28 +301,28 @@ String Jump::to_string() const
 String JumpIfFalse::to_string() const
 String JumpIfFalse::to_string() const
 {
 {
     if (m_target.has_value())
     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
 String JumpIfTrue::to_string() const
 {
 {
     if (m_target.has_value())
     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())
     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
 String Call::to_string() const
 {
 {
     StringBuilder builder;
     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) {
     if (m_argument_count != 0) {
         builder.append(", arguments:[");
         builder.append(", arguments:[");
         for (size_t i = 0; i < m_argument_count; ++i) {
         for (size_t i = 0; i < m_argument_count; ++i) {
@@ -321,8 +342,6 @@ String EnterScope::to_string() const
 
 
 String Return::to_string() const
 String Return::to_string() const
 {
 {
-    if (m_argument.has_value())
-        return String::formatted("Return {}", m_argument.value());
     return "Return";
     return "Return";
 }
 }
 
 

+ 52 - 72
Userland/Libraries/LibJS/Bytecode/Op.h

@@ -19,9 +19,23 @@ namespace JS::Bytecode::Op {
 
 
 class Load final : public Instruction {
 class Load final : public Instruction {
 public:
 public:
-    Load(Register dst, Value value)
+    Load(Register src)
         : Instruction(Type::Load)
         : Instruction(Type::Load)
-        , m_dst(dst)
+        , m_src(src)
+    {
+    }
+
+    void execute(Bytecode::Interpreter&) const;
+    String to_string() const;
+
+private:
+    Register m_src;
+};
+
+class LoadImmediate final : public Instruction {
+public:
+    LoadImmediate(Value value)
+        : Instruction(Type::LoadImmediate)
         , m_value(value)
         , m_value(value)
     {
     {
     }
     }
@@ -30,16 +44,14 @@ public:
     String to_string() const;
     String to_string() const;
 
 
 private:
 private:
-    Register m_dst;
     Value m_value;
     Value m_value;
 };
 };
 
 
-class LoadRegister final : public Instruction {
+class Store final : public Instruction {
 public:
 public:
-    LoadRegister(Register dst, Register src)
-        : Instruction(Type::LoadRegister)
+    Store(Register dst)
+        : Instruction(Type::Store)
         , m_dst(dst)
         , m_dst(dst)
-        , m_src(src)
     {
     {
     }
     }
 
 
@@ -48,7 +60,6 @@ public:
 
 
 private:
 private:
     Register m_dst;
     Register m_dst;
-    Register m_src;
 };
 };
 
 
 #define JS_ENUMERATE_COMMON_BINARY_OPS(O)     \
 #define JS_ENUMERATE_COMMON_BINARY_OPS(O)     \
@@ -78,11 +89,9 @@ private:
 #define JS_DECLARE_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \
 #define JS_DECLARE_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \
     class OpTitleCase final : public Instruction {              \
     class OpTitleCase final : public Instruction {              \
     public:                                                     \
     public:                                                     \
-        OpTitleCase(Register dst, Register src1, Register src2) \
+        OpTitleCase(Register lhs_reg)                           \
             : Instruction(Type::OpTitleCase)                    \
             : 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;                               \
         String to_string() const;                               \
                                                                 \
                                                                 \
     private:                                                    \
     private:                                                    \
-        Register m_dst;                                         \
-        Register m_src1;                                        \
-        Register m_src2;                                        \
+        Register m_lhs_reg;                                     \
     };
     };
 
 
 JS_ENUMERATE_COMMON_BINARY_OPS(JS_DECLARE_COMMON_BINARY_OP)
 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) \
 #define JS_DECLARE_COMMON_UNARY_OP(OpTitleCase, op_snake_case) \
     class OpTitleCase final : public Instruction {             \
     class OpTitleCase final : public Instruction {             \
     public:                                                    \
     public:                                                    \
-        OpTitleCase(Register dst, Register src)                \
+        OpTitleCase()                                          \
             : Instruction(Type::OpTitleCase)                   \
             : Instruction(Type::OpTitleCase)                   \
-            , m_dst(dst)                                       \
-            , m_src(src)                                       \
         {                                                      \
         {                                                      \
         }                                                      \
         }                                                      \
                                                                \
                                                                \
         void execute(Bytecode::Interpreter&) const;            \
         void execute(Bytecode::Interpreter&) const;            \
         String to_string() const;                              \
         String to_string() const;                              \
-                                                               \
-    private:                                                   \
-        Register m_dst;                                        \
-        Register m_src;                                        \
     };
     };
 
 
 JS_ENUMERATE_COMMON_UNARY_OPS(JS_DECLARE_COMMON_UNARY_OP)
 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 {
 class NewString final : public Instruction {
 public:
 public:
-    NewString(Register dst, String string)
+    NewString(String string)
         : Instruction(Type::NewString)
         : Instruction(Type::NewString)
-        , m_dst(dst)
         , m_string(move(string))
         , m_string(move(string))
     {
     {
     }
     }
@@ -139,30 +139,24 @@ public:
     String to_string() const;
     String to_string() const;
 
 
 private:
 private:
-    Register m_dst;
     String m_string;
     String m_string;
 };
 };
 
 
 class NewObject final : public Instruction {
 class NewObject final : public Instruction {
 public:
 public:
-    explicit NewObject(Register dst)
+    NewObject()
         : Instruction(Type::NewObject)
         : Instruction(Type::NewObject)
-        , m_dst(dst)
     {
     {
     }
     }
 
 
     void execute(Bytecode::Interpreter&) const;
     void execute(Bytecode::Interpreter&) const;
     String to_string() const;
     String to_string() const;
-
-private:
-    Register m_dst;
 };
 };
 
 
 class NewBigInt final : public Instruction {
 class NewBigInt final : public Instruction {
 public:
 public:
-    explicit NewBigInt(Register dst, Crypto::SignedBigInteger bigint)
+    explicit NewBigInt(Crypto::SignedBigInteger bigint)
         : Instruction(Type::NewBigInt)
         : Instruction(Type::NewBigInt)
-        , m_dst(dst)
         , m_bigint(move(bigint))
         , m_bigint(move(bigint))
     {
     {
     }
     }
@@ -171,16 +165,29 @@ public:
     String to_string() const;
     String to_string() const;
 
 
 private:
 private:
-    Register m_dst;
     Crypto::SignedBigInteger m_bigint;
     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 {
 class SetVariable final : public Instruction {
 public:
 public:
-    SetVariable(FlyString identifier, Register src)
+    SetVariable(FlyString identifier)
         : Instruction(Type::SetVariable)
         : Instruction(Type::SetVariable)
         , m_identifier(move(identifier))
         , m_identifier(move(identifier))
-        , m_src(src)
     {
     {
     }
     }
 
 
@@ -189,14 +196,12 @@ public:
 
 
 private:
 private:
     FlyString m_identifier;
     FlyString m_identifier;
-    Register m_src;
 };
 };
 
 
 class GetVariable final : public Instruction {
 class GetVariable final : public Instruction {
 public:
 public:
-    GetVariable(Register dst, FlyString identifier)
+    GetVariable(FlyString identifier)
         : Instruction(Type::GetVariable)
         : Instruction(Type::GetVariable)
-        , m_dst(dst)
         , m_identifier(move(identifier))
         , m_identifier(move(identifier))
     {
     {
     }
     }
@@ -205,16 +210,13 @@ public:
     String to_string() const;
     String to_string() const;
 
 
 private:
 private:
-    Register m_dst;
     FlyString m_identifier;
     FlyString m_identifier;
 };
 };
 
 
 class GetById final : public Instruction {
 class GetById final : public Instruction {
 public:
 public:
-    GetById(Register dst, Register base, FlyString property)
+    GetById(FlyString property)
         : Instruction(Type::GetById)
         : Instruction(Type::GetById)
-        , m_dst(dst)
-        , m_base(base)
         , m_property(move(property))
         , m_property(move(property))
     {
     {
     }
     }
@@ -223,18 +225,15 @@ public:
     String to_string() const;
     String to_string() const;
 
 
 private:
 private:
-    Register m_dst;
-    Register m_base;
     FlyString m_property;
     FlyString m_property;
 };
 };
 
 
 class PutById final : public Instruction {
 class PutById final : public Instruction {
 public:
 public:
-    PutById(Register base, FlyString property, Register src)
+    PutById(Register base, FlyString property)
         : Instruction(Type::PutById)
         : Instruction(Type::PutById)
         , m_base(base)
         , m_base(base)
         , m_property(move(property))
         , m_property(move(property))
-        , m_src(src)
     {
     {
     }
     }
 
 
@@ -244,7 +243,6 @@ public:
 private:
 private:
     Register m_base;
     Register m_base;
     FlyString m_property;
     FlyString m_property;
-    Register m_src;
 };
 };
 
 
 class Jump : public Instruction {
 class Jump : public Instruction {
@@ -272,55 +270,42 @@ protected:
 
 
 class JumpIfFalse final : public Jump {
 class JumpIfFalse final : public Jump {
 public:
 public:
-    explicit JumpIfFalse(Register result, Optional<Label> target = {})
+    explicit JumpIfFalse(Optional<Label> target = {})
         : Jump(Type::JumpIfFalse, move(target))
         : Jump(Type::JumpIfFalse, move(target))
-        , m_result(result)
     {
     {
     }
     }
 
 
     void execute(Bytecode::Interpreter&) const;
     void execute(Bytecode::Interpreter&) const;
     String to_string() const;
     String to_string() const;
-
-private:
-    Register m_result;
 };
 };
 
 
 class JumpIfTrue : public Jump {
 class JumpIfTrue : public Jump {
 public:
 public:
-    explicit JumpIfTrue(Register result, Optional<Label> target = {})
+    explicit JumpIfTrue(Optional<Label> target = {})
         : Jump(Type::JumpIfTrue, move(target))
         : Jump(Type::JumpIfTrue, move(target))
-        , m_result(result)
     {
     {
     }
     }
 
 
     void execute(Bytecode::Interpreter&) const;
     void execute(Bytecode::Interpreter&) const;
     String to_string() const;
     String to_string() const;
-
-private:
-    Register m_result;
 };
 };
 
 
-class JumpIfNullish final : public Jump {
+class JumpIfNotNullish final : public Jump {
 public:
 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;
     void execute(Bytecode::Interpreter&) const;
     String to_string() const;
     String to_string() const;
-
-private:
-    Register m_result;
 };
 };
 
 
 // NOTE: This instruction is variable-width depending on the number of arguments!
 // NOTE: This instruction is variable-width depending on the number of arguments!
 class Call final : public Instruction {
 class Call final : public Instruction {
 public:
 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)
         : Instruction(Type::Call)
-        , m_dst(dst)
         , m_callee(callee)
         , m_callee(callee)
         , m_this_value(this_value)
         , m_this_value(this_value)
         , m_argument_count(arguments.size())
         , m_argument_count(arguments.size())
@@ -335,7 +320,6 @@ public:
     size_t length() const { return sizeof(*this) + sizeof(Register) * m_argument_count; }
     size_t length() const { return sizeof(*this) + sizeof(Register) * m_argument_count; }
 
 
 private:
 private:
-    Register m_dst;
     Register m_callee;
     Register m_callee;
     Register m_this_value;
     Register m_this_value;
     size_t m_argument_count { 0 };
     size_t m_argument_count { 0 };
@@ -359,17 +343,13 @@ private:
 
 
 class Return final : public Instruction {
 class Return final : public Instruction {
 public:
 public:
-    explicit Return(Optional<Register> argument)
+    Return()
         : Instruction(Type::Return)
         : Instruction(Type::Return)
-        , m_argument(move(argument))
     {
     {
     }
     }
 
 
     void execute(Bytecode::Interpreter&) const;
     void execute(Bytecode::Interpreter&) const;
     String to_string() const;
     String to_string() const;
-
-private:
-    Optional<Register> m_argument;
 };
 };
 
 
 }
 }

+ 11 - 1
Userland/Libraries/LibJS/Bytecode/Register.h

@@ -12,6 +12,14 @@ namespace JS::Bytecode {
 
 
 class Register {
 class Register {
 public:
 public:
+    constexpr static u32 accumulator_index = 0;
+
+    static Register accumulator()
+    {
+        static Register accumulator(accumulator_index);
+        return accumulator;
+    }
+
     explicit Register(u32 index)
     explicit Register(u32 index)
         : m_index(index)
         : m_index(index)
     {
     {
@@ -20,7 +28,7 @@ public:
     u32 index() const { return m_index; }
     u32 index() const { return m_index; }
 
 
 private:
 private:
-    u32 m_index { 0 };
+    u32 m_index;
 };
 };
 
 
 }
 }
@@ -29,6 +37,8 @@ template<>
 struct AK::Formatter<JS::Bytecode::Register> : AK::Formatter<FormatString> {
 struct AK::Formatter<JS::Bytecode::Register> : AK::Formatter<FormatString> {
     void format(FormatBuilder& builder, JS::Bytecode::Register const& value)
     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());
         return AK::Formatter<FormatString>::format(builder, "${}", value.index());
     }
     }
 };
 };