@@ -483,6 +483,7 @@ pub enum SideExitReason {
483483 UnhandledHIRInsn ( InsnId ) ,
484484 UnhandledYARVInsn ( u32 ) ,
485485 UnhandledCallType ( CallType ) ,
486+ UnhandledBlockArg ,
486487 TooManyKeywordParameters ,
487488 FixnumAddOverflow ,
488489 FixnumSubOverflow ,
@@ -894,17 +895,6 @@ pub enum Insn {
894895 state : InsnId ,
895896 reason : SendFallbackReason ,
896897 } ,
897- /// Optimized super call to an ISEQ method
898- InvokeSuperDirect {
899- recv : InsnId ,
900- cd : * const rb_call_data ,
901- /// The CME of the method containing the super call (for runtime guard)
902- current_cme : * const rb_callable_method_entry_t ,
903- /// The resolved super method's CME (for PatchPoint and to get target ISEQ)
904- super_cme : * const rb_callable_method_entry_t ,
905- args : Vec < InsnId > ,
906- state : InsnId ,
907- } ,
908898 InvokeBlock {
909899 cd : * const rb_call_data ,
910900 args : Vec < InsnId > ,
@@ -981,6 +971,11 @@ pub enum Insn {
981971 GuardGreaterEq { left : InsnId , right : InsnId , state : InsnId } ,
982972 /// Side-exit if left is not less than right (both operands are C long).
983973 GuardLess { left : InsnId , right : InsnId , state : InsnId } ,
974+ /// Side-exit if the method entry at ep[VM_ENV_DATA_INDEX_ME_CREF] doesn't match the expected CME.
975+ /// Used to ensure super calls are made from the expected method context.
976+ GuardSuperMethodEntry { cme : * const rb_callable_method_entry_t , state : InsnId } ,
977+ /// Get the block handler from ep[VM_ENV_DATA_INDEX_SPECVAL] at the local EP (LEP).
978+ GetBlockHandler ,
984979
985980 /// Generate no code (or padding if necessary) and insert a patch point
986981 /// that can be rewritten to a side exit when the Invariant is broken.
@@ -1009,7 +1004,7 @@ impl Insn {
10091004 | Insn :: PatchPoint { .. } | Insn :: SetIvar { .. } | Insn :: SetClassVar { .. } | Insn :: ArrayExtend { .. }
10101005 | Insn :: ArrayPush { .. } | Insn :: SideExit { .. } | Insn :: SetGlobal { .. }
10111006 | Insn :: SetLocal { .. } | Insn :: Throw { .. } | Insn :: IncrCounter ( _) | Insn :: IncrCounterPtr { .. }
1012- | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. }
1007+ | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. } | Insn :: GuardSuperMethodEntry { .. }
10131008 | Insn :: StoreField { .. } | Insn :: WriteBarrier { .. } | Insn :: HashAset { .. }
10141009 | Insn :: ArrayAset { .. } => false ,
10151010 _ => true ,
@@ -1309,13 +1304,6 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
13091304 write ! ( f, " # SendFallbackReason: {reason}" ) ?;
13101305 Ok ( ( ) )
13111306 }
1312- Insn :: InvokeSuperDirect { recv, args, .. } => {
1313- write ! ( f, "InvokeSuperDirect {recv}" ) ?;
1314- for arg in args {
1315- write ! ( f, ", {arg}" ) ?;
1316- }
1317- Ok ( ( ) )
1318- }
13191307 Insn :: InvokeBlock { args, reason, .. } => {
13201308 write ! ( f, "InvokeBlock" ) ?;
13211309 for arg in args {
@@ -1363,6 +1351,8 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
13631351 Insn :: GuardNotShared { recv, .. } => write ! ( f, "GuardNotShared {recv}" ) ,
13641352 Insn :: GuardLess { left, right, .. } => write ! ( f, "GuardLess {left}, {right}" ) ,
13651353 Insn :: GuardGreaterEq { left, right, .. } => write ! ( f, "GuardGreaterEq {left}, {right}" ) ,
1354+ Insn :: GuardSuperMethodEntry { cme, .. } => write ! ( f, "GuardSuperMethodEntry {:p}" , self . ptr_map. map_ptr( cme) ) ,
1355+ Insn :: GetBlockHandler => write ! ( f, "GetBlockHandler" ) ,
13661356 Insn :: PatchPoint { invariant, .. } => { write ! ( f, "PatchPoint {}" , invariant. print( self . ptr_map) ) } ,
13671357 Insn :: GetConstantPath { ic, .. } => { write ! ( f, "GetConstantPath {:p}" , self . ptr_map. map_ptr( ic) ) } ,
13681358 Insn :: IsBlockGiven => { write ! ( f, "IsBlockGiven" ) } ,
@@ -2000,6 +1990,8 @@ impl Function {
20001990 & GuardNotShared { recv, state } => GuardNotShared { recv : find ! ( recv) , state } ,
20011991 & GuardGreaterEq { left, right, state } => GuardGreaterEq { left : find ! ( left) , right : find ! ( right) , state } ,
20021992 & GuardLess { left, right, state } => GuardLess { left : find ! ( left) , right : find ! ( right) , state } ,
1993+ & GuardSuperMethodEntry { cme, state } => GuardSuperMethodEntry { cme, state } ,
1994+ & GetBlockHandler => GetBlockHandler ,
20031995 & FixnumAdd { left, right, state } => FixnumAdd { left : find ! ( left) , right : find ! ( right) , state } ,
20041996 & FixnumSub { left, right, state } => FixnumSub { left : find ! ( left) , right : find ! ( right) , state } ,
20051997 & FixnumMult { left, right, state } => FixnumMult { left : find ! ( left) , right : find ! ( right) , state } ,
@@ -2065,14 +2057,6 @@ impl Function {
20652057 state,
20662058 reason,
20672059 } ,
2068- & InvokeSuperDirect { recv, cd, current_cme, super_cme, ref args, state } => InvokeSuperDirect {
2069- recv : find ! ( recv) ,
2070- cd,
2071- current_cme,
2072- super_cme,
2073- args : find_vec ! ( args) ,
2074- state,
2075- } ,
20762060 & InvokeBlock { cd, ref args, state, reason } => InvokeBlock {
20772061 cd,
20782062 args : find_vec ! ( args) ,
@@ -2180,8 +2164,9 @@ impl Function {
21802164 Insn :: SetGlobal { .. } | Insn :: Jump ( _) | Insn :: EntryPoint { .. }
21812165 | Insn :: IfTrue { .. } | Insn :: IfFalse { .. } | Insn :: Return { .. } | Insn :: Throw { .. }
21822166 | Insn :: PatchPoint { .. } | Insn :: SetIvar { .. } | Insn :: SetClassVar { .. } | Insn :: ArrayExtend { .. }
2183- | Insn :: ArrayPush { .. } | Insn :: SideExit { .. } | Insn :: SetLocal { .. } | Insn :: IncrCounter ( _)
2184- | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. } | Insn :: IncrCounterPtr { .. }
2167+ | Insn :: ArrayPush { .. } | Insn :: SideExit { .. } | Insn :: SetLocal { .. }
2168+ | Insn :: IncrCounter ( _) | Insn :: IncrCounterPtr { .. }
2169+ | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. } | Insn :: GuardSuperMethodEntry { .. }
21852170 | Insn :: StoreField { .. } | Insn :: WriteBarrier { .. } | Insn :: HashAset { .. } | Insn :: ArrayAset { .. } =>
21862171 panic ! ( "Cannot infer type of instruction with no output: {}. See Insn::has_output()." , self . insns[ insn. 0 ] ) ,
21872172 Insn :: Const { val : Const :: Value ( val) } => Type :: from_value ( * val) ,
@@ -2261,7 +2246,6 @@ impl Function {
22612246 Insn :: Send { .. } => types:: BasicObject ,
22622247 Insn :: SendForward { .. } => types:: BasicObject ,
22632248 Insn :: InvokeSuper { .. } => types:: BasicObject ,
2264- Insn :: InvokeSuperDirect { .. } => types:: BasicObject ,
22652249 Insn :: InvokeBlock { .. } => types:: BasicObject ,
22662250 Insn :: InvokeBuiltin { return_type, .. } => return_type. unwrap_or ( types:: BasicObject ) ,
22672251 Insn :: Defined { pushval, .. } => Type :: from_value ( * pushval) . union ( types:: NilClass ) ,
@@ -2289,6 +2273,7 @@ impl Function {
22892273 Insn :: AnyToString { .. } => types:: String ,
22902274 Insn :: GetLocal { rest_param : true , .. } => types:: ArrayExact ,
22912275 Insn :: GetLocal { .. } => types:: BasicObject ,
2276+ Insn :: GetBlockHandler => types:: RubyValue ,
22922277 // The type of Snapshot doesn't really matter; it's never materialized. It's used only
22932278 // as a reference for FrameState, which we use to generate side-exit code.
22942279 Insn :: Snapshot { .. } => types:: Any ,
@@ -3043,16 +3028,17 @@ impl Function {
30433028 self . push_insn_id ( block, insn_id) ; continue ;
30443029 }
30453030
3046- // Don't handle calls with complex arguments (kwarg, splat, kw_splat, blockarg, forwarding)
3031+ // Only handle bare `super` calls (i.e., with no arguments) so we can
3032+ // forward the caller arguments without needing to modify them.
30473033 let ci = unsafe { get_call_data_ci ( cd) } ;
30483034 let flags = unsafe { rb_vm_ci_flag ( ci) } ;
3049- if unspecializable_call_type ( flags) {
3035+ if ( flags & VM_CALL_ZSUPER ) == 0 || ( flags & VM_CALL_ARGS_SIMPLE ) == 0 {
30503036 self . push_insn_id ( block, insn_id) ; continue ;
30513037 }
30523038
30533039 let frame_state = self . frame_state ( state) ;
30543040
3055- // Get the profiled CME from the current method
3041+ // Get the profiled CME from the current method.
30563042 let Some ( profiles) = self . profiles . as_ref ( ) else {
30573043 self . push_insn_id ( block, insn_id) ; continue ;
30583044 } ;
@@ -3061,7 +3047,7 @@ impl Function {
30613047 self . push_insn_id ( block, insn_id) ; continue ;
30623048 } ;
30633049
3064- // Get defined_class and method ID from the profiled CME
3050+ // Get defined_class and method ID from the profiled CME.
30653051 let current_defined_class = unsafe { ( * current_cme) . defined_class } ;
30663052 let mid = unsafe { get_def_original_id ( ( * current_cme) . def ) } ;
30673053
@@ -3071,16 +3057,15 @@ impl Function {
30713057 self . push_insn_id ( block, insn_id) ; continue ;
30723058 }
30733059
3074- // Look up the super method
3060+ // Look up the super method.
30753061 let super_cme = unsafe { rb_callable_method_entry ( superclass, mid) } ;
30763062 if super_cme. is_null ( ) {
30773063 self . push_insn_id ( block, insn_id) ; continue ;
30783064 }
30793065
3080- // Check if it's an ISEQ method
3066+ // Check if it's an ISEQ method; bail if it isn't.
30813067 let def_type = unsafe { get_cme_def_type ( super_cme) } ;
30823068 if def_type != VM_METHOD_TYPE_ISEQ {
3083- // TODO: Handle CFUNCs
30843069 self . push_insn_id ( block, insn_id) ; continue ;
30853070 }
30863071
@@ -3091,8 +3076,7 @@ impl Function {
30913076 self . push_insn_id ( block, insn_id) ; continue ;
30923077 }
30933078
3094- // Add PatchPoints for method redefinition
3095- // TODO: Add guard that ep[-2] matches current_cme
3079+ // Add PatchPoint for method redefinition.
30963080 self . push_insn ( block, Insn :: PatchPoint {
30973081 invariant : Invariant :: MethodRedefined {
30983082 klass : unsafe { ( * super_cme) . defined_class } ,
@@ -3102,11 +3086,24 @@ impl Function {
31023086 state
31033087 } ) ;
31043088
3105- let send_direct = self . push_insn ( block, Insn :: InvokeSuperDirect {
3089+ // Guard that we're calling `super` from the expected method context.
3090+ self . push_insn ( block, Insn :: GuardSuperMethodEntry { cme : current_cme, state } ) ;
3091+
3092+ // Guard that no block is being passed (implicit or explicit).
3093+ let block_handler = self . push_insn ( block, Insn :: GetBlockHandler ) ;
3094+ self . push_insn ( block, Insn :: GuardBitEquals {
3095+ val : block_handler,
3096+ expected : Const :: Value ( VALUE ( VM_BLOCK_HANDLER_NONE as usize ) ) ,
3097+ reason : SideExitReason :: UnhandledBlockArg ,
3098+ state
3099+ } ) ;
3100+
3101+ // Use SendWithoutBlockDirect with the super method's CME and ISEQ.
3102+ let send_direct = self . push_insn ( block, Insn :: SendWithoutBlockDirect {
31063103 recv,
31073104 cd,
3108- current_cme ,
3109- super_cme ,
3105+ cme : super_cme ,
3106+ iseq : super_iseq ,
31103107 args,
31113108 state
31123109 } ) ;
@@ -3995,6 +3992,7 @@ impl Function {
39953992 | & Insn :: LoadEC
39963993 | & Insn :: LoadSelf
39973994 | & Insn :: GetLocal { .. }
3995+ | & Insn :: GetBlockHandler
39983996 | & Insn :: PutSpecialObject { .. }
39993997 | & Insn :: IsBlockGiven
40003998 | & Insn :: IncrCounter ( _)
@@ -4171,8 +4169,7 @@ impl Function {
41714169 | & Insn :: CCallWithFrame { recv, ref args, state, .. }
41724170 | & Insn :: SendWithoutBlockDirect { recv, ref args, state, .. }
41734171 | & Insn :: InvokeBuiltin { recv, ref args, state, .. }
4174- | & Insn :: InvokeSuper { recv, ref args, state, .. }
4175- | & Insn :: InvokeSuperDirect { recv, ref args, state, .. } => {
4172+ | & Insn :: InvokeSuper { recv, ref args, state, .. } => {
41764173 worklist. push_back ( recv) ;
41774174 worklist. extend ( args) ;
41784175 worklist. push_back ( state) ;
@@ -4224,6 +4221,7 @@ impl Function {
42244221 worklist. push_back ( val) ;
42254222 }
42264223 & Insn :: GuardBlockParamProxy { state, .. } |
4224+ & Insn :: GuardSuperMethodEntry { state, .. } |
42274225 & Insn :: GetGlobal { state, .. } |
42284226 & Insn :: GetSpecialSymbol { state, .. } |
42294227 & Insn :: GetSpecialNumber { state, .. } |
@@ -4735,6 +4733,8 @@ impl Function {
47354733 | Insn :: Jump { .. }
47364734 | Insn :: EntryPoint { .. }
47374735 | Insn :: GuardBlockParamProxy { .. }
4736+ | Insn :: GuardSuperMethodEntry { .. }
4737+ | Insn :: GetBlockHandler
47384738 | Insn :: PatchPoint { .. }
47394739 | Insn :: SideExit { .. }
47404740 | Insn :: IncrCounter { .. }
@@ -4788,7 +4788,6 @@ impl Function {
47884788 | Insn :: Send { recv, ref args, .. }
47894789 | Insn :: SendForward { recv, ref args, .. }
47904790 | Insn :: InvokeSuper { recv, ref args, .. }
4791- | Insn :: InvokeSuperDirect { recv, ref args, .. }
47924791 | Insn :: CCallWithFrame { recv, ref args, .. }
47934792 | Insn :: CCallVariadic { recv, ref args, .. }
47944793 | Insn :: InvokeBuiltin { recv, ref args, .. }
0 commit comments