@@ -6428,6 +6428,38 @@ fn gen_struct_aset(
64286428 Some ( EndBlock )
64296429}
64306430
6431+ // Generate code that calls a method with dynamic dispatch
6432+ fn gen_send_dynamic < F : Fn ( & mut Assembler ) -> Opnd > (
6433+ jit : & mut JITState ,
6434+ asm : & mut Assembler ,
6435+ cd : * const rb_call_data ,
6436+ sp_pops : usize ,
6437+ vm_sendish : F ,
6438+ ) -> Option < CodegenStatus > {
6439+ // Our frame handling is not compatible with tailcall
6440+ if unsafe { vm_ci_flag ( ( * cd) . ci ) } & VM_CALL_TAILCALL != 0 {
6441+ return None ;
6442+ }
6443+
6444+ // Save PC and SP to prepare for dynamic dispatch
6445+ jit_prepare_routine_call ( jit, asm) ;
6446+
6447+ // Pop arguments and a receiver
6448+ asm. stack_pop ( sp_pops) ;
6449+
6450+ // Dispatch a method
6451+ let ret = vm_sendish ( asm) ;
6452+
6453+ // Push the return value
6454+ let stack_ret = asm. stack_push ( Type :: Unknown ) ;
6455+ asm. mov ( stack_ret, ret) ;
6456+
6457+ // Fix the interpreter SP deviated by vm_sendish
6458+ asm. mov ( Opnd :: mem ( 64 , CFP , RUBY_OFFSET_CFP_SP ) , SP ) ;
6459+
6460+ Some ( KeepCompiling )
6461+ }
6462+
64316463fn gen_send_general (
64326464 jit : & mut JITState ,
64336465 asm : & mut Assembler ,
@@ -6909,33 +6941,84 @@ fn gen_opt_send_without_block(
69096941 asm : & mut Assembler ,
69106942 ocb : & mut OutlinedCb ,
69116943) -> Option < CodegenStatus > {
6944+ // Generate specialized code if possible
69126945 let cd = jit. get_arg ( 0 ) . as_ptr ( ) ;
6946+ if let Some ( status) = gen_send_general ( jit, asm, ocb, cd, None ) {
6947+ return Some ( status) ;
6948+ }
69136949
6914- gen_send_general ( jit, asm, ocb, cd, None )
6950+ // Otherwise, fallback to dynamic dispatch using the interpreter's implementation of send
6951+ gen_send_dynamic ( jit, asm, cd, unsafe { rb_yjit_sendish_sp_pops ( ( * cd) . ci ) } , |asm| {
6952+ extern "C" {
6953+ fn rb_vm_opt_send_without_block ( ec : EcPtr , cfp : CfpPtr , cd : VALUE ) -> VALUE ;
6954+ }
6955+ asm. ccall (
6956+ rb_vm_opt_send_without_block as * const u8 ,
6957+ vec ! [ EC , CFP , ( cd as usize ) . into( ) ] ,
6958+ )
6959+ } )
69156960}
69166961
69176962fn gen_send (
69186963 jit : & mut JITState ,
69196964 asm : & mut Assembler ,
69206965 ocb : & mut OutlinedCb ,
69216966) -> Option < CodegenStatus > {
6967+ // Generate specialized code if possible
69226968 let cd = jit. get_arg ( 0 ) . as_ptr ( ) ;
69236969 let block = jit. get_arg ( 1 ) . as_optional_ptr ( ) ;
6924- return gen_send_general ( jit, asm, ocb, cd, block) ;
6970+ if let Some ( status) = gen_send_general ( jit, asm, ocb, cd, block) {
6971+ return Some ( status) ;
6972+ }
6973+
6974+ // Otherwise, fallback to dynamic dispatch using the interpreter's implementation of send
6975+ let blockiseq = jit. get_arg ( 1 ) . as_iseq ( ) ;
6976+ gen_send_dynamic ( jit, asm, cd, unsafe { rb_yjit_sendish_sp_pops ( ( * cd) . ci ) } , |asm| {
6977+ extern "C" {
6978+ fn rb_vm_send ( ec : EcPtr , cfp : CfpPtr , cd : VALUE , blockiseq : IseqPtr ) -> VALUE ;
6979+ }
6980+ asm. ccall (
6981+ rb_vm_send as * const u8 ,
6982+ vec ! [ EC , CFP , ( cd as usize ) . into( ) , VALUE ( blockiseq as usize ) . into( ) ] ,
6983+ )
6984+ } )
69256985}
69266986
69276987fn gen_invokeblock (
69286988 jit : & mut JITState ,
69296989 asm : & mut Assembler ,
69306990 ocb : & mut OutlinedCb ,
6991+ ) -> Option < CodegenStatus > {
6992+ // Generate specialized code if possible
6993+ let cd = jit. get_arg ( 0 ) . as_ptr ( ) ;
6994+ if let Some ( status) = gen_invokeblock_specialized ( jit, asm, ocb, cd) {
6995+ return Some ( status) ;
6996+ }
6997+
6998+ // Otherwise, fallback to dynamic dispatch using the interpreter's implementation of send
6999+ gen_send_dynamic ( jit, asm, cd, unsafe { rb_yjit_invokeblock_sp_pops ( ( * cd) . ci ) } , |asm| {
7000+ extern "C" {
7001+ fn rb_vm_invokeblock ( ec : EcPtr , cfp : CfpPtr , cd : VALUE ) -> VALUE ;
7002+ }
7003+ asm. ccall (
7004+ rb_vm_invokeblock as * const u8 ,
7005+ vec ! [ EC , CFP , ( cd as usize ) . into( ) ] ,
7006+ )
7007+ } )
7008+ }
7009+
7010+ fn gen_invokeblock_specialized (
7011+ jit : & mut JITState ,
7012+ asm : & mut Assembler ,
7013+ ocb : & mut OutlinedCb ,
7014+ cd : * const rb_call_data ,
69317015) -> Option < CodegenStatus > {
69327016 if !jit. at_current_insn ( ) {
69337017 defer_compilation ( jit, asm, ocb) ;
69347018 return Some ( EndBlock ) ;
69357019 }
69367020
69377021 // Get call info
6938- let cd = jit. get_arg ( 0 ) . as_ptr ( ) ;
69397022 let ci = unsafe { get_call_data_ci ( cd) } ;
69407023 let argc: i32 = unsafe { vm_ci_argc ( ci) } . try_into ( ) . unwrap ( ) ;
69417024 let flags = unsafe { vm_ci_flag ( ci) } ;
@@ -7065,7 +7148,31 @@ fn gen_invokesuper(
70657148 asm : & mut Assembler ,
70667149 ocb : & mut OutlinedCb ,
70677150) -> Option < CodegenStatus > {
7068- let cd: * const rb_call_data = jit. get_arg ( 0 ) . as_ptr ( ) ;
7151+ // Generate specialized code if possible
7152+ let cd = jit. get_arg ( 0 ) . as_ptr ( ) ;
7153+ if let Some ( status) = gen_invokesuper_specialized ( jit, asm, ocb, cd) {
7154+ return Some ( status) ;
7155+ }
7156+
7157+ // Otherwise, fallback to dynamic dispatch using the interpreter's implementation of send
7158+ let blockiseq = jit. get_arg ( 1 ) . as_iseq ( ) ;
7159+ gen_send_dynamic ( jit, asm, cd, unsafe { rb_yjit_sendish_sp_pops ( ( * cd) . ci ) } , |asm| {
7160+ extern "C" {
7161+ fn rb_vm_invokesuper ( ec : EcPtr , cfp : CfpPtr , cd : VALUE , blockiseq : IseqPtr ) -> VALUE ;
7162+ }
7163+ asm. ccall (
7164+ rb_vm_invokesuper as * const u8 ,
7165+ vec ! [ EC , CFP , ( cd as usize ) . into( ) , VALUE ( blockiseq as usize ) . into( ) ] ,
7166+ )
7167+ } )
7168+ }
7169+
7170+ fn gen_invokesuper_specialized (
7171+ jit : & mut JITState ,
7172+ asm : & mut Assembler ,
7173+ ocb : & mut OutlinedCb ,
7174+ cd : * const rb_call_data ,
7175+ ) -> Option < CodegenStatus > {
70697176 let block: Option < IseqPtr > = jit. get_arg ( 1 ) . as_optional_ptr ( ) ;
70707177
70717178 // Defer compilation so we can specialize on class of receiver
0 commit comments