@@ -644,10 +644,13 @@ pub enum Insn {
644644 IfTrue { val : InsnId , target : BranchEdge } ,
645645 IfFalse { val : InsnId , target : BranchEdge } ,
646646
647- /// Call a C function
647+ /// Call a C function without pushing a frame
648648 /// `name` is for printing purposes only
649649 CCall { cfun : * const u8 , args : Vec < InsnId > , name : ID , return_type : Type , elidable : bool } ,
650650
651+ /// Call a C function that pushes a frame
652+ CallCFunc { cfun : * const u8 , args : Vec < InsnId > , cme : * const rb_callable_method_entry_t , name : ID , state : InsnId } ,
653+
651654 /// Call a variadic C function with signature: func(int argc, VALUE *argv, VALUE recv)
652655 /// This handles frame setup, argv creation, and frame teardown all in one
653656 CCallVariadic {
@@ -1027,6 +1030,13 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
10271030 }
10281031 Ok ( ( ) )
10291032 } ,
1033+ Insn :: CallCFunc { cfun, args, name, .. } => {
1034+ write ! ( f, "CallCFunc {}@{:p}" , name. contents_lossy( ) , self . ptr_map. map_ptr( cfun) ) ?;
1035+ for arg in args {
1036+ write ! ( f, ", {arg}" ) ?;
1037+ }
1038+ Ok ( ( ) )
1039+ } ,
10301040 Insn :: CCallVariadic { cfun, recv, args, name, .. } => {
10311041 write ! ( f, "CCallVariadic {}@{:p}, {recv}" , name. contents_lossy( ) , self . ptr_map. map_ptr( cfun) ) ?;
10321042 for arg in args {
@@ -1546,6 +1556,7 @@ impl Function {
15461556 & ObjectAlloc { val, state } => ObjectAlloc { val : find ! ( val) , state } ,
15471557 & ObjectAllocClass { class, state } => ObjectAllocClass { class, state : find ! ( state) } ,
15481558 & CCall { cfun, ref args, name, return_type, elidable } => CCall { cfun, args : find_vec ! ( args) , name, return_type, elidable } ,
1559+ & CallCFunc { cfun, ref args, cme, name, state } => CallCFunc { cfun, args : find_vec ! ( args) , cme, name, state : find ! ( state) } ,
15491560 & CCallVariadic { cfun, recv, ref args, cme, name, state } => CCallVariadic {
15501561 cfun, recv : find ! ( recv) , args : find_vec ! ( args) , cme, name, state
15511562 } ,
@@ -1646,6 +1657,7 @@ impl Function {
16461657 Insn :: NewRangeFixnum { .. } => types:: RangeExact ,
16471658 Insn :: ObjectAlloc { .. } => types:: HeapObject ,
16481659 Insn :: ObjectAllocClass { class, .. } => Type :: from_class ( * class) ,
1660+ Insn :: CallCFunc { .. } => types:: BasicObject ,
16491661 Insn :: CCall { return_type, .. } => * return_type,
16501662 Insn :: CCallVariadic { .. } => types:: BasicObject ,
16511663 Insn :: GuardType { val, guard_type, .. } => self . type_of ( * val) . intersection ( * guard_type) ,
@@ -2296,35 +2308,37 @@ impl Function {
22962308 return Err ( Some ( method) ) ;
22972309 }
22982310
2299- // Filter for a leaf and GC free function
2300- use crate :: cruby_methods:: FnProperties ;
2301- let Some ( FnProperties { leaf : true , no_gc : true , return_type, elidable } ) =
2302- ZJITState :: get_method_annotations ( ) . get_cfunc_properties ( method)
2303- else {
2304- fun. set_dynamic_send_reason ( send_insn_id, SendWithoutBlockCfuncNotVariadic ) ;
2305- return Err ( Some ( method) ) ;
2306- } ;
2307-
23082311 let ci_flags = unsafe { vm_ci_flag ( call_info) } ;
2309- // Filter for simple call sites (i.e. no splats etc.)
2310- if ci_flags & VM_CALL_ARGS_SIMPLE != 0 {
2311- gen_patch_points_for_optimized_ccall ( fun, block, recv_class, method_id, method, state) ;
23122312
2313- if recv_class. instance_can_have_singleton_class ( ) {
2314- fun. push_insn ( block, Insn :: PatchPoint { invariant : Invariant :: NoSingletonClass { klass : recv_class } , state } ) ;
2315- }
2316- if let Some ( profiled_type) = profiled_type {
2317- // Guard receiver class
2318- recv = fun. push_insn ( block, Insn :: GuardType { val : recv, guard_type : Type :: from_profiled_type ( profiled_type) , state } ) ;
2319- }
2313+ if ci_flags & VM_CALL_ARGS_SIMPLE == 0 {
2314+ return Err ( Some ( method) ) ;
2315+ }
23202316
2321- let cfun = unsafe { get_mct_func ( cfunc) } . cast ( ) ;
2322- let mut cfunc_args = vec ! [ recv] ;
2323- cfunc_args. append ( & mut args) ;
2317+ gen_patch_points_for_optimized_ccall ( fun, block, recv_class, method_id, method, state) ;
2318+ if recv_class. instance_can_have_singleton_class ( ) {
2319+ fun. push_insn ( block, Insn :: PatchPoint { invariant : Invariant :: NoSingletonClass { klass : recv_class } , state } ) ;
2320+ }
2321+ if let Some ( profiled_type) = profiled_type {
2322+ // Guard receiver class
2323+ recv = fun. push_insn ( block, Insn :: GuardType { val : recv, guard_type : Type :: from_profiled_type ( profiled_type) , state } ) ;
2324+ }
2325+ let cfun = unsafe { get_mct_func ( cfunc) } . cast ( ) ;
2326+ let mut cfunc_args = vec ! [ recv] ;
2327+ cfunc_args. append ( & mut args) ;
2328+
2329+ // Filter for a leaf and GC free function
2330+ use crate :: cruby_methods:: FnProperties ;
2331+ // Filter for simple call sites (i.e. no splats etc.)
2332+ // Commit to the replacement. Put PatchPoint.
2333+ if let Some ( FnProperties { leaf : true , no_gc : true , return_type, elidable } ) = ZJITState :: get_method_annotations ( ) . get_cfunc_properties ( method) {
23242334 let ccall = fun. push_insn ( block, Insn :: CCall { cfun, args : cfunc_args, name : method_id, return_type, elidable } ) ;
23252335 fun. make_equal_to ( send_insn_id, ccall) ;
2326- return Ok ( ( ) )
2336+ } else {
2337+ let ccall = fun. push_insn ( block, Insn :: CallCFunc { cfun, args : cfunc_args, cme : method, name : method_id, state } ) ;
2338+ fun. make_equal_to ( send_insn_id, ccall) ;
23272339 }
2340+
2341+ return Ok ( ( ) ) ;
23282342 }
23292343 // Variadic method
23302344 -1 => {
@@ -2637,7 +2651,8 @@ impl Function {
26372651 worklist. extend ( args) ;
26382652 worklist. push_back ( state) ;
26392653 }
2640- & Insn :: InvokeBuiltin { ref args, state, .. }
2654+ & Insn :: CallCFunc { ref args, state, .. }
2655+ | & Insn :: InvokeBuiltin { ref args, state, .. }
26412656 | & Insn :: InvokeBlock { ref args, state, .. } => {
26422657 worklist. extend ( args) ;
26432658 worklist. push_back ( state)
@@ -10864,8 +10879,10 @@ mod opt_tests {
1086410879 Jump bb2(v4)
1086510880 bb2(v6:BasicObject):
1086610881 v11:HashExact = NewHash
10867- v13:BasicObject = SendWithoutBlock v11, :dup
10868- v15:BasicObject = SendWithoutBlock v13, :freeze
10882+ PatchPoint MethodRedefined(Hash@0x1000, dup@0x1008, cme:0x1010)
10883+ PatchPoint NoSingletonClass(Hash@0x1000)
10884+ v24:BasicObject = CallCFunc dup@0x1038, v11
10885+ v15:BasicObject = SendWithoutBlock v24, :freeze
1086910886 CheckInterrupts
1087010887 Return v15
1087110888 " ) ;
@@ -10955,8 +10972,10 @@ mod opt_tests {
1095510972 Jump bb2(v4)
1095610973 bb2(v6:BasicObject):
1095710974 v11:ArrayExact = NewArray
10958- v13:BasicObject = SendWithoutBlock v11, :dup
10959- v15:BasicObject = SendWithoutBlock v13, :freeze
10975+ PatchPoint MethodRedefined(Array@0x1000, dup@0x1008, cme:0x1010)
10976+ PatchPoint NoSingletonClass(Array@0x1000)
10977+ v24:BasicObject = CallCFunc dup@0x1038, v11
10978+ v15:BasicObject = SendWithoutBlock v24, :freeze
1096010979 CheckInterrupts
1096110980 Return v15
1096210981 " ) ;
@@ -11047,8 +11066,10 @@ mod opt_tests {
1104711066 bb2(v6:BasicObject):
1104811067 v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
1104911068 v12:StringExact = StringCopy v10
11050- v14:BasicObject = SendWithoutBlock v12, :dup
11051- v16:BasicObject = SendWithoutBlock v14, :freeze
11069+ PatchPoint MethodRedefined(String@0x1008, dup@0x1010, cme:0x1018)
11070+ PatchPoint NoSingletonClass(String@0x1008)
11071+ v25:BasicObject = CallCFunc dup@0x1040, v12
11072+ v16:BasicObject = SendWithoutBlock v25, :freeze
1105211073 CheckInterrupts
1105311074 Return v16
1105411075 " ) ;
@@ -11140,8 +11161,10 @@ mod opt_tests {
1114011161 bb2(v6:BasicObject):
1114111162 v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
1114211163 v12:StringExact = StringCopy v10
11143- v14:BasicObject = SendWithoutBlock v12, :dup
11144- v16:BasicObject = SendWithoutBlock v14, :-@
11164+ PatchPoint MethodRedefined(String@0x1008, dup@0x1010, cme:0x1018)
11165+ PatchPoint NoSingletonClass(String@0x1008)
11166+ v25:BasicObject = CallCFunc dup@0x1040, v12
11167+ v16:BasicObject = SendWithoutBlock v25, :-@
1114511168 CheckInterrupts
1114611169 Return v16
1114711170 " ) ;
@@ -11279,8 +11302,11 @@ mod opt_tests {
1127911302 bb2(v8:BasicObject, v9:BasicObject):
1128011303 v13:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
1128111304 v25:BasicObject = GuardTypeNot v9, String
11282- v26:BasicObject = SendWithoutBlock v9, :to_s
11283- v17:String = AnyToString v9, str: v26
11305+ PatchPoint MethodRedefined(Array@0x1008, to_s@0x1010, cme:0x1018)
11306+ PatchPoint NoSingletonClass(Array@0x1008)
11307+ v30:ArrayExact = GuardType v9, ArrayExact
11308+ v31:BasicObject = CallCFunc to_s@0x1040, v30
11309+ v17:String = AnyToString v9, str: v31
1128411310 v19:StringExact = StringConcat v13, v17
1128511311 CheckInterrupts
1128611312 Return v19
0 commit comments