1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 05:07:45 +00:00

LibJS/JIT: Add fast path for Increment with Int32 value

This uses a new branch_if_int32() mechanism that takes a code generating
lambda whose code will run if the input register is an Int32 JS::Value.
This commit is contained in:
Andreas Kling 2023-10-23 10:20:35 +02:00
parent aeb9bd3bf1
commit ea65214c57
3 changed files with 99 additions and 0 deletions

View file

@ -204,6 +204,14 @@ struct Assembler {
return make_label(); 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) void jump(Operand op)
{ {
if (op.type == Operand::Type::Reg) { 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() void enter()
{ {
push_callee_saved_registers(); push_callee_saved_registers();
@ -459,6 +486,12 @@ struct Assembler {
pop(Operand::Register(Reg::RDX)); pop(Operand::Register(Reg::RDX));
pop(Operand::Register(Reg::RCX)); pop(Operand::Register(Reg::RCX));
} }
void trap()
{
// int3
emit8(0xcc);
}
}; };
} }

View file

@ -162,18 +162,81 @@ void Compiler::compile_jump_conditional(Bytecode::Op::JumpConditional const& op)
[[maybe_unused]] static Value cxx_increment(VM& vm, Value value) [[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)); auto old_value = TRY_OR_SET_EXCEPTION(value.to_numeric(vm));
if (old_value.is_number()) if (old_value.is_number())
return Value(old_value.as_double() + 1); return Value(old_value.as_double() + 1);
return BigInt::create(vm, old_value.as_bigint().big_integer().plus(Crypto::SignedBigInteger { 1 })); return BigInt::create(vm, old_value.as_bigint().big_integer().plus(Crypto::SignedBigInteger { 1 }));
} }
template<typename Codegen>
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&) void Compiler::compile_increment(Bytecode::Op::Increment const&)
{ {
load_vm_register(ARG1, Bytecode::Register::accumulator()); 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); m_assembler.native_call((void*)cxx_increment);
store_vm_register(Bytecode::Register::accumulator(), RET); store_vm_register(Bytecode::Register::accumulator(), RET);
check_exception(); check_exception();
end.link(m_assembler);
} }
static Value cxx_decrement(VM& vm, Value value) static Value cxx_decrement(VM& vm, Value value)

View file

@ -89,6 +89,9 @@ private:
void push_unwind_context(bool valid, Optional<Bytecode::Label> const& handler, Optional<Bytecode::Label> const& finalizer); void push_unwind_context(bool valid, Optional<Bytecode::Label> const& handler, Optional<Bytecode::Label> const& finalizer);
void pop_unwind_context(); void pop_unwind_context();
template<typename Codegen>
void branch_if_int32(Assembler::Reg, Codegen);
explicit Compiler(Bytecode::Executable& bytecode_executable) explicit Compiler(Bytecode::Executable& bytecode_executable)
: m_bytecode_executable(bytecode_executable) : m_bytecode_executable(bytecode_executable)
{ {