@@ -585,6 +585,7 @@ pub enum Insn {
585585 SendWithoutBlock { self_val : InsnId , cd : * const rb_call_data , args : Vec < InsnId > , state : InsnId } ,
586586 Send { self_val : InsnId , cd : * const rb_call_data , blockiseq : IseqPtr , args : Vec < InsnId > , state : InsnId } ,
587587 InvokeSuper { self_val : InsnId , cd : * const rb_call_data , blockiseq : IseqPtr , args : Vec < InsnId > , state : InsnId } ,
588+ InvokeBlock { cd : * const rb_call_data , args : Vec < InsnId > , state : InsnId } ,
588589
589590 /// Optimized ISEQ call
590591 SendWithoutBlockDirect {
@@ -845,6 +846,13 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
845846 }
846847 Ok ( ( ) )
847848 }
849+ Insn :: InvokeBlock { args, .. } => {
850+ write ! ( f, "InvokeBlock" ) ?;
851+ for arg in args {
852+ write ! ( f, ", {arg}" ) ?;
853+ }
854+ Ok ( ( ) )
855+ }
848856 Insn :: InvokeBuiltin { bf, args, .. } => {
849857 write ! ( f, "InvokeBuiltin {}" , unsafe { CStr :: from_ptr( bf. name) } . to_str( ) . unwrap( ) ) ?;
850858 for arg in args {
@@ -1349,6 +1357,11 @@ impl Function {
13491357 args : find_vec ! ( args) ,
13501358 state,
13511359 } ,
1360+ & InvokeBlock { cd, ref args, state } => InvokeBlock {
1361+ cd,
1362+ args : find_vec ! ( args) ,
1363+ state,
1364+ } ,
13521365 & InvokeBuiltin { bf, ref args, state, return_type } => InvokeBuiltin { bf, args : find_vec ! ( args) , state, return_type } ,
13531366 & ArrayDup { val, state } => ArrayDup { val : find ! ( val) , state } ,
13541367 & HashDup { val, state } => HashDup { val : find ! ( val) , state } ,
@@ -1463,6 +1476,7 @@ impl Function {
14631476 Insn :: SendWithoutBlockDirect { .. } => types:: BasicObject ,
14641477 Insn :: Send { .. } => types:: BasicObject ,
14651478 Insn :: InvokeSuper { .. } => types:: BasicObject ,
1479+ Insn :: InvokeBlock { .. } => types:: BasicObject ,
14661480 Insn :: InvokeBuiltin { return_type, .. } => return_type. unwrap_or ( types:: BasicObject ) ,
14671481 Insn :: Defined { pushval, .. } => Type :: from_value ( * pushval) . union ( types:: NilClass ) ,
14681482 Insn :: DefinedIvar { .. } => types:: BasicObject ,
@@ -2276,7 +2290,8 @@ impl Function {
22762290 worklist. extend ( args) ;
22772291 worklist. push_back ( state) ;
22782292 }
2279- & Insn :: InvokeBuiltin { ref args, state, .. } => {
2293+ & Insn :: InvokeBuiltin { ref args, state, .. }
2294+ | & Insn :: InvokeBlock { ref args, state, .. } => {
22802295 worklist. extend ( args) ;
22812296 worklist. push_back ( state)
22822297 }
@@ -3651,6 +3666,21 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
36513666 }
36523667 }
36533668 }
3669+ YARVINSN_invokeblock => {
3670+ let cd: * const rb_call_data = get_arg ( pc, 0 ) . as_ptr ( ) ;
3671+ let call_info = unsafe { rb_get_call_data_ci ( cd) } ;
3672+ if let Err ( call_type) = unknown_call_type ( unsafe { rb_vm_ci_flag ( call_info) } ) {
3673+ // Unknown call type; side-exit into the interpreter
3674+ let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
3675+ fun. push_insn ( block, Insn :: SideExit { state : exit_id, reason : SideExitReason :: UnhandledCallType ( call_type) } ) ;
3676+ break ; // End the block
3677+ }
3678+ let argc = unsafe { vm_ci_argc ( ( * cd) . ci ) } ;
3679+ let args = state. stack_pop_n ( argc as usize ) ?;
3680+ let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
3681+ let result = fun. push_insn ( block, Insn :: InvokeBlock { cd, args, state : exit_id } ) ;
3682+ state. stack_push ( result) ;
3683+ }
36543684 YARVINSN_getglobal => {
36553685 let id = ID ( get_arg ( pc, 0 ) . as_u64 ( ) ) ;
36563686 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
@@ -5835,11 +5865,14 @@ mod tests {
58355865 v19:CBool = Test v16
58365866 IfFalse v19, bb1(v0, v1, v2, v3, v4, v10)
58375867 PatchPoint NoEPEscape(open)
5838- SideExit UnhandledYARVInsn(invokeblock)
5839- bb1(v27:BasicObject, v28:BasicObject, v29:BasicObject, v30:BasicObject, v31:BasicObject, v32:BasicObject):
5868+ v26:BasicObject = InvokeBlock, v10
5869+ v30:BasicObject = InvokeBuiltin dir_s_close, v0, v10
5870+ CheckInterrupts
5871+ Return v26
5872+ bb1(v36:BasicObject, v37:BasicObject, v38:BasicObject, v39:BasicObject, v40:BasicObject, v41:BasicObject):
58405873 PatchPoint NoEPEscape(open)
58415874 CheckInterrupts
5842- Return v32
5875+ Return v41
58435876 " ) ;
58445877 }
58455878
@@ -6028,6 +6061,38 @@ mod tests {
60286061 Throw TAG_BREAK, v6
60296062 " ) ;
60306063 }
6064+
6065+ #[ test]
6066+ fn test_invokeblock ( ) {
6067+ eval ( r#"
6068+ def test
6069+ yield
6070+ end
6071+ "# ) ;
6072+ assert_snapshot ! ( hir_string( "test" ) , @r"
6073+ fn test@<compiled>:3:
6074+ bb0(v0:BasicObject):
6075+ v5:BasicObject = InvokeBlock
6076+ CheckInterrupts
6077+ Return v5
6078+ " ) ;
6079+ }
6080+
6081+ #[ test]
6082+ fn test_invokeblock_with_args ( ) {
6083+ eval ( r#"
6084+ def test(x, y)
6085+ yield x, y
6086+ end
6087+ "# ) ;
6088+ assert_snapshot ! ( hir_string( "test" ) , @r"
6089+ fn test@<compiled>:3:
6090+ bb0(v0:BasicObject, v1:BasicObject, v2:BasicObject):
6091+ v7:BasicObject = InvokeBlock, v1, v2
6092+ CheckInterrupts
6093+ Return v7
6094+ " ) ;
6095+ }
60316096}
60326097
60336098#[ cfg( test) ]
0 commit comments