diff --git a/Userland/Libraries/LibJIT/X86_64/Assembler.h b/Userland/Libraries/LibJIT/X86_64/Assembler.h index 15ed60afe78..a0cc5c69150 100644 --- a/Userland/Libraries/LibJIT/X86_64/Assembler.h +++ b/Userland/Libraries/LibJIT/X86_64/Assembler.h @@ -757,6 +757,21 @@ struct X86_64Assembler { } } + void dec32(Operand op, Optional overflow_label) + { + if (op.is_register_or_memory()) { + emit_rex_for_slash(op, REX_W::No); + emit8(0xff); + emit_modrm_slash(1, op); + } else { + VERIFY_NOT_REACHED(); + } + + if (overflow_label.has_value()) { + jump_if(Condition::Overflow, *overflow_label); + } + } + void add(Operand dst, Operand src) { if (dst.is_register_or_memory() && src.type == Operand::Type::Reg) { diff --git a/Userland/Libraries/LibJS/JIT/Compiler.cpp b/Userland/Libraries/LibJS/JIT/Compiler.cpp index 2d419b4da45..59416c1ebb6 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.cpp +++ b/Userland/Libraries/LibJS/JIT/Compiler.cpp @@ -396,9 +396,41 @@ static Value cxx_decrement(VM& vm, Value value) void Compiler::compile_decrement(Bytecode::Op::Decrement const&) { load_accumulator(ARG1); + + Assembler::Label end {}; + Assembler::Label slow_case {}; + + branch_if_int32(ARG1, [&] { + // GPR0 = ARG1; + m_assembler.mov( + Assembler::Operand::Register(GPR0), + Assembler::Operand::Register(ARG1)); + + // GPR0--; + m_assembler.dec32( + Assembler::Operand::Register(GPR0), + slow_case); + + // accumulator = GPR0 | SHIFTED_INT32_TAG; + m_assembler.mov( + Assembler::Operand::Register(GPR1), + Assembler::Operand::Imm(SHIFTED_INT32_TAG)); + m_assembler.bitwise_or( + Assembler::Operand::Register(GPR0), + Assembler::Operand::Register(GPR1)); + + // accumulator = GPR0; + store_accumulator(GPR0); + + m_assembler.jump(end); + }); + + slow_case.link(m_assembler); native_call((void*)cxx_decrement); store_accumulator(RET); check_exception(); + + end.link(m_assembler); } void Compiler::check_exception()