@@ -892,17 +892,6 @@ pub enum Insn {
892892 state : InsnId ,
893893 reason : SendFallbackReason ,
894894 } ,
895- /// Optimized super call to an ISEQ method
896- InvokeSuperDirect {
897- recv : InsnId ,
898- cd : * const rb_call_data ,
899- /// The CME of the method containing the super call (for runtime guard)
900- current_cme : * const rb_callable_method_entry_t ,
901- /// The resolved super method's CME (for PatchPoint and to get target ISEQ)
902- super_cme : * const rb_callable_method_entry_t ,
903- args : Vec < InsnId > ,
904- state : InsnId ,
905- } ,
906895 InvokeBlock {
907896 cd : * const rb_call_data ,
908897 args : Vec < InsnId > ,
@@ -976,6 +965,11 @@ pub enum Insn {
976965 GuardGreaterEq { left : InsnId , right : InsnId , state : InsnId } ,
977966 /// Side-exit if left is not less than right (both operands are C long).
978967 GuardLess { left : InsnId , right : InsnId , state : InsnId } ,
968+ /// Side-exit if the method entry at ep[VM_ENV_DATA_INDEX_ME_CREF] doesn't match the expected CME.
969+ /// Used to ensure super calls are made from the expected method context.
970+ GuardSuperMethodEntry { cme : * const rb_callable_method_entry_t , state : InsnId } ,
971+ /// Get the block handler from ep[VM_ENV_DATA_INDEX_SPECVAL] at the local EP (LEP).
972+ GetBlockHandler ,
979973
980974 /// Generate no code (or padding if necessary) and insert a patch point
981975 /// that can be rewritten to a side exit when the Invariant is broken.
@@ -1004,7 +998,8 @@ impl Insn {
1004998 | Insn :: PatchPoint { .. } | Insn :: SetIvar { .. } | Insn :: SetClassVar { .. } | Insn :: ArrayExtend { .. }
1005999 | Insn :: ArrayPush { .. } | Insn :: SideExit { .. } | Insn :: SetGlobal { .. }
10061000 | Insn :: SetLocal { .. } | Insn :: Throw { .. } | Insn :: IncrCounter ( _) | Insn :: IncrCounterPtr { .. }
1007- | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. } | Insn :: StoreField { .. } | Insn :: WriteBarrier { .. }
1001+ | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. } | Insn :: GuardSuperMethodEntry { .. }
1002+ | Insn :: StoreField { .. } | Insn :: WriteBarrier { .. }
10081003 | Insn :: HashAset { .. } => false ,
10091004 _ => true ,
10101005 }
@@ -1300,13 +1295,6 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
13001295 write ! ( f, " # SendFallbackReason: {reason}" ) ?;
13011296 Ok ( ( ) )
13021297 }
1303- Insn :: InvokeSuperDirect { recv, args, .. } => {
1304- write ! ( f, "InvokeSuperDirect {recv}" ) ?;
1305- for arg in args {
1306- write ! ( f, ", {arg}" ) ?;
1307- }
1308- Ok ( ( ) )
1309- }
13101298 Insn :: InvokeBlock { args, reason, .. } => {
13111299 write ! ( f, "InvokeBlock" ) ?;
13121300 for arg in args {
@@ -1353,6 +1341,8 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
13531341 Insn :: GuardNotFrozen { recv, .. } => write ! ( f, "GuardNotFrozen {recv}" ) ,
13541342 Insn :: GuardLess { left, right, .. } => write ! ( f, "GuardLess {left}, {right}" ) ,
13551343 Insn :: GuardGreaterEq { left, right, .. } => write ! ( f, "GuardGreaterEq {left}, {right}" ) ,
1344+ Insn :: GuardSuperMethodEntry { cme, .. } => write ! ( f, "GuardSuperMethodEntry {:p}" , self . ptr_map. map_ptr( cme) ) ,
1345+ Insn :: GetBlockHandler => write ! ( f, "GetBlockHandler" ) ,
13561346 Insn :: PatchPoint { invariant, .. } => { write ! ( f, "PatchPoint {}" , invariant. print( self . ptr_map) ) } ,
13571347 Insn :: GetConstantPath { ic, .. } => { write ! ( f, "GetConstantPath {:p}" , self . ptr_map. map_ptr( ic) ) } ,
13581348 Insn :: IsBlockGiven => { write ! ( f, "IsBlockGiven" ) } ,
@@ -1989,6 +1979,8 @@ impl Function {
19891979 & GuardNotFrozen { recv, state } => GuardNotFrozen { recv : find ! ( recv) , state } ,
19901980 & GuardGreaterEq { left, right, state } => GuardGreaterEq { left : find ! ( left) , right : find ! ( right) , state } ,
19911981 & GuardLess { left, right, state } => GuardLess { left : find ! ( left) , right : find ! ( right) , state } ,
1982+ & GuardSuperMethodEntry { cme, state } => GuardSuperMethodEntry { cme, state } ,
1983+ & GetBlockHandler => GetBlockHandler ,
19921984 & FixnumAdd { left, right, state } => FixnumAdd { left : find ! ( left) , right : find ! ( right) , state } ,
19931985 & FixnumSub { left, right, state } => FixnumSub { left : find ! ( left) , right : find ! ( right) , state } ,
19941986 & FixnumMult { left, right, state } => FixnumMult { left : find ! ( left) , right : find ! ( right) , state } ,
@@ -2054,14 +2046,6 @@ impl Function {
20542046 state,
20552047 reason,
20562048 } ,
2057- & InvokeSuperDirect { recv, cd, current_cme, super_cme, ref args, state } => InvokeSuperDirect {
2058- recv : find ! ( recv) ,
2059- cd,
2060- current_cme,
2061- super_cme,
2062- args : find_vec ! ( args) ,
2063- state,
2064- } ,
20652049 & InvokeBlock { cd, ref args, state, reason } => InvokeBlock {
20662050 cd,
20672051 args : find_vec ! ( args) ,
@@ -2169,8 +2153,8 @@ impl Function {
21692153 | Insn :: IfTrue { .. } | Insn :: IfFalse { .. } | Insn :: Return { .. } | Insn :: Throw { .. }
21702154 | Insn :: PatchPoint { .. } | Insn :: SetIvar { .. } | Insn :: SetClassVar { .. } | Insn :: ArrayExtend { .. }
21712155 | Insn :: ArrayPush { .. } | Insn :: SideExit { .. } | Insn :: SetLocal { .. } | Insn :: IncrCounter ( _)
2172- | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. } | Insn :: IncrCounterPtr { .. }
2173- | Insn :: StoreField { .. } | Insn :: WriteBarrier { .. } | Insn :: HashAset { .. } =>
2156+ | Insn :: CheckInterrupts { .. } | Insn :: GuardBlockParamProxy { .. } | Insn :: GuardSuperMethodEntry { .. }
2157+ | Insn :: IncrCounterPtr { .. } | Insn :: StoreField { .. } | Insn :: WriteBarrier { .. } | Insn :: HashAset { .. } =>
21742158 panic ! ( "Cannot infer type of instruction with no output: {}. See Insn::has_output()." , self . insns[ insn. 0 ] ) ,
21752159 Insn :: Const { val : Const :: Value ( val) } => Type :: from_value ( * val) ,
21762160 Insn :: Const { val : Const :: CBool ( val) } => Type :: from_cbool ( * val) ,
@@ -2249,7 +2233,6 @@ impl Function {
22492233 Insn :: Send { .. } => types:: BasicObject ,
22502234 Insn :: SendForward { .. } => types:: BasicObject ,
22512235 Insn :: InvokeSuper { .. } => types:: BasicObject ,
2252- Insn :: InvokeSuperDirect { .. } => types:: BasicObject ,
22532236 Insn :: InvokeBlock { .. } => types:: BasicObject ,
22542237 Insn :: InvokeBuiltin { return_type, .. } => return_type. unwrap_or ( types:: BasicObject ) ,
22552238 Insn :: Defined { pushval, .. } => Type :: from_value ( * pushval) . union ( types:: NilClass ) ,
@@ -2277,6 +2260,7 @@ impl Function {
22772260 Insn :: AnyToString { .. } => types:: String ,
22782261 Insn :: GetLocal { rest_param : true , .. } => types:: ArrayExact ,
22792262 Insn :: GetLocal { .. } => types:: BasicObject ,
2263+ Insn :: GetBlockHandler => types:: RubyValue ,
22802264 // The type of Snapshot doesn't really matter; it's never materialized. It's used only
22812265 // as a reference for FrameState, which we use to generate side-exit code.
22822266 Insn :: Snapshot { .. } => types:: Any ,
@@ -3031,7 +3015,7 @@ impl Function {
30313015 self . push_insn_id ( block, insn_id) ; continue ;
30323016 }
30333017
3034- // Don't handle calls with complex arguments (kwarg, splat, kw_splat, blockarg, forwarding)
3018+ // Don't handle calls with complex arguments.
30353019 let ci = unsafe { get_call_data_ci ( cd) } ;
30363020 let flags = unsafe { rb_vm_ci_flag ( ci) } ;
30373021 if unspecializable_call_type ( flags) {
@@ -3040,7 +3024,7 @@ impl Function {
30403024
30413025 let frame_state = self . frame_state ( state) ;
30423026
3043- // Get the profiled CME from the current method
3027+ // Get the profiled CME from the current method.
30443028 let Some ( profiles) = self . profiles . as_ref ( ) else {
30453029 self . push_insn_id ( block, insn_id) ; continue ;
30463030 } ;
@@ -3049,7 +3033,7 @@ impl Function {
30493033 self . push_insn_id ( block, insn_id) ; continue ;
30503034 } ;
30513035
3052- // Get defined_class and method ID from the profiled CME
3036+ // Get defined_class and method ID from the profiled CME.
30533037 let current_defined_class = unsafe { ( * current_cme) . defined_class } ;
30543038 let mid = unsafe { get_def_original_id ( ( * current_cme) . def ) } ;
30553039
@@ -3059,16 +3043,15 @@ impl Function {
30593043 self . push_insn_id ( block, insn_id) ; continue ;
30603044 }
30613045
3062- // Look up the super method
3046+ // Look up the super method.
30633047 let super_cme = unsafe { rb_callable_method_entry ( superclass, mid) } ;
30643048 if super_cme. is_null ( ) {
30653049 self . push_insn_id ( block, insn_id) ; continue ;
30663050 }
30673051
3068- // Check if it's an ISEQ method
3052+ // Check if it's an ISEQ method; bail if it isn't.
30693053 let def_type = unsafe { get_cme_def_type ( super_cme) } ;
30703054 if def_type != VM_METHOD_TYPE_ISEQ {
3071- // TODO: Handle CFUNCs
30723055 self . push_insn_id ( block, insn_id) ; continue ;
30733056 }
30743057
@@ -3079,8 +3062,7 @@ impl Function {
30793062 self . push_insn_id ( block, insn_id) ; continue ;
30803063 }
30813064
3082- // Add PatchPoints for method redefinition
3083- // TODO: Add guard that ep[-2] matches current_cme
3065+ // Add PatchPoint for method redefinition.
30843066 self . push_insn ( block, Insn :: PatchPoint {
30853067 invariant : Invariant :: MethodRedefined {
30863068 klass : unsafe { ( * super_cme) . defined_class } ,
@@ -3090,11 +3072,23 @@ impl Function {
30903072 state
30913073 } ) ;
30923074
3093- let send_direct = self . push_insn ( block, Insn :: InvokeSuperDirect {
3075+ // Guard that we're calling `super` from the expected method context.
3076+ self . push_insn ( block, Insn :: GuardSuperMethodEntry { cme : current_cme, state } ) ;
3077+
3078+ // Guard that no block is being passed (implicit or explicit).
3079+ let block_handler = self . push_insn ( block, Insn :: GetBlockHandler ) ;
3080+ self . push_insn ( block, Insn :: GuardBitEquals {
3081+ val : block_handler,
3082+ expected : Const :: Value ( VALUE ( VM_BLOCK_HANDLER_NONE as usize ) ) ,
3083+ state
3084+ } ) ;
3085+
3086+ // Use SendWithoutBlockDirect with the super method's CME and ISEQ.
3087+ let send_direct = self . push_insn ( block, Insn :: SendWithoutBlockDirect {
30943088 recv,
30953089 cd,
3096- current_cme ,
3097- super_cme ,
3090+ cme : super_cme ,
3091+ iseq : super_iseq ,
30983092 args,
30993093 state
31003094 } ) ;
@@ -3962,6 +3956,7 @@ impl Function {
39623956 | & Insn :: LoadEC
39633957 | & Insn :: LoadSelf
39643958 | & Insn :: GetLocal { .. }
3959+ | & Insn :: GetBlockHandler
39653960 | & Insn :: PutSpecialObject { .. }
39663961 | & Insn :: IsBlockGiven
39673962 | & Insn :: IncrCounter ( _)
@@ -4132,8 +4127,7 @@ impl Function {
41324127 | & Insn :: CCallWithFrame { recv, ref args, state, .. }
41334128 | & Insn :: SendWithoutBlockDirect { recv, ref args, state, .. }
41344129 | & Insn :: InvokeBuiltin { recv, ref args, state, .. }
4135- | & Insn :: InvokeSuper { recv, ref args, state, .. }
4136- | & Insn :: InvokeSuperDirect { recv, ref args, state, .. } => {
4130+ | & Insn :: InvokeSuper { recv, ref args, state, .. } => {
41374131 worklist. push_back ( recv) ;
41384132 worklist. extend ( args) ;
41394133 worklist. push_back ( state) ;
@@ -4185,6 +4179,7 @@ impl Function {
41854179 worklist. push_back ( val) ;
41864180 }
41874181 & Insn :: GuardBlockParamProxy { state, .. } |
4182+ & Insn :: GuardSuperMethodEntry { state, .. } |
41884183 & Insn :: GetGlobal { state, .. } |
41894184 & Insn :: GetSpecialSymbol { state, .. } |
41904185 & Insn :: GetSpecialNumber { state, .. } |
@@ -4696,6 +4691,8 @@ impl Function {
46964691 | Insn :: Jump { .. }
46974692 | Insn :: EntryPoint { .. }
46984693 | Insn :: GuardBlockParamProxy { .. }
4694+ | Insn :: GuardSuperMethodEntry { .. }
4695+ | Insn :: GetBlockHandler
46994696 | Insn :: PatchPoint { .. }
47004697 | Insn :: SideExit { .. }
47014698 | Insn :: IncrCounter { .. }
@@ -4749,7 +4746,6 @@ impl Function {
47494746 | Insn :: Send { recv, ref args, .. }
47504747 | Insn :: SendForward { recv, ref args, .. }
47514748 | Insn :: InvokeSuper { recv, ref args, .. }
4752- | Insn :: InvokeSuperDirect { recv, ref args, .. }
47534749 | Insn :: CCallWithFrame { recv, ref args, .. }
47544750 | Insn :: CCallVariadic { recv, ref args, .. }
47554751 | Insn :: InvokeBuiltin { recv, ref args, .. }
0 commit comments