@@ -895,17 +895,6 @@ pub enum Insn {
895895 state : InsnId ,
896896 reason : SendFallbackReason ,
897897 } ,
898- /// Optimized super call to an ISEQ method
899- InvokeSuperDirect {
900- recv : InsnId ,
901- cd : * const rb_call_data ,
902- /// The CME of the method containing the super call (for runtime guard)
903- current_cme : * const rb_callable_method_entry_t ,
904- /// The resolved super method's CME (for PatchPoint and to get target ISEQ)
905- super_cme : * const rb_callable_method_entry_t ,
906- args : Vec < InsnId > ,
907- state : InsnId ,
908- } ,
909898 InvokeBlock {
910899 cd : * const rb_call_data ,
911900 args : Vec < InsnId > ,
@@ -982,6 +971,11 @@ pub enum Insn {
982971 GuardGreaterEq { left : InsnId , right : InsnId , state : InsnId } ,
983972 /// Side-exit if left is not less than right (both operands are C long).
984973 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 ,
985979
986980 /// Generate no code (or padding if necessary) and insert a patch point
987981 /// that can be rewritten to a side exit when the Invariant is broken.
@@ -1010,7 +1004,7 @@ impl Insn {
10101004 | Insn :: PatchPoint { .. } | Insn :: SetIvar { .. } | Insn :: SetClassVar { .. } | Insn :: ArrayExtend { .. }
10111005 | Insn :: ArrayPush { .. } | Insn :: SideExit { .. } | Insn :: SetGlobal { .. }
10121006 | Insn :: SetLocal { .. } | Insn :: Throw { .. } | Insn :: IncrCounter ( _) | Insn :: IncrCounterPtr { .. }
1013- | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. }
1007+ | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. } | Insn :: GuardSuperMethodEntry { .. }
10141008 | Insn :: StoreField { .. } | Insn :: WriteBarrier { .. } | Insn :: HashAset { .. }
10151009 | Insn :: ArrayAset { .. } => false ,
10161010 _ => true ,
@@ -1310,13 +1304,6 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
13101304 write ! ( f, " # SendFallbackReason: {reason}" ) ?;
13111305 Ok ( ( ) )
13121306 }
1313- Insn :: InvokeSuperDirect { recv, args, .. } => {
1314- write ! ( f, "InvokeSuperDirect {recv}" ) ?;
1315- for arg in args {
1316- write ! ( f, ", {arg}" ) ?;
1317- }
1318- Ok ( ( ) )
1319- }
13201307 Insn :: InvokeBlock { args, reason, .. } => {
13211308 write ! ( f, "InvokeBlock" ) ?;
13221309 for arg in args {
@@ -1364,6 +1351,8 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
13641351 Insn :: GuardNotShared { recv, .. } => write ! ( f, "GuardNotShared {recv}" ) ,
13651352 Insn :: GuardLess { left, right, .. } => write ! ( f, "GuardLess {left}, {right}" ) ,
13661353 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" ) ,
13671356 Insn :: PatchPoint { invariant, .. } => { write ! ( f, "PatchPoint {}" , invariant. print( self . ptr_map) ) } ,
13681357 Insn :: GetConstantPath { ic, .. } => { write ! ( f, "GetConstantPath {:p}" , self . ptr_map. map_ptr( ic) ) } ,
13691358 Insn :: IsBlockGiven => { write ! ( f, "IsBlockGiven" ) } ,
@@ -2001,6 +1990,8 @@ impl Function {
20011990 & GuardNotShared { recv, state } => GuardNotShared { recv : find ! ( recv) , state } ,
20021991 & GuardGreaterEq { left, right, state } => GuardGreaterEq { left : find ! ( left) , right : find ! ( right) , state } ,
20031992 & GuardLess { left, right, state } => GuardLess { left : find ! ( left) , right : find ! ( right) , state } ,
1993+ & GuardSuperMethodEntry { cme, state } => GuardSuperMethodEntry { cme, state } ,
1994+ & GetBlockHandler => GetBlockHandler ,
20041995 & FixnumAdd { left, right, state } => FixnumAdd { left : find ! ( left) , right : find ! ( right) , state } ,
20051996 & FixnumSub { left, right, state } => FixnumSub { left : find ! ( left) , right : find ! ( right) , state } ,
20061997 & FixnumMult { left, right, state } => FixnumMult { left : find ! ( left) , right : find ! ( right) , state } ,
@@ -2066,14 +2057,6 @@ impl Function {
20662057 state,
20672058 reason,
20682059 } ,
2069- & InvokeSuperDirect { recv, cd, current_cme, super_cme, ref args, state } => InvokeSuperDirect {
2070- recv : find ! ( recv) ,
2071- cd,
2072- current_cme,
2073- super_cme,
2074- args : find_vec ! ( args) ,
2075- state,
2076- } ,
20772060 & InvokeBlock { cd, ref args, state, reason } => InvokeBlock {
20782061 cd,
20792062 args : find_vec ! ( args) ,
@@ -2181,8 +2164,9 @@ impl Function {
21812164 Insn :: SetGlobal { .. } | Insn :: Jump ( _) | Insn :: EntryPoint { .. }
21822165 | Insn :: IfTrue { .. } | Insn :: IfFalse { .. } | Insn :: Return { .. } | Insn :: Throw { .. }
21832166 | Insn :: PatchPoint { .. } | Insn :: SetIvar { .. } | Insn :: SetClassVar { .. } | Insn :: ArrayExtend { .. }
2184- | Insn :: ArrayPush { .. } | Insn :: SideExit { .. } | Insn :: SetLocal { .. } | Insn :: IncrCounter ( _)
2185- | 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 { .. }
21862170 | Insn :: StoreField { .. } | Insn :: WriteBarrier { .. } | Insn :: HashAset { .. } | Insn :: ArrayAset { .. } =>
21872171 panic ! ( "Cannot infer type of instruction with no output: {}. See Insn::has_output()." , self . insns[ insn. 0 ] ) ,
21882172 Insn :: Const { val : Const :: Value ( val) } => Type :: from_value ( * val) ,
@@ -2262,7 +2246,6 @@ impl Function {
22622246 Insn :: Send { .. } => types:: BasicObject ,
22632247 Insn :: SendForward { .. } => types:: BasicObject ,
22642248 Insn :: InvokeSuper { .. } => types:: BasicObject ,
2265- Insn :: InvokeSuperDirect { .. } => types:: BasicObject ,
22662249 Insn :: InvokeBlock { .. } => types:: BasicObject ,
22672250 Insn :: InvokeBuiltin { return_type, .. } => return_type. unwrap_or ( types:: BasicObject ) ,
22682251 Insn :: Defined { pushval, .. } => Type :: from_value ( * pushval) . union ( types:: NilClass ) ,
@@ -2290,6 +2273,7 @@ impl Function {
22902273 Insn :: AnyToString { .. } => types:: String ,
22912274 Insn :: GetLocal { rest_param : true , .. } => types:: ArrayExact ,
22922275 Insn :: GetLocal { .. } => types:: BasicObject ,
2276+ Insn :: GetBlockHandler => types:: RubyValue ,
22932277 // The type of Snapshot doesn't really matter; it's never materialized. It's used only
22942278 // as a reference for FrameState, which we use to generate side-exit code.
22952279 Insn :: Snapshot { .. } => types:: Any ,
@@ -3044,16 +3028,17 @@ impl Function {
30443028 self . push_insn_id ( block, insn_id) ; continue ;
30453029 }
30463030
3047- // 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.
30483033 let ci = unsafe { get_call_data_ci ( cd) } ;
30493034 let flags = unsafe { rb_vm_ci_flag ( ci) } ;
3050- if unspecializable_call_type ( flags) {
3035+ if ( flags & VM_CALL_ZSUPER ) == 0 {
30513036 self . push_insn_id ( block, insn_id) ; continue ;
30523037 }
30533038
30543039 let frame_state = self . frame_state ( state) ;
30553040
3056- // Get the profiled CME from the current method
3041+ // Get the profiled CME from the current method.
30573042 let Some ( profiles) = self . profiles . as_ref ( ) else {
30583043 self . push_insn_id ( block, insn_id) ; continue ;
30593044 } ;
@@ -3062,7 +3047,7 @@ impl Function {
30623047 self . push_insn_id ( block, insn_id) ; continue ;
30633048 } ;
30643049
3065- // Get defined_class and method ID from the profiled CME
3050+ // Get defined_class and method ID from the profiled CME.
30663051 let current_defined_class = unsafe { ( * current_cme) . defined_class } ;
30673052 let mid = unsafe { get_def_original_id ( ( * current_cme) . def ) } ;
30683053
@@ -3072,16 +3057,15 @@ impl Function {
30723057 self . push_insn_id ( block, insn_id) ; continue ;
30733058 }
30743059
3075- // Look up the super method
3060+ // Look up the super method.
30763061 let super_cme = unsafe { rb_callable_method_entry ( superclass, mid) } ;
30773062 if super_cme. is_null ( ) {
30783063 self . push_insn_id ( block, insn_id) ; continue ;
30793064 }
30803065
3081- // Check if it's an ISEQ method
3066+ // Check if it's an ISEQ method; bail if it isn't.
30823067 let def_type = unsafe { get_cme_def_type ( super_cme) } ;
30833068 if def_type != VM_METHOD_TYPE_ISEQ {
3084- // TODO: Handle CFUNCs
30853069 self . push_insn_id ( block, insn_id) ; continue ;
30863070 }
30873071
@@ -3092,8 +3076,7 @@ impl Function {
30923076 self . push_insn_id ( block, insn_id) ; continue ;
30933077 }
30943078
3095- // Add PatchPoints for method redefinition
3096- // TODO: Add guard that ep[-2] matches current_cme
3079+ // Add PatchPoint for method redefinition.
30973080 self . push_insn ( block, Insn :: PatchPoint {
30983081 invariant : Invariant :: MethodRedefined {
30993082 klass : unsafe { ( * super_cme) . defined_class } ,
@@ -3103,11 +3086,23 @@ impl Function {
31033086 state
31043087 } ) ;
31053088
3106- 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+ state
3098+ } ) ;
3099+
3100+ // Use SendWithoutBlockDirect with the super method's CME and ISEQ.
3101+ let send_direct = self . push_insn ( block, Insn :: SendWithoutBlockDirect {
31073102 recv,
31083103 cd,
3109- current_cme ,
3110- super_cme ,
3104+ cme : super_cme ,
3105+ iseq : super_iseq ,
31113106 args,
31123107 state
31133108 } ) ;
@@ -3975,6 +3970,7 @@ impl Function {
39753970 | & Insn :: LoadEC
39763971 | & Insn :: LoadSelf
39773972 | & Insn :: GetLocal { .. }
3973+ | & Insn :: GetBlockHandler
39783974 | & Insn :: PutSpecialObject { .. }
39793975 | & Insn :: IsBlockGiven
39803976 | & Insn :: IncrCounter ( _)
@@ -4151,8 +4147,7 @@ impl Function {
41514147 | & Insn :: CCallWithFrame { recv, ref args, state, .. }
41524148 | & Insn :: SendWithoutBlockDirect { recv, ref args, state, .. }
41534149 | & Insn :: InvokeBuiltin { recv, ref args, state, .. }
4154- | & Insn :: InvokeSuper { recv, ref args, state, .. }
4155- | & Insn :: InvokeSuperDirect { recv, ref args, state, .. } => {
4150+ | & Insn :: InvokeSuper { recv, ref args, state, .. } => {
41564151 worklist. push_back ( recv) ;
41574152 worklist. extend ( args) ;
41584153 worklist. push_back ( state) ;
@@ -4204,6 +4199,7 @@ impl Function {
42044199 worklist. push_back ( val) ;
42054200 }
42064201 & Insn :: GuardBlockParamProxy { state, .. } |
4202+ & Insn :: GuardSuperMethodEntry { state, .. } |
42074203 & Insn :: GetGlobal { state, .. } |
42084204 & Insn :: GetSpecialSymbol { state, .. } |
42094205 & Insn :: GetSpecialNumber { state, .. } |
@@ -4715,6 +4711,8 @@ impl Function {
47154711 | Insn :: Jump { .. }
47164712 | Insn :: EntryPoint { .. }
47174713 | Insn :: GuardBlockParamProxy { .. }
4714+ | Insn :: GuardSuperMethodEntry { .. }
4715+ | Insn :: GetBlockHandler
47184716 | Insn :: PatchPoint { .. }
47194717 | Insn :: SideExit { .. }
47204718 | Insn :: IncrCounter { .. }
@@ -4768,7 +4766,6 @@ impl Function {
47684766 | Insn :: Send { recv, ref args, .. }
47694767 | Insn :: SendForward { recv, ref args, .. }
47704768 | Insn :: InvokeSuper { recv, ref args, .. }
4771- | Insn :: InvokeSuperDirect { recv, ref args, .. }
47724769 | Insn :: CCallWithFrame { recv, ref args, .. }
47734770 | Insn :: CCallVariadic { recv, ref args, .. }
47744771 | Insn :: InvokeBuiltin { recv, ref args, .. }
0 commit comments