diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 986e84de8ab..cf907280c77 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -340,9 +340,10 @@ CodeGenerationErrorOr> Generator::compile(VM& vm, ASTNo while (!it.at_end()) { auto& instruction = const_cast(*it); - // OPTIMIZATION: Don't emit jumps that just jump to the next block. if (instruction.type() == Instruction::Type::Jump) { auto& jump = static_cast(instruction); + + // OPTIMIZATION: Don't emit jumps that just jump to the next block. if (jump.target().basic_block_index() == block->index() + 1) { if (basic_block_start_offsets.last() == bytecode.size()) { // This block is empty, just skip it. @@ -351,6 +352,29 @@ CodeGenerationErrorOr> Generator::compile(VM& vm, ASTNo ++it; continue; } + + // OPTIMIZATION: For jumps to a return-or-end-only block, we can emit a `Return` or `End` directly instead. + auto& target_block = *generator.m_root_basic_blocks[jump.target().basic_block_index()]; + if (target_block.is_terminated()) { + auto target_instruction_iterator = InstructionStreamIterator { target_block.instruction_stream() }; + auto& target_instruction = *target_instruction_iterator; + + if (target_instruction.type() == Instruction::Type::Return) { + auto& return_instruction = static_cast(target_instruction); + Op::Return return_op(return_instruction.value()); + bytecode.append(reinterpret_cast(&return_op), return_op.length()); + ++it; + continue; + } + + if (target_instruction.type() == Instruction::Type::End) { + auto& return_instruction = static_cast(target_instruction); + Op::End end_op(return_instruction.value()); + bytecode.append(reinterpret_cast(&end_op), end_op.length()); + ++it; + continue; + } + } } // OPTIMIZATION: For `JumpIf` where one of the targets is the very next block,