diff --git a/Userland/Libraries/LibJIT/Assembler.h b/Userland/Libraries/LibJIT/Assembler.h index 0d2b393c80..539ae6125c 100644 --- a/Userland/Libraries/LibJIT/Assembler.h +++ b/Userland/Libraries/LibJIT/Assembler.h @@ -546,6 +546,28 @@ struct Assembler { } } + void mul32(Operand dest, Operand src, Optional overflow_label) + { + // imul32 dest, src (32-bit signed) + if (dest.type == Operand::Type::Reg && src.type == Operand::Type::Reg) { + emit_rex_for_rm(dest, src, REX_W::No); + emit8(0x0f); + emit8(0xaf); + emit_modrm_rm(dest, src); + } else if (dest.type == Operand::Type::Reg && src.type == Operand::Type::Mem64BaseAndOffset) { + emit_rex_for_rm(dest, src, REX_W::No); + emit8(0x0f); + emit8(0xaf); + emit_modrm_rm(dest, src); + } else { + VERIFY_NOT_REACHED(); + } + + if (overflow_label.has_value()) { + jump_if(Condition::Overflow, *overflow_label); + } + } + void enter() { push(Operand::Register(Reg::RBP)); diff --git a/Userland/Libraries/LibJS/JIT/Compiler.cpp b/Userland/Libraries/LibJS/JIT/Compiler.cpp index da18352acb..d55215f5d4 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.cpp +++ b/Userland/Libraries/LibJS/JIT/Compiler.cpp @@ -578,6 +578,48 @@ void Compiler::compile_sub(Bytecode::Op::Sub const& op) end.link(m_assembler); } +static Value cxx_mul(VM& vm, Value lhs, Value rhs) +{ + return TRY_OR_SET_EXCEPTION(mul(vm, lhs, rhs)); +} + +void Compiler::compile_mul(Bytecode::Op::Mul const& op) +{ + load_vm_register(ARG1, op.lhs()); + load_accumulator(ARG2); + + Assembler::Label end {}; + Assembler::Label slow_case {}; + + branch_if_both_int32(ARG1, ARG2, [&] { + // GPR0 = ARG1 * ARG2 (32-bit) + // if (overflow) goto slow_case; + m_assembler.mov( + Assembler::Operand::Register(GPR0), + Assembler::Operand::Register(ARG1)); + m_assembler.mul32( + Assembler::Operand::Register(GPR0), + Assembler::Operand::Register(ARG2), + 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)); + store_accumulator(GPR0); + m_assembler.jump(end); + }); + + slow_case.link(m_assembler); + native_call((void*)cxx_mul); + store_accumulator(RET); + check_exception(); + end.link(m_assembler); +} + static Value cxx_less_than(VM& vm, Value lhs, Value rhs) { return TRY_OR_SET_EXCEPTION(less_than(vm, lhs, rhs)); diff --git a/Userland/Libraries/LibJS/JIT/Compiler.h b/Userland/Libraries/LibJS/JIT/Compiler.h index 1be48841c5..b50446d6c9 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.h +++ b/Userland/Libraries/LibJS/JIT/Compiler.h @@ -41,7 +41,6 @@ private: # endif # define JS_ENUMERATE_COMMON_BINARY_OPS_WITHOUT_FAST_PATH(O) \ - O(Mul, mul) \ O(Div, div) \ O(Exp, exp) \ O(Mod, mod) \