@@ -462,6 +462,8 @@ pub enum SideExitReason {
462462 CalleeSideExit ,
463463 ObjToStringFallback ,
464464 Interrupt ,
465+ BlockParamProxyModified ,
466+ BlockParamProxyNotIseqOrIfunc ,
465467}
466468
467469impl std:: fmt:: Display for SideExitReason {
@@ -556,6 +558,9 @@ pub enum Insn {
556558 GetLocal { level : u32 , ep_offset : u32 } ,
557559 /// Set a local variable in a higher scope or the heap
558560 SetLocal { level : u32 , ep_offset : u32 , val : InsnId } ,
561+ /// Get a special singleton instance `rb_block_param_proxy` if the block
562+ /// handler for the EP specified by `level` is an ISEQ or an ifunc.
563+ GetBlockParamProxy { level : u32 , state : InsnId } ,
559564 GetSpecialSymbol { symbol_type : SpecialBackrefSymbol , state : InsnId } ,
560565 GetSpecialNumber { nth : u64 , state : InsnId } ,
561566
@@ -900,6 +905,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
900905 Insn :: SetGlobal { id, val, .. } => write ! ( f, "SetGlobal :{}, {val}" , id. contents_lossy( ) ) ,
901906 Insn :: GetLocal { level, ep_offset } => write ! ( f, "GetLocal l{level}, EP@{ep_offset}" ) ,
902907 Insn :: SetLocal { val, level, ep_offset } => write ! ( f, "SetLocal l{level}, EP@{ep_offset}, {val}" ) ,
908+ Insn :: GetBlockParamProxy { level, .. } => write ! ( f, "GetBlockParamProxy l{level}" ) ,
903909 Insn :: GetSpecialSymbol { symbol_type, .. } => write ! ( f, "GetSpecialSymbol {symbol_type:?}" ) ,
904910 Insn :: GetSpecialNumber { nth, .. } => write ! ( f, "GetSpecialNumber {nth}" ) ,
905911 Insn :: ToArray { val, .. } => write ! ( f, "ToArray {val}" ) ,
@@ -1361,6 +1367,7 @@ impl Function {
13611367 & NewRange { low, high, flag, state } => NewRange { low : find ! ( low) , high : find ! ( high) , flag, state : find ! ( state) } ,
13621368 & NewRangeFixnum { low, high, flag, state } => NewRangeFixnum { low : find ! ( low) , high : find ! ( high) , flag, state : find ! ( state) } ,
13631369 & ArrayMax { ref elements, state } => ArrayMax { elements : find_vec ! ( elements) , state : find ! ( state) } ,
1370+ & GetBlockParamProxy { level, state } => GetBlockParamProxy { level, state : find ! ( state) } ,
13641371 & SetGlobal { id, val, state } => SetGlobal { id, val : find ! ( val) , state } ,
13651372 & GetIvar { self_val, id, state } => GetIvar { self_val : find ! ( self_val) , id, state } ,
13661373 & LoadIvarEmbedded { self_val, id, index } => LoadIvarEmbedded { self_val : find ! ( self_val) , id, index } ,
@@ -1472,6 +1479,7 @@ impl Function {
14721479 Insn :: ObjToString { .. } => types:: BasicObject ,
14731480 Insn :: AnyToString { .. } => types:: String ,
14741481 Insn :: GetLocal { .. } => types:: BasicObject ,
1482+ Insn :: GetBlockParamProxy { .. } => types:: BasicObject ,
14751483 // The type of Snapshot doesn't really matter; it's never materialized. It's used only
14761484 // as a reference for FrameState, which we use to generate side-exit code.
14771485 Insn :: Snapshot { .. } => types:: Any ,
@@ -2300,6 +2308,7 @@ impl Function {
23002308 | & Insn :: LoadIvarExtended { self_val, .. } => {
23012309 worklist. push_back ( self_val) ;
23022310 }
2311+ & Insn :: GetBlockParamProxy { state, .. } |
23032312 & Insn :: GetGlobal { state, .. } |
23042313 & Insn :: GetSpecialSymbol { state, .. } |
23052314 & Insn :: GetSpecialNumber { state, .. } |
@@ -3466,6 +3475,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
34663475 let level = get_arg ( pc, 1 ) . as_u32 ( ) ;
34673476 fun. push_insn ( block, Insn :: SetLocal { val : state. stack_pop ( ) ?, ep_offset, level } ) ;
34683477 }
3478+ YARVINSN_getblockparamproxy => {
3479+ let level = get_arg ( pc, 1 ) . as_u32 ( ) ;
3480+ let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
3481+ state. stack_push ( fun. push_insn ( block, Insn :: GetBlockParamProxy { level, state : exit_id } ) ) ;
3482+ }
34693483 YARVINSN_pop => { state. stack_pop ( ) ?; }
34703484 YARVINSN_dup => { state. stack_push ( state. stack_top ( ) ?) ; }
34713485 YARVINSN_dupn => {
@@ -5816,7 +5830,16 @@ mod tests {
58165830 v5:NilClass = Const Value(nil)
58175831 v10:BasicObject = InvokeBuiltin dir_s_open, v0, v1, v2
58185832 PatchPoint NoEPEscape(open)
5819- SideExit UnhandledYARVInsn(getblockparamproxy)
5833+ v16:BasicObject = GetBlockParamProxy l0
5834+ CheckInterrupts
5835+ v19:CBool = Test v16
5836+ IfFalse v19, bb1(v0, v1, v2, v3, v4, v10)
5837+ PatchPoint NoEPEscape(open)
5838+ SideExit UnhandledYARVInsn(invokeblock)
5839+ bb1(v27:BasicObject, v28:BasicObject, v29:BasicObject, v30:BasicObject, v31:BasicObject, v32:BasicObject):
5840+ PatchPoint NoEPEscape(open)
5841+ CheckInterrupts
5842+ Return v32
58205843 " ) ;
58215844 }
58225845
@@ -7980,6 +8003,19 @@ mod opt_tests {
79808003 " ) ;
79818004 }
79828005
8006+ #[ test]
8007+ fn test_getblockparamproxy ( ) {
8008+ eval ( "
8009+ def test(&block) = tap(&block)
8010+ " ) ;
8011+ assert_snapshot ! ( hir_string( "test" ) , @r"
8012+ fn test@<compiled>:2:
8013+ bb0(v0:BasicObject, v1:BasicObject):
8014+ v6:BasicObject = GetBlockParamProxy l0
8015+ SideExit UnhandledCallType(BlockArg)
8016+ " ) ;
8017+ }
8018+
79838019 #[ test]
79848020 fn test_getinstancevariable ( ) {
79858021 eval ( "
0 commit comments