浏览代码

LibJS/Bytecode: Don't fuse unrelated compare and jump in peephole pass

Fixes an issue where https://x.com/awesomekling crashed on load. :^)
Andreas Kling 1 年之前
父节点
当前提交
c1dbde72e9
共有 2 个文件被更改,包括 28 次插入21 次删除
  1. 18 21
      Userland/Libraries/LibJS/Bytecode/Pass/Peephole.cpp
  2. 10 0
      Userland/Libraries/LibJS/Tests/optimizer-bugs.js

+ 18 - 21
Userland/Libraries/LibJS/Bytecode/Pass/Peephole.cpp

@@ -40,32 +40,29 @@ void Peephole::perform(PassPipelineExecutable& executable)
 
                     if (instruction.type() == Instruction::Type::Not) {
                         auto const& not_ = static_cast<Op::Not const&>(instruction);
-                        VERIFY(jump.condition() == not_.dst());
-                        new_block->append<Op::JumpIfNot>(
-                            not_.source_record().source_start_offset,
-                            not_.source_record().source_end_offset,
-                            not_.src(),
-                            *jump.true_target(),
-                            *jump.false_target());
-                        ++it;
-                        VERIFY(it.at_end());
-                        continue;
+                        if (jump.condition() != not_.dst()) {
+                            auto slot_offset = new_block->size();
+                            new_block->grow(not_.length());
+                            memcpy(new_block->data() + slot_offset, &not_, not_.length());
+                            continue;
+                        }
                     }
 
 #define DO_FUSE_JUMP(PreOp, ...)                                          \
     if (instruction.type() == Instruction::Type::PreOp) {                 \
         auto const& compare = static_cast<Op::PreOp const&>(instruction); \
-        VERIFY(jump.condition() == compare.dst());                        \
-        new_block->append<Op::Jump##PreOp>(                               \
-            compare.source_record().source_start_offset,                  \
-            compare.source_record().source_end_offset,                    \
-            compare.lhs(),                                                \
-            compare.rhs(),                                                \
-            *jump.true_target(),                                          \
-            *jump.false_target());                                        \
-        ++it;                                                             \
-        VERIFY(it.at_end());                                              \
-        continue;                                                         \
+        if (jump.condition() == compare.dst()) {                          \
+            new_block->append<Op::Jump##PreOp>(                           \
+                compare.source_record().source_start_offset,              \
+                compare.source_record().source_end_offset,                \
+                compare.lhs(),                                            \
+                compare.rhs(),                                            \
+                *jump.true_target(),                                      \
+                *jump.false_target());                                    \
+            ++it;                                                         \
+            VERIFY(it.at_end());                                          \
+            continue;                                                     \
+        }                                                                 \
     }
                     JS_ENUMERATE_FUSABLE_BINARY_OPS(DO_FUSE_JUMP)
                 }

+ 10 - 0
Userland/Libraries/LibJS/Tests/optimizer-bugs.js

@@ -0,0 +1,10 @@
+test("Don't fuse unrelated jump and compare", () => {
+    function go(a) {
+        a < 3;
+        a &&= 1;
+
+        a < 3;
+        a ||= 1;
+    }
+    go();
+});