diff --git a/Userland/Libraries/LibJIT/Assembler.h b/Userland/Libraries/LibJIT/Assembler.h index 539ae6125c..b02054d1ca 100644 --- a/Userland/Libraries/LibJIT/Assembler.h +++ b/Userland/Libraries/LibJIT/Assembler.h @@ -732,11 +732,17 @@ struct Assembler { } } - // NOTE: It's up to the caller of this function to preserve registers as needed. - void native_call(void* callee, Vector const& stack_arguments = {}) + void native_call( + void* callee, + Vector const& preserved_registers = {}, + Vector const& stack_arguments = {}) { + for (auto const& reg : preserved_registers.in_reverse()) + push(reg); + // Preserve 16-byte stack alignment for non-even amount of stack-passed arguments - if ((stack_arguments.size() % 2) == 1) + auto needs_aligning = ((stack_arguments.size() + preserved_registers.size()) % 2) == 1; + if (needs_aligning) push(Operand::Imm(0)); for (auto const& stack_argument : stack_arguments.in_reverse()) push(stack_argument); @@ -748,8 +754,11 @@ struct Assembler { emit8(0xff); emit_modrm_slash(2, Operand::Register(Reg::RAX)); - if (!stack_arguments.is_empty()) - add(Operand::Register(Reg::RSP), Operand::Imm(align_up_to(stack_arguments.size(), 2) * sizeof(void*))); + if (!stack_arguments.is_empty() || needs_aligning) + add(Operand::Register(Reg::RSP), Operand::Imm((stack_arguments.size() + (needs_aligning ? 1 : 0)) * sizeof(void*))); + + for (auto const& reg : preserved_registers) + pop(reg); } void trap() diff --git a/Userland/Libraries/LibJS/JIT/Compiler.cpp b/Userland/Libraries/LibJS/JIT/Compiler.cpp index eb611d251a..9b0ecb496b 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.cpp +++ b/Userland/Libraries/LibJS/JIT/Compiler.cpp @@ -1917,21 +1917,9 @@ void Compiler::jump_to_exit() void Compiler::native_call(void* function_address, Vector const& stack_arguments) { - // Make sure we don't clobber the VM&. - m_assembler.push(Assembler::Operand::Register(ARG0)); - - // Align the stack pointer. - m_assembler.sub(Assembler::Operand::Register(STACK_POINTER), Assembler::Operand::Imm(8)); - // NOTE: We don't preserve caller-saved registers when making a native call. // This means that they may have changed after we return from the call. - m_assembler.native_call(function_address, stack_arguments); - - // Restore the stack pointer. - m_assembler.add(Assembler::Operand::Register(STACK_POINTER), Assembler::Operand::Imm(8)); - - // Restore our VM&. - m_assembler.pop(Assembler::Operand::Register(ARG0)); + m_assembler.native_call(function_address, { Assembler::Operand::Register(ARG0) }, stack_arguments); } OwnPtr Compiler::compile(Bytecode::Executable& bytecode_executable)