瀏覽代碼

LibJS/Bytecode: Bunch all tests together in switch statement codegen

Before this change, switch codegen would interleave bytecode like this:

    (test for case 1)
    (code for case 1)
    (test for case 2)
    (code for case 2)

This meant that we often had to make many large jumps while looking for
the matching case, since code for each case can be huge.

It now looks like this instead:

    (test for case 1)
    (test for case 2)
    (code for case 1)
    (code for case 2)

This way, we can just fall through the tests until we hit one that fits,
without having to make any large jumps.
Andreas Kling 1 年之前
父節點
當前提交
f164e18a55
共有 1 個文件被更改,包括 8 次插入1 次删除
  1. 8 1
      Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

+ 8 - 1
Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

@@ -8,6 +8,7 @@
  */
  */
 
 
 #include <AK/Find.h>
 #include <AK/Find.h>
+#include <AK/Queue.h>
 #include <LibJS/AST.h>
 #include <LibJS/AST.h>
 #include <LibJS/Bytecode/Generator.h>
 #include <LibJS/Bytecode/Generator.h>
 #include <LibJS/Bytecode/Instruction.h>
 #include <LibJS/Bytecode/Instruction.h>
@@ -2586,6 +2587,12 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> SwitchStatement::genera
 
 
     generator.emit<Bytecode::Op::Jump>(Bytecode::Label { *next_test_block });
     generator.emit<Bytecode::Op::Jump>(Bytecode::Label { *next_test_block });
 
 
+    Queue<Bytecode::BasicBlock*> test_blocks;
+    for (auto& switch_case : m_cases) {
+        if (switch_case->test())
+            test_blocks.enqueue(&generator.make_block());
+    }
+
     for (auto& switch_case : m_cases) {
     for (auto& switch_case : m_cases) {
         auto& case_block = generator.make_block();
         auto& case_block = generator.make_block();
         if (switch_case->test()) {
         if (switch_case->test()) {
@@ -2593,7 +2600,7 @@ Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> SwitchStatement::genera
             auto test_value = TRY(switch_case->test()->generate_bytecode(generator)).value();
             auto test_value = TRY(switch_case->test()->generate_bytecode(generator)).value();
             auto result = generator.allocate_register();
             auto result = generator.allocate_register();
             generator.emit<Bytecode::Op::StrictlyEquals>(result, test_value, discriminant);
             generator.emit<Bytecode::Op::StrictlyEquals>(result, test_value, discriminant);
-            next_test_block = &generator.make_block();
+            next_test_block = test_blocks.dequeue();
             generator.emit<Bytecode::Op::JumpIf>(
             generator.emit<Bytecode::Op::JumpIf>(
                 result,
                 result,
                 Bytecode::Label { case_block },
                 Bytecode::Label { case_block },