From 5da94b30eb4e44faea83ee7633fb731e6612e9fe Mon Sep 17 00:00:00 2001 From: Luke Date: Wed, 9 Jun 2021 21:14:31 +0100 Subject: [PATCH] LibJS: Add logical assignment bytecode generation --- .../Libraries/LibJS/Bytecode/ASTCodegen.cpp | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 8daa80b2c1..2b8a566ab0 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -232,6 +232,39 @@ void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) con } m_lhs->generate_bytecode(generator); + + Bytecode::BasicBlock* rhs_block_ptr { nullptr }; + Bytecode::BasicBlock* end_block_ptr { nullptr }; + + // Logical assignments short circuit. + if (m_op == AssignmentOp::AndAssignment) { // &&= + rhs_block_ptr = &generator.make_block(); + end_block_ptr = &generator.make_block(); + + generator.emit().set_targets( + Bytecode::Label { *rhs_block_ptr }, + Bytecode::Label { *end_block_ptr }); + } else if (m_op == AssignmentOp::OrAssignment) { // ||= + rhs_block_ptr = &generator.make_block(); + end_block_ptr = &generator.make_block(); + + generator.emit().set_targets( + Bytecode::Label { *end_block_ptr }, + Bytecode::Label { *rhs_block_ptr }); + } else if (m_op == AssignmentOp::NullishAssignment) { // ??= + rhs_block_ptr = &generator.make_block(); + end_block_ptr = &generator.make_block(); + + generator.emit().set_targets( + Bytecode::Label { *rhs_block_ptr }, + Bytecode::Label { *end_block_ptr }); + } + + if (rhs_block_ptr) + generator.switch_to_basic_block(*rhs_block_ptr); + + // lhs_reg is a part of the rhs_block because the store isn't necessary + // if the logical assignment condition fails. auto lhs_reg = generator.allocate_register(); generator.emit(lhs_reg); m_rhs->generate_bytecode(generator); @@ -273,12 +306,24 @@ void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) con case AssignmentOp::UnsignedRightShiftAssignment: generator.emit(lhs_reg); break; + case AssignmentOp::AndAssignment: + case AssignmentOp::OrAssignment: + case AssignmentOp::NullishAssignment: + break; // These are handled above. default: TODO(); } generator.emit(generator.intern_string(identifier.string())); + if (end_block_ptr) { + generator.emit().set_targets( + Bytecode::Label { *end_block_ptr }, + {}); + + generator.switch_to_basic_block(*end_block_ptr); + } + return; }