From 79eac08f5bc9850749a3280d517649a1d0c9933a Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 6 Jun 2021 13:26:50 +0200 Subject: LibJS: Add basic "if" statement support to the bytecode VM :^) This also required making Bytecode::Op::Jump support lazy linking to a target label. I left a FIXME here about having the "if" statement return the result value from the taken branch statement. That's what the AST interpreter does but I'm not sure if it's actually required. --- Userland/Libraries/LibJS/AST.h | 1 + Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp | 22 ++++++++++++++++++++++ Userland/Libraries/LibJS/Bytecode/Op.cpp | 4 ++-- Userland/Libraries/LibJS/Bytecode/Op.h | 8 +++++--- 4 files changed, 30 insertions(+), 5 deletions(-) (limited to 'Userland') diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index 4e156ef655..5dc8e73911 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -351,6 +351,7 @@ public: virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; + virtual Optional generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr m_predicate; diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 18d4e24700..e53658f2ca 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -187,4 +187,26 @@ Optional ReturnStatement::generate_bytecode(Bytecode::Genera return argument_reg; } +Optional IfStatement::generate_bytecode(Bytecode::Generator& generator) const +{ + auto predicate_reg = m_predicate->generate_bytecode(generator); + auto& if_jump = generator.emit(*predicate_reg); + auto& else_jump = generator.emit(*predicate_reg); + + if_jump.set_target(generator.make_label()); + (void)m_consequent->generate_bytecode(generator); + auto& end_jump = generator.emit(); + + else_jump.set_target(generator.make_label()); + if (m_alternate) { + (void)m_alternate->generate_bytecode(generator); + } + + end_jump.set_target(generator.make_label()); + + // FIXME: Do we need IfStatement to return the consequent/alternate result value? + // (That's what the AST interpreter currently does) + return {}; +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index 869dd169ce..0297533b11 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -72,7 +72,7 @@ void PutById::execute(Bytecode::Interpreter& interpreter) const void Jump::execute(Bytecode::Interpreter& interpreter) const { - interpreter.jump(m_target); + interpreter.jump(*m_target); } void JumpIfFalse::execute(Bytecode::Interpreter& interpreter) const @@ -196,7 +196,7 @@ String GetById::to_string() const String Jump::to_string() const { - return String::formatted("Jump {}", m_target); + return String::formatted("Jump {}", *m_target); } String JumpIfFalse::to_string() const diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 1d57fed10b..9769a6b5a6 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -214,17 +214,19 @@ private: class Jump final : public Instruction { public: - explicit Jump(Label target) - : m_target(target) + explicit Jump(Optional