ZJIT: Load return value before frame teardown

Or else the following returns garbage since it loads after
moving SP. Prior bad disassembly:

    def a(n1,n2,n3,n4,n5,n6,n7,n8) = n8
    a(1,1,1,1,1,1,1,0)

    # Block: bb0(v0, v1, v2, v3, v4, v5, v6, v7, v8)
    stp x29, x30, [sp, #-0x10]!
    mov x29, sp
    # bump C stack pointer
    sub sp, sp, #0x10
    # Insn: v10 Return v8
    # pop stack frame
    adds x19, x19, #0x38
    stur x19, [x20, #0x10]
    # restore C stack pointer
    add sp, sp, #0x10
    mov sp, x29
    ldp x29, x30, [sp], #0x10
    ldur x0, [sp]
    ret
This commit is contained in:
Alan Wu 2025-07-18 14:30:58 -04:00
parent 9f961a4b30
commit e77eee96a3
2 changed files with 10 additions and 1 deletions

View file

@ -898,6 +898,10 @@ fn gen_return(jit: &JITState, asm: &mut Assembler, val: lir::Opnd) -> Option<()>
asm.mov(CFP, incr_cfp);
asm.mov(Opnd::mem(64, EC, RUBY_OFFSET_EC_CFP), CFP);
// Order here is important. Because we're about to tear down the frame,
// we need to load the return value, which might be part of the frame.
asm.load_into(C_RET_OPND, val);
// Restore the C stack pointer bumped for basic block arguments
if jit.c_stack_bytes > 0 {
asm_comment!(asm, "restore C stack pointer");
@ -908,7 +912,7 @@ fn gen_return(jit: &JITState, asm: &mut Assembler, val: lir::Opnd) -> Option<()>
asm.frame_teardown();
// Return from the function
asm.cret(val);
asm.cret(C_RET_OPND);
Some(())
}