@@ -640,42 +640,6 @@ fn gen_ccall(asm: &mut Assembler, cfun: *const u8, args: Vec<Opnd>) -> lir::Opnd
640640 asm. ccall ( cfun, args)
641641}
642642
643- /// Push a C frame for cfunc calls
644- fn gen_push_cfunc_frame ( asm : & mut Assembler , recv : Opnd , cme : * const rb_callable_method_entry_t , sp_offset : i32 ) {
645- asm_comment ! ( asm, "push C frame" ) ;
646-
647- let new_sp = asm. lea ( Opnd :: mem ( 64 , SP , sp_offset * SIZEOF_VALUE_I32 ) ) ;
648- // sp[-3]: cme
649- asm. store ( Opnd :: mem ( 64 , SP , ( sp_offset - 3 ) * SIZEOF_VALUE_I32 ) , VALUE :: from ( cme) . into ( ) ) ;
650- // sp[-2]: block_handler (specval)
651- asm. store ( Opnd :: mem ( 64 , SP , ( sp_offset - 2 ) * SIZEOF_VALUE_I32 ) , VM_BLOCK_HANDLER_NONE . into ( ) ) ;
652- // sp[-1]: frame type (must be a valid FIXNUM)
653- let frame_type = VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL ;
654- asm. store ( Opnd :: mem ( 64 , SP , ( sp_offset - 1 ) * SIZEOF_VALUE_I32 ) , frame_type. into ( ) ) ;
655-
656- fn cfp_opnd ( offset : i32 ) -> Opnd {
657- Opnd :: mem ( 64 , CFP , offset - ( RUBY_SIZEOF_CONTROL_FRAME as i32 ) )
658- }
659-
660- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_PC ) , 0 . into ( ) ) ; // C frames don't have a PC
661- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_SP ) , new_sp) ; // SP for new frame
662-
663- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_ISEQ ) , 0 . into ( ) ) ; // C frames don't have an iseq
664- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_SELF ) , recv) ;
665- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_BLOCK_CODE ) , 0 . into ( ) ) ;
666-
667- let ep = asm. sub ( new_sp, SIZEOF_VALUE . into ( ) ) ;
668- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_EP ) , ep) ;
669- }
670-
671- /// Pop a C frame after cfunc call
672- fn gen_pop_cfunc_frame ( asm : & mut Assembler ) {
673- asm_comment ! ( asm, "pop C frame" ) ;
674- let new_cfp = asm. add ( CFP , RUBY_SIZEOF_CONTROL_FRAME . into ( ) ) ;
675- asm. mov ( CFP , new_cfp) ;
676- asm. store ( Opnd :: mem ( 64 , EC , RUBY_OFFSET_EC_CFP ) , CFP ) ;
677- }
678-
679643/// Generate code for a variadic C function call
680644/// func(int argc, VALUE *argv, VALUE recv)
681645fn gen_ccall_variadic (
@@ -689,26 +653,35 @@ fn gen_ccall_variadic(
689653) -> lir:: Opnd {
690654 gen_prepare_non_leaf_call ( jit, asm, state) ;
691655
692- asm_comment ! ( asm, "pushing C frame for cme=0x{:x}" , cme as usize ) ;
693- // Following YJIT: allocate 3 slots for frame metadata (cme, block_handler, frame_type)
694- // The new frame's SP will be at current_stack_size + 3
695- let sp_offset = state. stack ( ) . len ( ) as i32 + 3 ;
696- gen_push_cfunc_frame ( asm, recv, cme, sp_offset) ;
697-
698- // Move to the new frame
699- let new_cfp = asm. lea ( Opnd :: mem ( 64 , CFP , -( RUBY_SIZEOF_CONTROL_FRAME as i32 ) ) ) ;
700- asm. mov ( CFP , new_cfp) ;
701- asm. store ( Opnd :: mem ( 64 , EC , RUBY_OFFSET_EC_CFP ) , new_cfp) ;
656+ gen_push_frame ( asm, args. len ( ) , state, ControlFrame {
657+ recv,
658+ iseq : None ,
659+ cme,
660+ frame_type : VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL ,
661+ } ) ;
702662
703- let argc = args. len ( ) ;
663+ asm_comment ! ( asm, "switch to new SP register" ) ;
664+ let sp_offset = ( state. stack ( ) . len ( ) - args. len ( ) + VM_ENV_DATA_SIZE . as_usize ( ) ) * SIZEOF_VALUE ;
665+ let new_sp = asm. add ( SP , sp_offset. into ( ) ) ;
666+ asm. mov ( SP , new_sp) ;
704667
705- asm_comment ! ( asm, "call variadic cfunc: argc={}" , argc) ;
668+ asm_comment ! ( asm, "switch to new CFP" ) ;
669+ let new_cfp = asm. sub ( CFP , RUBY_SIZEOF_CONTROL_FRAME . into ( ) ) ;
670+ asm. mov ( CFP , new_cfp) ;
671+ asm. store ( Opnd :: mem ( 64 , EC , RUBY_OFFSET_EC_CFP ) , CFP ) ;
706672
707673 let argv_ptr = gen_push_opnds ( jit, asm, & args) ;
708- let result = asm. ccall ( cfun, vec ! [ argc . into( ) , argv_ptr, recv] ) ;
674+ let result = asm. ccall ( cfun, vec ! [ args . len ( ) . into( ) , argv_ptr, recv] ) ;
709675 gen_pop_opnds ( asm, & args) ;
710676
711- gen_pop_cfunc_frame ( asm) ;
677+ asm_comment ! ( asm, "pop C frame" ) ;
678+ let new_cfp = asm. add ( CFP , RUBY_SIZEOF_CONTROL_FRAME . into ( ) ) ;
679+ asm. mov ( CFP , new_cfp) ;
680+ asm. store ( Opnd :: mem ( 64 , EC , RUBY_OFFSET_EC_CFP ) , CFP ) ;
681+
682+ asm_comment ! ( asm, "restore SP register for the caller" ) ;
683+ let new_sp = asm. sub ( SP , sp_offset. into ( ) ) ;
684+ asm. mov ( SP , new_sp) ;
712685
713686 result
714687}
@@ -1129,7 +1102,7 @@ fn gen_send_without_block_direct(
11291102 // TODO: Lazily materialize caller frames on side exits or when needed
11301103 gen_push_frame ( asm, args. len ( ) , state, ControlFrame {
11311104 recv,
1132- iseq,
1105+ iseq : Some ( iseq ) ,
11331106 cme,
11341107 frame_type : VM_FRAME_MAGIC_METHOD | VM_ENV_FLAG_LOCAL ,
11351108 } ) ;
@@ -1649,7 +1622,7 @@ fn gen_prepare_non_leaf_call(jit: &JITState, asm: &mut Assembler, state: &FrameS
16491622/// Frame metadata written by gen_push_frame()
16501623struct ControlFrame {
16511624 recv : Opnd ,
1652- iseq : IseqPtr ,
1625+ iseq : Option < IseqPtr > ,
16531626 cme : * const rb_callable_method_entry_t ,
16541627 frame_type : u32 ,
16551628}
@@ -1661,7 +1634,11 @@ fn gen_push_frame(asm: &mut Assembler, argc: usize, state: &FrameState, frame: C
16611634 // See vm_push_frame() for details
16621635 asm_comment ! ( asm, "push cme, specval, frame type" ) ;
16631636 // ep[-2]: cref of cme
1664- let local_size = unsafe { get_iseq_body_local_table_size ( frame. iseq ) } as i32 ;
1637+ let local_size = if let Some ( iseq) = frame. iseq {
1638+ ( unsafe { get_iseq_body_local_table_size ( iseq) } ) as i32
1639+ } else {
1640+ 0
1641+ } ;
16651642 let ep_offset = state. stack ( ) . len ( ) as i32 + local_size - argc as i32 + VM_ENV_DATA_SIZE as i32 - 1 ;
16661643 asm. store ( Opnd :: mem ( 64 , SP , ( ep_offset - 2 ) * SIZEOF_VALUE_I32 ) , VALUE :: from ( frame. cme ) . into ( ) ) ;
16671644 // ep[-1]: block_handler or prev EP
@@ -1676,9 +1653,15 @@ fn gen_push_frame(asm: &mut Assembler, argc: usize, state: &FrameState, frame: C
16761653 }
16771654
16781655 asm_comment ! ( asm, "push callee control frame" ) ;
1656+
1657+ let pc = if let Some ( iseq) = frame. iseq {
1658+ VALUE :: from ( iseq) . into ( )
1659+ } else {
1660+ 0 . into ( )
1661+ } ;
16791662 // cfp_opnd(RUBY_OFFSET_CFP_PC): written by the callee frame on side-exits or non-leaf calls
16801663 // cfp_opnd(RUBY_OFFSET_CFP_SP): written by the callee frame on side-exits or non-leaf calls
1681- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_ISEQ ) , VALUE :: from ( frame . iseq ) . into ( ) ) ;
1664+ asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_ISEQ ) , pc ) ;
16821665 asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_SELF ) , frame. recv ) ;
16831666 let ep = asm. lea ( Opnd :: mem ( 64 , SP , ep_offset * SIZEOF_VALUE_I32 ) ) ;
16841667 asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_EP ) , ep) ;
0 commit comments