@@ -711,6 +711,9 @@ pub enum Insn {
711711 /// Increment a counter in ZJIT stats
712712 IncrCounter ( Counter ) ,
713713
714+ /// Increment a counter in ZJIT stats for the given counter pointer
715+ IncrCounterPtr { counter_ptr : * mut u64 } ,
716+
714717 /// Equivalent of RUBY_VM_CHECK_INTS. Automatically inserted by the compiler before jumps and
715718 /// return instructions.
716719 CheckInterrupts { state : InsnId } ,
@@ -724,7 +727,7 @@ impl Insn {
724727 | Insn :: IfTrue { .. } | Insn :: IfFalse { .. } | Insn :: EntryPoint { .. } | Insn :: Return { .. }
725728 | Insn :: PatchPoint { .. } | Insn :: SetIvar { .. } | Insn :: ArrayExtend { .. }
726729 | Insn :: ArrayPush { .. } | Insn :: SideExit { .. } | Insn :: SetGlobal { .. }
727- | Insn :: SetLocal { .. } | Insn :: Throw { .. } | Insn :: IncrCounter ( _)
730+ | Insn :: SetLocal { .. } | Insn :: Throw { .. } | Insn :: IncrCounter ( _) | Insn :: IncrCounterPtr { .. }
728731 | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. } => false ,
729732 _ => true ,
730733 }
@@ -978,6 +981,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
978981 }
979982 Ok ( ( ) )
980983 } ,
984+ Insn :: IncrCounterPtr { .. } => write ! ( f, "IncrCounterPtr" ) ,
981985 Insn :: Snapshot { state } => write ! ( f, "Snapshot {}" , state. print( self . ptr_map) ) ,
982986 Insn :: Defined { op_type, v, .. } => {
983987 // op_type (enum defined_type) printing logic from iseq.c.
@@ -1385,6 +1389,7 @@ impl Function {
13851389 | EntryPoint { ..}
13861390 | LoadPC
13871391 | LoadSelf
1392+ | IncrCounterPtr { ..}
13881393 | IncrCounter ( _) ) => result. clone ( ) ,
13891394 & Snapshot { state : FrameState { iseq, insn_idx, pc, ref stack, ref locals } } =>
13901395 Snapshot {
@@ -1534,7 +1539,7 @@ impl Function {
15341539 | Insn :: IfTrue { .. } | Insn :: IfFalse { .. } | Insn :: Return { .. } | Insn :: Throw { .. }
15351540 | Insn :: PatchPoint { .. } | Insn :: SetIvar { .. } | Insn :: ArrayExtend { .. }
15361541 | Insn :: ArrayPush { .. } | Insn :: SideExit { .. } | Insn :: SetLocal { .. } | Insn :: IncrCounter ( _)
1537- | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. } =>
1542+ | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. } | Insn :: IncrCounterPtr { .. } =>
15381543 panic ! ( "Cannot infer type of instruction with no output: {}" , self . insns[ insn. 0 ] ) ,
15391544 Insn :: Const { val : Const :: Value ( val) } => Type :: from_value ( * val) ,
15401545 Insn :: Const { val : Const :: CBool ( val) } => Type :: from_cbool ( * val) ,
@@ -2154,9 +2159,9 @@ impl Function {
21542159 self_type : Type ,
21552160 send : Insn ,
21562161 send_insn_id : InsnId ,
2157- ) -> Result < ( ) , ( ) > {
2162+ ) -> Result < ( ) , Option < * const rb_callable_method_entry_struct > > {
21582163 let Insn :: SendWithoutBlock { mut recv, cd, mut args, state, .. } = send else {
2159- return Err ( ( ) ) ;
2164+ return Err ( None ) ;
21602165 } ;
21612166
21622167 let call_info = unsafe { ( * cd) . ci } ;
@@ -2168,20 +2173,20 @@ impl Function {
21682173 ( class, None )
21692174 } else {
21702175 let iseq_insn_idx = fun. frame_state ( state) . insn_idx ;
2171- let Some ( recv_type) = fun. profiled_type_of_at ( recv, iseq_insn_idx) else { return Err ( ( ) ) } ;
2176+ let Some ( recv_type) = fun. profiled_type_of_at ( recv, iseq_insn_idx) else { return Err ( None ) } ;
21722177 ( recv_type. class ( ) , Some ( recv_type) )
21732178 } ;
21742179
21752180 // Do method lookup
2176- let method = unsafe { rb_callable_method_entry ( recv_class, method_id) } ;
2181+ let method: * const rb_callable_method_entry_struct = unsafe { rb_callable_method_entry ( recv_class, method_id) } ;
21772182 if method. is_null ( ) {
2178- return Err ( ( ) ) ;
2183+ return Err ( None ) ;
21792184 }
21802185
21812186 // Filter for C methods
21822187 let def_type = unsafe { get_cme_def_type ( method) } ;
21832188 if def_type != VM_METHOD_TYPE_CFUNC {
2184- return Err ( ( ) ) ;
2189+ return Err ( None ) ;
21852190 }
21862191
21872192 // Find the `argc` (arity) of the C method, which describes the parameters it expects
@@ -2193,15 +2198,15 @@ impl Function {
21932198 //
21942199 // Bail on argc mismatch
21952200 if argc != cfunc_argc as u32 {
2196- return Err ( ( ) ) ;
2201+ return Err ( Some ( method ) ) ;
21972202 }
21982203
21992204 // Filter for a leaf and GC free function
22002205 use crate :: cruby_methods:: FnProperties ;
22012206 let Some ( FnProperties { leaf : true , no_gc : true , return_type, elidable } ) =
22022207 ZJITState :: get_method_annotations ( ) . get_cfunc_properties ( method)
22032208 else {
2204- return Err ( ( ) ) ;
2209+ return Err ( Some ( method ) ) ;
22052210 } ;
22062211
22072212 let ci_flags = unsafe { vm_ci_flag ( call_info) } ;
@@ -2218,13 +2223,13 @@ impl Function {
22182223 cfunc_args. append ( & mut args) ;
22192224 let ccall = fun. push_insn ( block, Insn :: CCall { cfun, args : cfunc_args, name : method_id, return_type, elidable } ) ;
22202225 fun. make_equal_to ( send_insn_id, ccall) ;
2221- return Ok ( ( ) ) ;
2226+ return Ok ( ( ) )
22222227 }
22232228 }
22242229 // Variadic method
22252230 -1 => {
22262231 if unsafe { rb_zjit_method_tracing_currently_enabled ( ) } {
2227- return Err ( ( ) ) ;
2232+ return Err ( None ) ;
22282233 }
22292234 // The method gets a pointer to the first argument
22302235 // func(int argc, VALUE *argv, VALUE recv)
@@ -2256,8 +2261,9 @@ impl Function {
22562261 } ) ;
22572262
22582263 fun. make_equal_to ( send_insn_id, ccall) ;
2259- return Ok ( ( ) ) ;
2264+ return Ok ( ( ) )
22602265 }
2266+
22612267 // Fall through for complex cases (splat, kwargs, etc.)
22622268 }
22632269 -2 => {
@@ -2267,7 +2273,7 @@ impl Function {
22672273 _ => unreachable ! ( "unknown cfunc kind: argc={argc}" )
22682274 }
22692275
2270- Err ( ( ) )
2276+ Err ( Some ( method ) )
22712277 }
22722278
22732279 for block in self . rpo ( ) {
@@ -2276,8 +2282,23 @@ impl Function {
22762282 for insn_id in old_insns {
22772283 if let send @ Insn :: SendWithoutBlock { recv, .. } = self . find ( insn_id) {
22782284 let recv_type = self . type_of ( recv) ;
2279- if reduce_to_ccall ( self , block, recv_type, send, insn_id) . is_ok ( ) {
2280- continue ;
2285+ match reduce_to_ccall ( self , block, recv_type, send, insn_id) {
2286+ Ok ( ( ) ) => continue ,
2287+ Err ( Some ( cme) ) => {
2288+ if get_option ! ( stats) {
2289+ let owner = unsafe { ( * cme) . owner } ;
2290+ let called_id = unsafe { ( * cme) . called_id } ;
2291+ let class_name = get_class_name ( owner) ;
2292+ let method_name = called_id. contents_lossy ( ) ;
2293+ let qualified_method_name = format ! ( "{}#{}" , class_name, method_name) ;
2294+ let unoptimized_cfunc_counter_pointers = ZJITState :: get_unoptimized_cfunc_counter_pointers ( ) ;
2295+ let counter_ptr = unoptimized_cfunc_counter_pointers. entry ( qualified_method_name. clone ( ) ) . or_insert_with ( || Box :: new ( 0 ) ) ;
2296+ let counter_ptr = & mut * * counter_ptr as * mut u64 ;
2297+
2298+ self . push_insn ( block, Insn :: IncrCounterPtr { counter_ptr } ) ;
2299+ }
2300+ }
2301+ _ => { }
22812302 }
22822303 }
22832304 self . push_insn_id ( block, insn_id) ;
@@ -2423,7 +2444,8 @@ impl Function {
24232444 | & Insn :: LoadSelf
24242445 | & Insn :: GetLocal { .. }
24252446 | & Insn :: PutSpecialObject { .. }
2426- | & Insn :: IncrCounter ( _) =>
2447+ | & Insn :: IncrCounter ( _)
2448+ | & Insn :: IncrCounterPtr { .. } =>
24272449 { }
24282450 & Insn :: PatchPoint { state, .. }
24292451 | & Insn :: CheckInterrupts { state }
0 commit comments