@@ -257,7 +257,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
257
257
Insn :: Jump ( branch) => return gen_jump ( jit, asm, branch) ,
258
258
Insn :: IfTrue { val, target } => return gen_if_true ( jit, asm, opnd ! ( val) , target) ,
259
259
Insn :: IfFalse { val, target } => return gen_if_false ( jit, asm, opnd ! ( val) , target) ,
260
- Insn :: SendWithoutBlock { call_info, cd, state, .. } => gen_send_without_block ( jit, asm, call_info, * cd, & function. frame_state ( * state) ) ?,
260
+ Insn :: SendWithoutBlock { call_info, cd, state, self_val , args , .. } => gen_send_without_block ( jit, asm, call_info, * cd, & function. frame_state ( * state) , self_val , args ) ?,
261
261
Insn :: SendWithoutBlockDirect { iseq, self_val, args, .. } => gen_send_without_block_direct ( cb, jit, asm, * iseq, opnd ! ( self_val) , args) ?,
262
262
Insn :: Return { val } => return Some ( gen_return ( asm, opnd ! ( val) ) ?) ,
263
263
Insn :: FixnumAdd { left, right, state } => gen_fixnum_add ( asm, opnd ! ( left) , opnd ! ( right) , & function. frame_state ( * state) ) ?,
@@ -443,18 +443,20 @@ fn gen_send_without_block(
443
443
call_info : & CallInfo ,
444
444
cd : * const rb_call_data ,
445
445
state : & FrameState ,
446
+ self_val : & InsnId ,
447
+ args : & Vec < InsnId > ,
446
448
) -> Option < lir:: Opnd > {
447
- // Spill the virtual stack onto the stack. They need to be marked by GC and may be caller-saved registers.
449
+ // Spill the receiver and the arguments onto the stack. They need to be marked by GC and may be caller-saved registers.
448
450
// TODO: Avoid spilling operands that have been spilled before.
449
- for ( idx, & insn_id) in state . stack ( ) . enumerate ( ) {
451
+ for ( idx, & insn_id) in [ * self_val ] . iter ( ) . chain ( args . iter ( ) ) . enumerate ( ) {
450
452
// Currently, we don't move the SP register. So it's equal to the base pointer.
451
453
let stack_opnd = Opnd :: mem ( 64 , SP , idx as i32 * SIZEOF_VALUE_I32 ) ;
452
454
asm. mov ( stack_opnd, jit. get_opnd ( insn_id) ?) ;
453
455
}
454
456
455
457
// Save PC and SP
456
458
gen_save_pc ( asm, state) ;
457
- gen_save_sp ( asm, state ) ;
459
+ gen_save_sp ( asm, 1 + args . len ( ) ) ; // +1 for receiver
458
460
459
461
asm_comment ! ( asm, "call #{} with dynamic dispatch" , call_info. method_name) ;
460
462
unsafe extern "C" {
@@ -678,13 +680,13 @@ fn gen_save_pc(asm: &mut Assembler, state: &FrameState) {
678
680
}
679
681
680
682
/// Save the current SP on the CFP
681
- fn gen_save_sp ( asm : & mut Assembler , state : & FrameState ) {
683
+ fn gen_save_sp ( asm : & mut Assembler , stack_size : usize ) {
682
684
// Update cfp->sp which will be read by the interpreter. We also have the SP register in JIT
683
685
// code, and ZJIT's codegen currently assumes the SP register doesn't move, e.g. gen_param().
684
686
// So we don't update the SP register here. We could update the SP register to avoid using
685
687
// an extra register for asm.lea(), but you'll need to manage the SP offset like YJIT does.
686
- asm_comment ! ( asm, "save SP to CFP: {}" , state . stack_size( ) ) ;
687
- let sp_addr = asm. lea ( Opnd :: mem ( 64 , SP , state . stack_size ( ) as i32 * SIZEOF_VALUE_I32 ) ) ;
688
+ asm_comment ! ( asm, "save SP to CFP: {}" , stack_size) ;
689
+ let sp_addr = asm. lea ( Opnd :: mem ( 64 , SP , stack_size as i32 * SIZEOF_VALUE_I32 ) ) ;
688
690
let cfp_sp = Opnd :: mem ( 64 , CFP , RUBY_OFFSET_CFP_SP ) ;
689
691
asm. mov ( cfp_sp, sp_addr) ;
690
692
}
0 commit comments