@@ -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 }
@@ -3665,6 +3680,21 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
36653680 }
36663681 }
36673682 }
3683+ YARVINSN_invokeblock => {
3684+ let cd: * const rb_call_data = get_arg ( pc, 0 ) . as_ptr ( ) ;
3685+ let call_info = unsafe { rb_get_call_data_ci ( cd) } ;
3686+ if let Err ( call_type) = unknown_call_type ( unsafe { rb_vm_ci_flag ( call_info) } ) {
3687+ // Unknown call type; side-exit into the interpreter
3688+ let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
3689+ fun. push_insn ( block, Insn :: SideExit { state : exit_id, reason : SideExitReason :: UnhandledCallType ( call_type) } ) ;
3690+ break ; // End the block
3691+ }
3692+ let argc = unsafe { vm_ci_argc ( ( * cd) . ci ) } ;
3693+ let args = state. stack_pop_n ( argc as usize ) ?;
3694+ let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
3695+ let result = fun. push_insn ( block, Insn :: InvokeBlock { cd, args, state : exit_id } ) ;
3696+ state. stack_push ( result) ;
3697+ }
36683698 YARVINSN_getglobal => {
36693699 let id = ID ( get_arg ( pc, 0 ) . as_u64 ( ) ) ;
36703700 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
@@ -6028,6 +6058,38 @@ mod tests {
60286058 Throw TAG_BREAK, v6
60296059 " ) ;
60306060 }
6061+
6062+ #[ test]
6063+ fn test_invokeblock ( ) {
6064+ eval ( r#"
6065+ def test
6066+ yield
6067+ end
6068+ "# ) ;
6069+ assert_snapshot ! ( hir_string( "test" ) , @r"
6070+ fn test@<compiled>:3:
6071+ bb0(v0:BasicObject):
6072+ v5:BasicObject = InvokeBlock
6073+ CheckInterrupts
6074+ Return v5
6075+ " ) ;
6076+ }
6077+
6078+ #[ test]
6079+ fn test_invokeblock_with_args ( ) {
6080+ eval ( r#"
6081+ def test(x, y)
6082+ yield x, y
6083+ end
6084+ "# ) ;
6085+ assert_snapshot ! ( hir_string( "test" ) , @r"
6086+ fn test@<compiled>:3:
6087+ bb0(v0:BasicObject, v1:BasicObject, v2:BasicObject):
6088+ v7:BasicObject = InvokeBlock, v1, v2
6089+ CheckInterrupts
6090+ Return v7
6091+ " ) ;
6092+ }
60316093}
60326094
60336095#[ cfg( test) ]
0 commit comments