From c1dbde72e963a3ed6e930b8e8e6a45c848dbb193 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 5 Mar 2024 12:47:48 +0100 Subject: [PATCH] LibJS/Bytecode: Don't fuse unrelated compare and jump in peephole pass Fixes an issue where https://x.com/awesomekling crashed on load. :^) --- .../LibJS/Bytecode/Pass/Peephole.cpp | 39 +++++++++---------- .../Libraries/LibJS/Tests/optimizer-bugs.js | 10 +++++ 2 files changed, 28 insertions(+), 21 deletions(-) create mode 100644 Userland/Libraries/LibJS/Tests/optimizer-bugs.js diff --git a/Userland/Libraries/LibJS/Bytecode/Pass/Peephole.cpp b/Userland/Libraries/LibJS/Bytecode/Pass/Peephole.cpp index 2c5b53693c67ff..cddae5da840ea3 100644 --- a/Userland/Libraries/LibJS/Bytecode/Pass/Peephole.cpp +++ b/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(instruction); - VERIFY(jump.condition() == not_.dst()); - new_block->append( - 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_.length()); + continue; + } } #define DO_FUSE_JUMP(PreOp, ...) \ if (instruction.type() == Instruction::Type::PreOp) { \ auto const& compare = static_cast(instruction); \ - VERIFY(jump.condition() == compare.dst()); \ - new_block->append( \ - 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( \ + 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) } diff --git a/Userland/Libraries/LibJS/Tests/optimizer-bugs.js b/Userland/Libraries/LibJS/Tests/optimizer-bugs.js new file mode 100644 index 00000000000000..c8c2d48d20fe72 --- /dev/null +++ b/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(); +});