diff --git a/Userland/Libraries/LibJS/JIT/Assembler.h b/Userland/Libraries/LibJS/JIT/Assembler.h index 773fe78337..72d9bfcb4e 100644 --- a/Userland/Libraries/LibJS/JIT/Assembler.h +++ b/Userland/Libraries/LibJS/JIT/Assembler.h @@ -204,6 +204,14 @@ struct Assembler { return make_label(); } + void jump(Label& label) + { + // jmp target (RIP-relative 32-bit offset) + emit8(0xe9); + emit32(0xdeadbeef); + label.offset_in_instruction_stream = m_output.size(); + } + void jump(Operand op) { if (op.type == Operand::Type::Reg) { @@ -309,6 +317,25 @@ struct Assembler { } } + void bitwise_or(Operand dst, Operand src) + { + // or dst,src + if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Reg) { + emit8(0x48 + | ((to_underlying(src.reg) >= 8) ? 1 << 2 : 0) + | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0)); + emit8(0x09); + emit8(0xc0 | (encode_reg(src.reg) << 3) | encode_reg(dst.reg)); + } else if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Imm32) { + emit8(0x48 | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0)); + emit8(0x81); + emit8(0xc8 | encode_reg(dst.reg)); + emit32(src.offset_or_immediate); + } else { + VERIFY_NOT_REACHED(); + } + } + void enter() { push_callee_saved_registers(); @@ -459,6 +486,12 @@ struct Assembler { pop(Operand::Register(Reg::RDX)); pop(Operand::Register(Reg::RCX)); } + + void trap() + { + // int3 + emit8(0xcc); + } }; } diff --git a/Userland/Libraries/LibJS/JIT/Compiler.cpp b/Userland/Libraries/LibJS/JIT/Compiler.cpp index 66d376c805..ac862e309d 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.cpp +++ b/Userland/Libraries/LibJS/JIT/Compiler.cpp @@ -162,18 +162,81 @@ void Compiler::compile_jump_conditional(Bytecode::Op::JumpConditional const& op) [[maybe_unused]] static Value cxx_increment(VM& vm, Value value) { + dbgln("cxx_increment {}", value); auto old_value = TRY_OR_SET_EXCEPTION(value.to_numeric(vm)); if (old_value.is_number()) return Value(old_value.as_double() + 1); return BigInt::create(vm, old_value.as_bigint().big_integer().plus(Crypto::SignedBigInteger { 1 })); } +template +void Compiler::branch_if_int32(Assembler::Reg reg, Codegen codegen) +{ + // GPR0 = reg >> 48; + m_assembler.mov(Assembler::Operand::Register(GPR0), Assembler::Operand::Register(reg)); + m_assembler.shift_right(Assembler::Operand::Register(GPR0), Assembler::Operand::Imm8(48)); + + auto not_int32_case = m_assembler.make_label(); + m_assembler.jump_if_not_equal( + Assembler::Operand::Register(GPR0), + Assembler::Operand::Imm32(INT32_TAG), + not_int32_case); + + codegen(); + + not_int32_case.link(m_assembler); +} + void Compiler::compile_increment(Bytecode::Op::Increment const&) { load_vm_register(ARG1, Bytecode::Register::accumulator()); + + auto end = m_assembler.make_label(); + auto slow_case = m_assembler.make_label(); + + branch_if_int32(ARG1, [&] { + // GPR0 = ARG1 & 0xffffffff; + m_assembler.mov( + Assembler::Operand::Register(GPR0), + Assembler::Operand::Register(ARG1)); + m_assembler.mov( + Assembler::Operand::Register(GPR1), + Assembler::Operand::Imm64(0xffffffff)); + m_assembler.bitwise_and( + Assembler::Operand::Register(GPR0), + Assembler::Operand::Register(GPR1)); + + // if (GPR0 == 0x7fffffff) goto slow_case; + m_assembler.jump_if_equal( + Assembler::Operand::Register(GPR0), + Assembler::Operand::Imm32(0x7fffffff), + slow_case); + + // GPR0 += 1; + m_assembler.add( + Assembler::Operand::Register(GPR0), + Assembler::Operand::Imm32(1)); + + // GPR0 |= INT32_TAG << 48; + m_assembler.mov( + Assembler::Operand::Register(GPR1), + Assembler::Operand::Imm64(SHIFTED_INT32_TAG)); + m_assembler.bitwise_or( + Assembler::Operand::Register(GPR0), + Assembler::Operand::Register(GPR1)); + + // accumulator = GPR0; + store_vm_register(Bytecode::Register::accumulator(), GPR0); + + m_assembler.jump(end); + }); + + slow_case.link(m_assembler); m_assembler.native_call((void*)cxx_increment); store_vm_register(Bytecode::Register::accumulator(), RET); check_exception(); + + end.link(m_assembler); } static Value cxx_decrement(VM& vm, Value value) diff --git a/Userland/Libraries/LibJS/JIT/Compiler.h b/Userland/Libraries/LibJS/JIT/Compiler.h index 04d377fd12..0034321169 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.h +++ b/Userland/Libraries/LibJS/JIT/Compiler.h @@ -89,6 +89,9 @@ private: void push_unwind_context(bool valid, Optional const& handler, Optional const& finalizer); void pop_unwind_context(); + template + void branch_if_int32(Assembler::Reg, Codegen); + explicit Compiler(Bytecode::Executable& bytecode_executable) : m_bytecode_executable(bytecode_executable) {