@@ -522,7 +522,12 @@ pub enum Insn {
522522 } ,
523523
524524 // Invoke a builtin function
525- InvokeBuiltin { bf : rb_builtin_function , args : Vec < InsnId > , state : InsnId } ,
525+ InvokeBuiltin {
526+ bf : rb_builtin_function ,
527+ args : Vec < InsnId > ,
528+ state : InsnId ,
529+ return_type : Option < Type > , // None for unannotated builtins
530+ } ,
526531
527532 /// Control flow instructions
528533 Return { val : InsnId } ,
@@ -1163,7 +1168,7 @@ impl Function {
11631168 args : find_vec ! ( args) ,
11641169 state,
11651170 } ,
1166- & InvokeBuiltin { bf, ref args, state } => InvokeBuiltin { bf : bf , args : find_vec ! ( args) , state } ,
1171+ & InvokeBuiltin { bf, ref args, state, return_type } => InvokeBuiltin { bf, args : find_vec ! ( args) , state, return_type } ,
11671172 & ArrayDup { val, state } => ArrayDup { val : find ! ( val) , state } ,
11681173 & HashDup { val, state } => HashDup { val : find ! ( val) , state } ,
11691174 & CCall { cfun, ref args, name, return_type, elidable } => CCall { cfun, args : find_vec ! ( args) , name, return_type, elidable } ,
@@ -1260,7 +1265,7 @@ impl Function {
12601265 Insn :: SendWithoutBlock { .. } => types:: BasicObject ,
12611266 Insn :: SendWithoutBlockDirect { .. } => types:: BasicObject ,
12621267 Insn :: Send { .. } => types:: BasicObject ,
1263- Insn :: InvokeBuiltin { .. } => types:: BasicObject ,
1268+ Insn :: InvokeBuiltin { return_type , .. } => return_type . unwrap_or ( types:: BasicObject ) ,
12641269 Insn :: Defined { .. } => types:: BasicObject ,
12651270 Insn :: DefinedIvar { .. } => types:: BasicObject ,
12661271 Insn :: GetConstantPath { .. } => types:: BasicObject ,
@@ -3119,7 +3124,18 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
31193124 args. reverse ( ) ;
31203125
31213126 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
3122- let insn_id = fun. push_insn ( block, Insn :: InvokeBuiltin { bf, args, state : exit_id } ) ;
3127+
3128+ // Check if this builtin is annotated
3129+ let return_type = ZJITState :: get_method_annotations ( )
3130+ . get_builtin_properties ( & bf)
3131+ . map ( |props| props. return_type ) ;
3132+
3133+ let insn_id = fun. push_insn ( block, Insn :: InvokeBuiltin {
3134+ bf,
3135+ args,
3136+ state : exit_id,
3137+ return_type,
3138+ } ) ;
31233139 state. stack_push ( insn_id) ;
31243140 }
31253141 YARVINSN_opt_invokebuiltin_delegate |
@@ -3134,7 +3150,18 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
31343150 }
31353151
31363152 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
3137- let insn_id = fun. push_insn ( block, Insn :: InvokeBuiltin { bf, args, state : exit_id } ) ;
3153+
3154+ // Check if this builtin is annotated
3155+ let return_type = ZJITState :: get_method_annotations ( )
3156+ . get_builtin_properties ( & bf)
3157+ . map ( |props| props. return_type ) ;
3158+
3159+ let insn_id = fun. push_insn ( block, Insn :: InvokeBuiltin {
3160+ bf,
3161+ args,
3162+ state : exit_id,
3163+ return_type,
3164+ } ) ;
31383165 state. stack_push ( insn_id) ;
31393166 }
31403167 YARVINSN_objtostring => {
@@ -4973,17 +5000,32 @@ mod tests {
49735000 }
49745001
49755002 #[ test]
4976- fn test_invokebuiltin_delegate_with_args ( ) {
5003+ fn test_invokebuiltin_delegate_annotated ( ) {
49775004 assert_method_hir_with_opcode ( "Float" , YARVINSN_opt_invokebuiltin_delegate_leave , expect ! [ [ r#"
49785005 fn Float@<internal:kernel>:197:
49795006 bb0(v0:BasicObject, v1:BasicObject, v2:BasicObject, v3:BasicObject):
4980- v6:BasicObject = InvokeBuiltin rb_f_float, v0, v1, v2
5007+ v6:Flonum = InvokeBuiltin rb_f_float, v0, v1, v2
49815008 Jump bb1(v0, v1, v2, v3, v6)
4982- bb1(v8:BasicObject, v9:BasicObject, v10:BasicObject, v11:BasicObject, v12:BasicObject ):
5009+ bb1(v8:BasicObject, v9:BasicObject, v10:BasicObject, v11:BasicObject, v12:Flonum ):
49835010 Return v12
49845011 "# ] ] ) ;
49855012 }
49865013
5014+ #[ test]
5015+ fn test_invokebuiltin_delegate_with_args ( ) {
5016+ // Using an unannotated builtin to test InvokeBuiltin generation
5017+ let iseq = crate :: cruby:: with_rubyvm ( || get_method_iseq ( "Dir" , "open" ) ) ;
5018+ assert ! ( iseq_contains_opcode( iseq, YARVINSN_opt_invokebuiltin_delegate ) , "iseq Dir.open does not contain invokebuiltin" ) ;
5019+ let function = iseq_to_hir ( iseq) . unwrap ( ) ;
5020+ assert_function_hir ( function, expect ! [ [ r#"
5021+ fn open@<internal:dir>:184:
5022+ bb0(v0:BasicObject, v1:BasicObject, v2:BasicObject, v3:BasicObject, v4:BasicObject):
5023+ v5:NilClass = Const Value(nil)
5024+ v8:BasicObject = InvokeBuiltin dir_s_open, v0, v1, v2
5025+ SideExit UnknownOpcode(getblockparamproxy)
5026+ "# ] ] ) ;
5027+ }
5028+
49875029 #[ test]
49885030 fn test_invokebuiltin_delegate_without_args ( ) {
49895031 assert_method_hir_with_opcode ( "class" , YARVINSN_opt_invokebuiltin_delegate_leave , expect ! [ [ r#"
0 commit comments