@@ -595,9 +595,6 @@ pub enum Insn {
595595 GetLocal { level : u32 , ep_offset : u32 } ,
596596 /// Set a local variable in a higher scope or the heap
597597 SetLocal { level : u32 , ep_offset : u32 , val : InsnId } ,
598- /// Get a special singleton instance `rb_block_param_proxy` if the block
599- /// handler for the EP specified by `level` is an ISEQ or an ifunc.
600- GetBlockParamProxy { level : u32 , state : InsnId } ,
601598 GetSpecialSymbol { symbol_type : SpecialBackrefSymbol , state : InsnId } ,
602599 GetSpecialNumber { nth : u64 , state : InsnId } ,
603600
@@ -679,6 +676,9 @@ pub enum Insn {
679676 GuardBitEquals { val : InsnId , expected : VALUE , state : InsnId } ,
680677 /// Side-exit if val doesn't have the expected shape.
681678 GuardShape { val : InsnId , shape : ShapeId , state : InsnId } ,
679+ /// Side-exit if the block param has been modified or the block handler for the frame
680+ /// is neither ISEQ nor ifunc, which makes it incompatible with rb_block_param_proxy.
681+ GuardBlockParamProxy { level : u32 , state : InsnId } ,
682682
683683 /// Generate no code (or padding if necessary) and insert a patch point
684684 /// that can be rewritten to a side exit when the Invariant is broken.
@@ -704,7 +704,7 @@ impl Insn {
704704 | Insn :: PatchPoint { .. } | Insn :: SetIvar { .. } | Insn :: ArrayExtend { .. }
705705 | Insn :: ArrayPush { .. } | Insn :: SideExit { .. } | Insn :: SetGlobal { .. }
706706 | Insn :: SetLocal { .. } | Insn :: Throw { .. } | Insn :: IncrCounter ( _)
707- | Insn :: CheckInterrupts { .. } => false ,
707+ | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. } => false ,
708708 _ => true ,
709709 }
710710 }
@@ -921,6 +921,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
921921 Insn :: GuardTypeNot { val, guard_type, .. } => { write ! ( f, "GuardTypeNot {val}, {}" , guard_type. print( self . ptr_map) ) } ,
922922 Insn :: GuardBitEquals { val, expected, .. } => { write ! ( f, "GuardBitEquals {val}, {}" , expected. print( self . ptr_map) ) } ,
923923 & Insn :: GuardShape { val, shape, .. } => { write ! ( f, "GuardShape {val}, {:p}" , self . ptr_map. map_shape( shape) ) } ,
924+ Insn :: GuardBlockParamProxy { level, .. } => write ! ( f, "GuardBlockParamProxy l{level}" ) ,
924925 Insn :: PatchPoint { invariant, .. } => { write ! ( f, "PatchPoint {}" , invariant. print( self . ptr_map) ) } ,
925926 Insn :: GetConstantPath { ic, .. } => { write ! ( f, "GetConstantPath {:p}" , self . ptr_map. map_ptr( ic) ) } ,
926927 Insn :: CCall { cfun, args, name, return_type : _, elidable : _ } => {
@@ -956,7 +957,6 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
956957 Insn :: SetGlobal { id, val, .. } => write ! ( f, "SetGlobal :{}, {val}" , id. contents_lossy( ) ) ,
957958 Insn :: GetLocal { level, ep_offset } => write ! ( f, "GetLocal l{level}, EP@{ep_offset}" ) ,
958959 Insn :: SetLocal { val, level, ep_offset } => write ! ( f, "SetLocal l{level}, EP@{ep_offset}, {val}" ) ,
959- Insn :: GetBlockParamProxy { level, .. } => write ! ( f, "GetBlockParamProxy l{level}" ) ,
960960 Insn :: GetSpecialSymbol { symbol_type, .. } => write ! ( f, "GetSpecialSymbol {symbol_type:?}" ) ,
961961 Insn :: GetSpecialNumber { nth, .. } => write ! ( f, "GetSpecialNumber {nth}" ) ,
962962 Insn :: ToArray { val, .. } => write ! ( f, "ToArray {val}" ) ,
@@ -1349,6 +1349,7 @@ impl Function {
13491349 & GuardTypeNot { val, guard_type, state } => GuardTypeNot { val : find ! ( val) , guard_type, state } ,
13501350 & GuardBitEquals { val, expected, state } => GuardBitEquals { val : find ! ( val) , expected, state } ,
13511351 & GuardShape { val, shape, state } => GuardShape { val : find ! ( val) , shape, state } ,
1352+ & GuardBlockParamProxy { level, state } => GuardBlockParamProxy { level, state : find ! ( state) } ,
13521353 & FixnumAdd { left, right, state } => FixnumAdd { left : find ! ( left) , right : find ! ( right) , state } ,
13531354 & FixnumSub { left, right, state } => FixnumSub { left : find ! ( left) , right : find ! ( right) , state } ,
13541355 & FixnumMult { left, right, state } => FixnumMult { left : find ! ( left) , right : find ! ( right) , state } ,
@@ -1424,7 +1425,6 @@ impl Function {
14241425 & NewRange { low, high, flag, state } => NewRange { low : find ! ( low) , high : find ! ( high) , flag, state : find ! ( state) } ,
14251426 & NewRangeFixnum { low, high, flag, state } => NewRangeFixnum { low : find ! ( low) , high : find ! ( high) , flag, state : find ! ( state) } ,
14261427 & ArrayMax { ref elements, state } => ArrayMax { elements : find_vec ! ( elements) , state : find ! ( state) } ,
1427- & GetBlockParamProxy { level, state } => GetBlockParamProxy { level, state : find ! ( state) } ,
14281428 & SetGlobal { id, val, state } => SetGlobal { id, val : find ! ( val) , state } ,
14291429 & GetIvar { self_val, id, state } => GetIvar { self_val : find ! ( self_val) , id, state } ,
14301430 & LoadIvarEmbedded { self_val, id, index } => LoadIvarEmbedded { self_val : find ! ( self_val) , id, index } ,
@@ -1465,7 +1465,7 @@ impl Function {
14651465 | Insn :: IfTrue { .. } | Insn :: IfFalse { .. } | Insn :: Return { .. } | Insn :: Throw { .. }
14661466 | Insn :: PatchPoint { .. } | Insn :: SetIvar { .. } | Insn :: ArrayExtend { .. }
14671467 | Insn :: ArrayPush { .. } | Insn :: SideExit { .. } | Insn :: SetLocal { .. } | Insn :: IncrCounter ( _)
1468- | Insn :: CheckInterrupts { .. } =>
1468+ | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. } =>
14691469 panic ! ( "Cannot infer type of instruction with no output: {}" , self . insns[ insn. 0 ] ) ,
14701470 Insn :: Const { val : Const :: Value ( val) } => Type :: from_value ( * val) ,
14711471 Insn :: Const { val : Const :: CBool ( val) } => Type :: from_cbool ( * val) ,
@@ -1537,7 +1537,6 @@ impl Function {
15371537 Insn :: ObjToString { .. } => types:: BasicObject ,
15381538 Insn :: AnyToString { .. } => types:: String ,
15391539 Insn :: GetLocal { .. } => types:: BasicObject ,
1540- Insn :: GetBlockParamProxy { .. } => types:: BasicObject ,
15411540 // The type of Snapshot doesn't really matter; it's never materialized. It's used only
15421541 // as a reference for FrameState, which we use to generate side-exit code.
15431542 Insn :: Snapshot { .. } => types:: Any ,
@@ -2370,7 +2369,7 @@ impl Function {
23702369 | & Insn :: LoadIvarExtended { self_val, .. } => {
23712370 worklist. push_back ( self_val) ;
23722371 }
2373- & Insn :: GetBlockParamProxy { state, .. } |
2372+ & Insn :: GuardBlockParamProxy { state, .. } |
23742373 & Insn :: GetGlobal { state, .. } |
23752374 & Insn :: GetSpecialSymbol { state, .. } |
23762375 & Insn :: GetSpecialNumber { state, .. } |
@@ -3515,7 +3514,9 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
35153514 YARVINSN_getblockparamproxy => {
35163515 let level = get_arg ( pc, 1 ) . as_u32 ( ) ;
35173516 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
3518- state. stack_push ( fun. push_insn ( block, Insn :: GetBlockParamProxy { level, state : exit_id } ) ) ;
3517+ fun. push_insn ( block, Insn :: GuardBlockParamProxy { level, state : exit_id } ) ;
3518+ // TODO(Shopify/ruby#753): GC root, so we should be able to avoid unnecessary GC tracing
3519+ state. stack_push ( fun. push_insn ( block, Insn :: Const { val : Const :: Value ( unsafe { rb_block_param_proxy } ) } ) ) ;
35193520 }
35203521 YARVINSN_pop => { state. stack_pop ( ) ?; }
35213522 YARVINSN_dup => { state. stack_push ( state. stack_top ( ) ?) ; }
@@ -5942,19 +5943,20 @@ mod tests {
59425943 v5:NilClass = Const Value(nil)
59435944 v10:BasicObject = InvokeBuiltin dir_s_open, v0, v1, v2
59445945 PatchPoint NoEPEscape(open)
5945- v16:BasicObject = GetBlockParamProxy l0
5946+ GuardBlockParamProxy l0
5947+ v17:BasicObject[BlockParamProxy] = Const Value(VALUE(0x1000))
59465948 CheckInterrupts
5947- v19 :CBool = Test v16
5948- IfFalse v19 , bb1(v0, v1, v2, v3, v4, v10)
5949+ v20 :CBool = Test v17
5950+ IfFalse v20 , bb1(v0, v1, v2, v3, v4, v10)
59495951 PatchPoint NoEPEscape(open)
5950- v26 :BasicObject = InvokeBlock, v10
5951- v30 :BasicObject = InvokeBuiltin dir_s_close, v0, v10
5952+ v27 :BasicObject = InvokeBlock, v10
5953+ v31 :BasicObject = InvokeBuiltin dir_s_close, v0, v10
59525954 CheckInterrupts
5953- Return v26
5954- bb1(v36:BasicObject, v37:BasicObject, v38:BasicObject, v39:BasicObject, v40:BasicObject, v41:BasicObject):
5955+ Return v27
5956+ bb1(v37:BasicObject, v38:BasicObject, v39:BasicObject, v40:BasicObject, v41:BasicObject, v42 :BasicObject):
59555957 PatchPoint NoEPEscape(open)
59565958 CheckInterrupts
5957- Return v41
5959+ Return v42
59585960 " ) ;
59595961 }
59605962
@@ -8158,11 +8160,12 @@ mod opt_tests {
81588160 assert_snapshot ! ( hir_string( "test" ) , @r"
81598161 fn test@<compiled>:2:
81608162 bb0(v0:BasicObject, v1:BasicObject):
8161- v6:BasicObject = GetBlockParamProxy l0
8162- v8:BasicObject = Send v0, 0x1000, :tap, v6
8163- v9:BasicObject = GetLocal l0, EP@3
8163+ GuardBlockParamProxy l0
8164+ v7:BasicObject[BlockParamProxy] = Const Value(VALUE(0x1000))
8165+ v9:BasicObject = Send v0, 0x1008, :tap, v7
8166+ v10:BasicObject = GetLocal l0, EP@3
81648167 CheckInterrupts
8165- Return v8
8168+ Return v9
81668169 " ) ;
81678170 }
81688171
0 commit comments