@@ -493,6 +493,7 @@ pub enum SideExitReason {
493493 GuardNotFrozen ,
494494 GuardLess ,
495495 GuardGreaterEq ,
496+ GuardSuperMethodEntry ,
496497 PatchPoint ( Invariant ) ,
497498 CalleeSideExit ,
498499 ObjToStringFallback ,
@@ -884,6 +885,17 @@ pub enum Insn {
884885 state : InsnId ,
885886 reason : SendFallbackReason ,
886887 } ,
888+ /// Optimized super call to an ISEQ method
889+ InvokeSuperDirect {
890+ recv : InsnId ,
891+ cd : * const rb_call_data ,
892+ /// The CME of the method containing the super call (for runtime guard)
893+ current_cme : * const rb_callable_method_entry_t ,
894+ /// The resolved super method's CME (for PatchPoint and to get target ISEQ)
895+ super_cme : * const rb_callable_method_entry_t ,
896+ args : Vec < InsnId > ,
897+ state : InsnId ,
898+ } ,
887899 InvokeBlock {
888900 cd : * const rb_call_data ,
889901 args : Vec < InsnId > ,
@@ -1279,6 +1291,13 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
12791291 write ! ( f, " # SendFallbackReason: {reason}" ) ?;
12801292 Ok ( ( ) )
12811293 }
1294+ Insn :: InvokeSuperDirect { recv, args, .. } => {
1295+ write ! ( f, "InvokeSuperDirect {recv}" ) ?;
1296+ for arg in args {
1297+ write ! ( f, ", {arg}" ) ?;
1298+ }
1299+ Ok ( ( ) )
1300+ }
12821301 Insn :: InvokeBlock { args, reason, .. } => {
12831302 write ! ( f, "InvokeBlock" ) ?;
12841303 for arg in args {
@@ -2018,6 +2037,14 @@ impl Function {
20182037 state,
20192038 reason,
20202039 } ,
2040+ & InvokeSuperDirect { recv, cd, current_cme, super_cme, ref args, state } => InvokeSuperDirect {
2041+ recv : find ! ( recv) ,
2042+ cd,
2043+ current_cme,
2044+ super_cme,
2045+ args : find_vec ! ( args) ,
2046+ state,
2047+ } ,
20212048 & InvokeBlock { cd, ref args, state, reason } => InvokeBlock {
20222049 cd,
20232050 args : find_vec ! ( args) ,
@@ -2203,6 +2230,7 @@ impl Function {
22032230 Insn :: Send { .. } => types:: BasicObject ,
22042231 Insn :: SendForward { .. } => types:: BasicObject ,
22052232 Insn :: InvokeSuper { .. } => types:: BasicObject ,
2233+ Insn :: InvokeSuperDirect { .. } => types:: BasicObject ,
22062234 Insn :: InvokeBlock { .. } => types:: BasicObject ,
22072235 Insn :: InvokeBuiltin { return_type, .. } => return_type. unwrap_or ( types:: BasicObject ) ,
22082236 Insn :: Defined { pushval, .. } => Type :: from_value ( * pushval) . union ( types:: NilClass ) ,
@@ -2968,6 +2996,74 @@ impl Function {
29682996 self . push_insn_id ( block, insn_id) ;
29692997 } ;
29702998 }
2999+ Insn :: InvokeSuper { recv, cd, blockiseq, args, state, .. } => {
3000+ // Don't handle calls with literal blocks (e.g., super { ... })
3001+ if !blockiseq. is_null ( ) {
3002+ self . push_insn_id ( block, insn_id) ; continue ;
3003+ }
3004+
3005+ // Don't handle calls with complex arguments (kwarg, splat, kw_splat, blockarg, forwarding)
3006+ let ci = unsafe { get_call_data_ci ( cd) } ;
3007+ let flags = unsafe { rb_vm_ci_flag ( ci) } ;
3008+ if unspecializable_call_type ( flags) {
3009+ self . push_insn_id ( block, insn_id) ; continue ;
3010+ }
3011+
3012+ let frame_state = self . frame_state ( state) ;
3013+
3014+ // Get the profiled CME from the current method
3015+ let Some ( profiles) = self . profiles . as_ref ( ) else {
3016+ self . push_insn_id ( block, insn_id) ; continue ;
3017+ } ;
3018+ let Some ( current_cme) = profiles. payload . profile . get_super_method_entry ( frame_state. insn_idx ) else {
3019+ // No profile or polymorphic
3020+ self . push_insn_id ( block, insn_id) ; continue ;
3021+ } ;
3022+
3023+ // Get defined_class and method ID from the profiled CME
3024+ let current_defined_class = unsafe { ( * current_cme) . defined_class } ;
3025+ let mid = unsafe { get_def_original_id ( ( * current_cme) . def ) } ;
3026+
3027+ // Compute superclass: RCLASS_SUPER(RCLASS_ORIGIN(defined_class))
3028+ let superclass = unsafe { rb_class_get_superclass ( RCLASS_ORIGIN ( current_defined_class) ) } ;
3029+ if superclass. nil_p ( ) {
3030+ self . push_insn_id ( block, insn_id) ; continue ;
3031+ }
3032+
3033+ // Look up the super method
3034+ let super_cme = unsafe { rb_callable_method_entry ( superclass, mid) } ;
3035+ if super_cme. is_null ( ) {
3036+ self . push_insn_id ( block, insn_id) ; continue ;
3037+ }
3038+
3039+ // Check if it's an ISEQ method
3040+ let def_type = unsafe { get_cme_def_type ( super_cme) } ;
3041+ if def_type != VM_METHOD_TYPE_ISEQ {
3042+ // TODO: Handle CFUNCs
3043+ self . push_insn_id ( block, insn_id) ; continue ;
3044+ }
3045+
3046+ // Add PatchPoints for method redefinition
3047+ // TODO: Add guard that ep[-2] matches current_cme
3048+ self . push_insn ( block, Insn :: PatchPoint {
3049+ invariant : Invariant :: MethodRedefined {
3050+ klass : unsafe { ( * super_cme) . defined_class } ,
3051+ method : mid,
3052+ cme : super_cme
3053+ } ,
3054+ state
3055+ } ) ;
3056+
3057+ let send_direct = self . push_insn ( block, Insn :: InvokeSuperDirect {
3058+ recv,
3059+ cd,
3060+ current_cme,
3061+ super_cme,
3062+ args,
3063+ state
3064+ } ) ;
3065+ self . make_equal_to ( insn_id, send_direct) ;
3066+ }
29713067 _ => { self . push_insn_id ( block, insn_id) ; }
29723068 }
29733069 }
@@ -3974,7 +4070,8 @@ impl Function {
39744070 | & Insn :: CCallWithFrame { recv, ref args, state, .. }
39754071 | & Insn :: SendWithoutBlockDirect { recv, ref args, state, .. }
39764072 | & Insn :: InvokeBuiltin { recv, ref args, state, .. }
3977- | & Insn :: InvokeSuper { recv, ref args, state, .. } => {
4073+ | & Insn :: InvokeSuper { recv, ref args, state, .. }
4074+ | & Insn :: InvokeSuperDirect { recv, ref args, state, .. } => {
39784075 worklist. push_back ( recv) ;
39794076 worklist. extend ( args) ;
39804077 worklist. push_back ( state) ;
@@ -4590,6 +4687,7 @@ impl Function {
45904687 | Insn :: Send { recv, ref args, .. }
45914688 | Insn :: SendForward { recv, ref args, .. }
45924689 | Insn :: InvokeSuper { recv, ref args, .. }
4690+ | Insn :: InvokeSuperDirect { recv, ref args, .. }
45934691 | Insn :: CCallWithFrame { recv, ref args, .. }
45944692 | Insn :: CCallVariadic { recv, ref args, .. }
45954693 | Insn :: InvokeBuiltin { recv, ref args, .. }
0 commit comments