Ver Fonte

LibJS/Bytecode: Rewrite Jump-to-Return-or-End as just Return or End

Instead of wasting time jumping to a shared Return or End instruction,
we can also emit a Return or End directly in many cases.
Andreas Kling há 1 ano atrás
pai
commit
044539c60b
1 ficheiros alterados com 25 adições e 1 exclusões
  1. 25 1
      Userland/Libraries/LibJS/Bytecode/Generator.cpp

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

@@ -340,9 +340,10 @@ CodeGenerationErrorOr<NonnullGCPtr<Executable>> Generator::compile(VM& vm, ASTNo
         while (!it.at_end()) {
             auto& instruction = const_cast<Instruction&>(*it);
 
-            // OPTIMIZATION: Don't emit jumps that just jump to the next block.
             if (instruction.type() == Instruction::Type::Jump) {
                 auto& jump = static_cast<Bytecode::Op::Jump&>(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<NonnullGCPtr<Executable>> 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<Bytecode::Op::Return const&>(target_instruction);
+                        Op::Return return_op(return_instruction.value());
+                        bytecode.append(reinterpret_cast<u8 const*>(&return_op), return_op.length());
+                        ++it;
+                        continue;
+                    }
+
+                    if (target_instruction.type() == Instruction::Type::End) {
+                        auto& return_instruction = static_cast<Bytecode::Op::End const&>(target_instruction);
+                        Op::End end_op(return_instruction.value());
+                        bytecode.append(reinterpret_cast<u8 const*>(&end_op), end_op.length());
+                        ++it;
+                        continue;
+                    }
+                }
             }
 
             // OPTIMIZATION: For `JumpIf` where one of the targets is the very next block,