@@ -1346,7 +1346,7 @@ fn gen_send_without_block_direct(
13461346 gen_save_sp ( asm, state. stack ( ) . len ( ) - args. len ( ) - 1 ) ; // -1 for receiver
13471347
13481348 gen_spill_locals ( jit, asm, state) ;
1349- gen_spill_stack ( jit, asm, state) ;
1349+ gen_spill_stack_for_send ( jit, asm, state, & args ) ;
13501350
13511351 let ( frame_type, specval) = if VM_METHOD_TYPE_BMETHOD == unsafe { get_cme_def_type ( cme) } {
13521352 // Extract EP from the Proc instance
@@ -2211,6 +2211,24 @@ fn gen_spill_stack(jit: &JITState, asm: &mut Assembler, state: &FrameState) {
22112211 }
22122212}
22132213
2214+ /// Spill stack for a direct send, with args in callee order.
2215+ /// This is needed because reorder_keyword_arguments may reorder the args in the HIR
2216+ /// but the FrameState's stack remains in caller order.
2217+ fn gen_spill_stack_for_send ( jit : & JITState , asm : & mut Assembler , state : & FrameState , args : & [ Opnd ] ) {
2218+ gen_incr_counter ( asm, Counter :: vm_write_stack_count) ;
2219+ let stack: Vec < _ > = state. stack ( ) . collect ( ) ;
2220+ let recv_idx = stack. len ( ) - args. len ( ) - 1 ;
2221+ asm_comment ! ( asm, "spill stack up to and including receiver" ) ;
2222+ for idx in 0 ..=recv_idx {
2223+ asm. mov ( Opnd :: mem ( 64 , SP , idx as i32 * SIZEOF_VALUE_I32 ) , jit. get_opnd ( * stack[ idx] ) ) ;
2224+ }
2225+ asm_comment ! ( asm, "spill args in callee order" ) ;
2226+ for ( i, arg) in args. iter ( ) . enumerate ( ) {
2227+ let offset = ( recv_idx + 1 + i) as i32 * SIZEOF_VALUE_I32 ;
2228+ asm. mov ( Opnd :: mem ( 64 , SP , offset) , * arg) ;
2229+ }
2230+ }
2231+
22142232/// Prepare for calling a C function that may call an arbitrary method.
22152233/// Use gen_prepare_leaf_call_with_gc() if the method is leaf but allocates objects.
22162234fn gen_prepare_non_leaf_call ( jit : & JITState , asm : & mut Assembler , state : & FrameState ) {
0 commit comments