@@ -643,42 +643,6 @@ fn gen_ccall(asm: &mut Assembler, cfun: *const u8, args: Vec<Opnd>) -> lir::Opnd
643643 asm. ccall ( cfun, args)
644644}
645645
646- /// Push a C frame for cfunc calls
647- fn gen_push_cfunc_frame ( asm : & mut Assembler , recv : Opnd , cme : * const rb_callable_method_entry_t , sp_offset : i32 ) {
648- asm_comment ! ( asm, "push C frame" ) ;
649-
650- let new_sp = asm. lea ( Opnd :: mem ( 64 , SP , sp_offset * SIZEOF_VALUE_I32 ) ) ;
651- // sp[-3]: cme
652- asm. store ( Opnd :: mem ( 64 , SP , ( sp_offset - 3 ) * SIZEOF_VALUE_I32 ) , VALUE :: from ( cme) . into ( ) ) ;
653- // sp[-2]: block_handler (specval)
654- asm. store ( Opnd :: mem ( 64 , SP , ( sp_offset - 2 ) * SIZEOF_VALUE_I32 ) , VM_BLOCK_HANDLER_NONE . into ( ) ) ;
655- // sp[-1]: frame type (must be a valid FIXNUM)
656- let frame_type = VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL ;
657- asm. store ( Opnd :: mem ( 64 , SP , ( sp_offset - 1 ) * SIZEOF_VALUE_I32 ) , frame_type. into ( ) ) ;
658-
659- fn cfp_opnd ( offset : i32 ) -> Opnd {
660- Opnd :: mem ( 64 , CFP , offset - ( RUBY_SIZEOF_CONTROL_FRAME as i32 ) )
661- }
662-
663- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_PC ) , 0 . into ( ) ) ; // C frames don't have a PC
664- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_SP ) , new_sp) ; // SP for new frame
665-
666- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_ISEQ ) , 0 . into ( ) ) ; // C frames don't have an iseq
667- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_SELF ) , recv) ;
668- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_BLOCK_CODE ) , 0 . into ( ) ) ;
669-
670- let ep = asm. sub ( new_sp, SIZEOF_VALUE . into ( ) ) ;
671- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_EP ) , ep) ;
672- }
673-
674- /// Pop a C frame after cfunc call
675- fn gen_pop_cfunc_frame ( asm : & mut Assembler ) {
676- asm_comment ! ( asm, "pop C frame" ) ;
677- let new_cfp = asm. add ( CFP , RUBY_SIZEOF_CONTROL_FRAME . into ( ) ) ;
678- asm. mov ( CFP , new_cfp) ;
679- asm. store ( Opnd :: mem ( 64 , EC , RUBY_OFFSET_EC_CFP ) , CFP ) ;
680- }
681-
682646/// Generate code for a variadic C function call
683647/// func(int argc, VALUE *argv, VALUE recv)
684648fn gen_ccall_variadic (
@@ -692,16 +656,22 @@ fn gen_ccall_variadic(
692656) -> lir:: Opnd {
693657 gen_prepare_non_leaf_call ( jit, asm, state) ;
694658
695- asm_comment ! ( asm, "pushing C frame for cme=0x{:x}" , cme as usize ) ;
696- // Following YJIT: allocate 3 slots for frame metadata (cme, block_handler, frame_type)
697- // The new frame's SP will be at current_stack_size + 3
698- let sp_offset = state. stack ( ) . len ( ) as i32 + 3 ;
699- gen_push_cfunc_frame ( asm, recv, cme, sp_offset) ;
659+ gen_push_frame ( asm, args. len ( ) , state, ControlFrame {
660+ recv,
661+ iseq : None ,
662+ cme,
663+ frame_type : VM_FRAME_MAGIC_CFUNC | VM_FRAME_FLAG_CFRAME | VM_ENV_FLAG_LOCAL ,
664+ } ) ;
665+
666+ asm_comment ! ( asm, "switch to new SP register" ) ;
667+ let sp_offset = ( state. stack ( ) . len ( ) - args. len ( ) + VM_ENV_DATA_SIZE . as_usize ( ) ) * SIZEOF_VALUE ;
668+ let new_sp = asm. add ( SP , sp_offset. into ( ) ) ;
669+ asm. mov ( SP , new_sp) ;
700670
701- // Move to the new frame
702- let new_cfp = asm. lea ( Opnd :: mem ( 64 , CFP , - ( RUBY_SIZEOF_CONTROL_FRAME as i32 ) ) ) ;
671+ asm_comment ! ( asm , "switch to new CFP" ) ;
672+ let new_cfp = asm. sub ( CFP , RUBY_SIZEOF_CONTROL_FRAME . into ( ) ) ;
703673 asm. mov ( CFP , new_cfp) ;
704- asm. store ( Opnd :: mem ( 64 , EC , RUBY_OFFSET_EC_CFP ) , new_cfp ) ;
674+ asm. store ( Opnd :: mem ( 64 , EC , RUBY_OFFSET_EC_CFP ) , CFP ) ;
705675
706676 let argc = args. len ( ) ;
707677
@@ -711,7 +681,14 @@ fn gen_ccall_variadic(
711681 let result = asm. ccall ( cfun, vec ! [ argc. into( ) , argv_ptr, recv] ) ;
712682 gen_pop_opnds ( asm, & args) ;
713683
714- gen_pop_cfunc_frame ( asm) ;
684+ asm_comment ! ( asm, "pop C frame" ) ;
685+ let new_cfp = asm. add ( CFP , RUBY_SIZEOF_CONTROL_FRAME . into ( ) ) ;
686+ asm. mov ( CFP , new_cfp) ;
687+ asm. store ( Opnd :: mem ( 64 , EC , RUBY_OFFSET_EC_CFP ) , CFP ) ;
688+
689+ asm_comment ! ( asm, "restore SP register for the caller" ) ;
690+ let new_sp = asm. sub ( SP , sp_offset. into ( ) ) ;
691+ asm. mov ( SP , new_sp) ;
715692
716693 result
717694}
@@ -1126,7 +1103,7 @@ fn gen_send_without_block_direct(
11261103 // TODO: Lazily materialize caller frames on side exits or when needed
11271104 gen_push_frame ( asm, args. len ( ) , state, ControlFrame {
11281105 recv,
1129- iseq,
1106+ iseq : Some ( iseq ) ,
11301107 cme,
11311108 frame_type : VM_FRAME_MAGIC_METHOD | VM_ENV_FLAG_LOCAL ,
11321109 } ) ;
@@ -1646,7 +1623,7 @@ fn gen_prepare_non_leaf_call(jit: &JITState, asm: &mut Assembler, state: &FrameS
16461623/// Frame metadata written by gen_push_frame()
16471624struct ControlFrame {
16481625 recv : Opnd ,
1649- iseq : IseqPtr ,
1626+ iseq : Option < IseqPtr > ,
16501627 cme : * const rb_callable_method_entry_t ,
16511628 frame_type : u32 ,
16521629}
@@ -1658,7 +1635,11 @@ fn gen_push_frame(asm: &mut Assembler, argc: usize, state: &FrameState, frame: C
16581635 // See vm_push_frame() for details
16591636 asm_comment ! ( asm, "push cme, specval, frame type" ) ;
16601637 // ep[-2]: cref of cme
1661- let local_size = unsafe { get_iseq_body_local_table_size ( frame. iseq ) } as i32 ;
1638+ let local_size = if let Some ( iseq) = frame. iseq {
1639+ ( unsafe { get_iseq_body_local_table_size ( iseq) } ) as i32
1640+ } else {
1641+ 0
1642+ } ;
16621643 let ep_offset = state. stack ( ) . len ( ) as i32 + local_size - argc as i32 + VM_ENV_DATA_SIZE as i32 - 1 ;
16631644 asm. store ( Opnd :: mem ( 64 , SP , ( ep_offset - 2 ) * SIZEOF_VALUE_I32 ) , VALUE :: from ( frame. cme ) . into ( ) ) ;
16641645 // ep[-1]: block_handler or prev EP
@@ -1673,9 +1654,15 @@ fn gen_push_frame(asm: &mut Assembler, argc: usize, state: &FrameState, frame: C
16731654 }
16741655
16751656 asm_comment ! ( asm, "push callee control frame" ) ;
1657+
1658+ let pc = if let Some ( iseq) = frame. iseq {
1659+ VALUE :: from ( iseq) . into ( )
1660+ } else {
1661+ 0 . into ( )
1662+ } ;
16761663 // cfp_opnd(RUBY_OFFSET_CFP_PC): written by the callee frame on side-exits or non-leaf calls
16771664 // cfp_opnd(RUBY_OFFSET_CFP_SP): written by the callee frame on side-exits or non-leaf calls
1678- asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_ISEQ ) , VALUE :: from ( frame . iseq ) . into ( ) ) ;
1665+ asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_ISEQ ) , pc ) ;
16791666 asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_SELF ) , frame. recv ) ;
16801667 let ep = asm. lea ( Opnd :: mem ( 64 , SP , ep_offset * SIZEOF_VALUE_I32 ) ) ;
16811668 asm. mov ( cfp_opnd ( RUBY_OFFSET_CFP_EP ) , ep) ;
0 commit comments