diff options
author | Gunnar Beutner <gbeutner@serenityos.org> | 2021-06-08 02:18:47 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-06-08 10:42:45 +0200 |
commit | 6da587b59b5b96517adddef7b738d7092aec8783 (patch) | |
tree | a747003677f9dbe6eedef8089ec0411381238e2d /Userland | |
parent | 216d27d4c13be78a859b8bcc7a1abc555a58f322 (diff) | |
download | serenity-6da587b59b5b96517adddef7b738d7092aec8783.zip |
LibJS: Implement bytecode ops for logical expressions
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibJS/AST.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp | 47 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Instruction.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Op.cpp | 15 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Op.h | 19 |
5 files changed, 83 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index 15a792c9fd..8a10cd9fc4 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -557,6 +557,7 @@ public: virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; + virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override; private: LogicalOp m_op; diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 41e2da493e..7c808aaee7 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -121,6 +121,53 @@ Optional<Bytecode::Register> BinaryExpression::generate_bytecode(Bytecode::Gener } } +Optional<Bytecode::Register> LogicalExpression::generate_bytecode(Bytecode::Generator& generator) const +{ + auto result_reg = generator.allocate_register(); + auto lhs_reg = m_lhs->generate_bytecode(generator); + + Bytecode::Instruction* test_instr; + switch (m_op) { + case LogicalOp::And: + test_instr = &generator.emit<Bytecode::Op::JumpIfTrue>(*lhs_reg); + break; + case LogicalOp::Or: + test_instr = &generator.emit<Bytecode::Op::JumpIfFalse>(*lhs_reg); + break; + case LogicalOp::NullishCoalescing: + test_instr = &generator.emit<Bytecode::Op::JumpIfNullish>(*lhs_reg); + break; + default: + VERIFY_NOT_REACHED(); + } + + generator.emit<Bytecode::Op::LoadRegister>(result_reg, *lhs_reg); + auto& end_jump = generator.emit<Bytecode::Op::Jump>(); + + auto rhs_label = generator.make_label(); + + switch (m_op) { + case LogicalOp::And: + static_cast<Bytecode::Op::JumpIfTrue*>(test_instr)->set_target(rhs_label); + break; + case LogicalOp::Or: + static_cast<Bytecode::Op::JumpIfFalse*>(test_instr)->set_target(rhs_label); + break; + case LogicalOp::NullishCoalescing: + static_cast<Bytecode::Op::JumpIfNullish*>(test_instr)->set_target(rhs_label); + break; + default: + VERIFY_NOT_REACHED(); + } + + 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; +} + Optional<Bytecode::Register> UnaryExpression::generate_bytecode(Bytecode::Generator& generator) const { auto lhs_reg = m_lhs->generate_bytecode(generator); diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index 11d0bf2978..5679c47a92 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -35,6 +35,7 @@ O(Jump) \ O(JumpIfFalse) \ O(JumpIfTrue) \ + O(JumpIfNullish) \ O(Call) \ O(EnterScope) \ O(Return) \ diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index e3d7a997e1..32057060f5 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -165,6 +165,14 @@ void JumpIfTrue::execute(Bytecode::Interpreter& interpreter) const interpreter.jump(m_target.value()); } +void JumpIfNullish::execute(Bytecode::Interpreter& interpreter) const +{ + VERIFY(m_target.has_value()); + auto result = interpreter.reg(m_result); + if (result.is_nullish()) + interpreter.jump(m_target.value()); +} + void Call::execute(Bytecode::Interpreter& interpreter) const { auto callee = interpreter.reg(m_callee); @@ -272,6 +280,13 @@ String JumpIfTrue::to_string() const return String::formatted("JumpIfTrue result:{}, target:<empty>", m_result); } +String JumpIfNullish::to_string() const +{ + if (m_target.has_value()) + return String::formatted("JumpIfNullish result:{}, target:{}", m_result, m_target.value()); + return String::formatted("JumpIfNullish result:{}, target:<empty>", m_result); +} + String Call::to_string() const { StringBuilder builder; diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 735dcbf331..d60138196c 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -284,6 +284,25 @@ private: Optional<Label> m_target; }; +class JumpIfNullish final : public Instruction { +public: + explicit JumpIfNullish(Register result, Optional<Label> target = {}) + : Instruction(Type::JumpIfNullish) + , m_result(result) + , m_target(move(target)) + { + } + + void set_target(Optional<Label> target) { m_target = move(target); } + + void execute(Bytecode::Interpreter&) const; + String to_string() const; + +private: + Register m_result; + Optional<Label> m_target; +}; + // NOTE: This instruction is variable-width depending on the number of arguments! class Call final : public Instruction { public: |