@@ -7793,45 +7793,81 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
77937793 break ;
77947794 }
77957795
7796- let branch_insn_idx = exit_state. insn_idx as u32 ;
7797- let args = state. stack_pop_n ( argc as usize ) ?;
7798- let recv = state. stack_pop ( ) ?;
7799-
7800- if let Some ( summary) = fun. polymorphic_summary ( & profiles, recv, exit_state. insn_idx ) {
7801- let join_block = insn_idx_to_block. get ( & insn_idx) . copied ( ) . unwrap_or_else ( || fun. new_block ( insn_idx) ) ;
7802- let join_param = fun. push_insn ( join_block, Insn :: Param ) ;
7803- // Dedup by expected type so immediate/heap variants
7804- // under the same Ruby class can still get separate branches.
7805- let mut seen_types = Vec :: with_capacity ( summary. buckets ( ) . len ( ) ) ;
7806- for & profiled_type in summary. buckets ( ) {
7807- if profiled_type. is_empty ( ) { break ; }
7808- let expected = Type :: from_profiled_type ( profiled_type) ;
7809- if seen_types. iter ( ) . any ( |ty : & Type | ty. bit_equal ( expected) ) {
7810- continue ;
7796+ {
7797+ fn new_branch_block (
7798+ fun : & mut Function ,
7799+ cd : * const rb_call_data ,
7800+ argc : usize ,
7801+ opcode : u32 ,
7802+ new_type : Type ,
7803+ insn_idx : u32 ,
7804+ exit_state : & FrameState ,
7805+ locals_count : usize ,
7806+ stack_count : usize ,
7807+ join_block : BlockId ,
7808+ ) -> BlockId {
7809+ let block = fun. new_block ( insn_idx) ;
7810+ let self_param = fun. push_insn ( block, Insn :: Param ) ;
7811+ let mut state = exit_state. clone ( ) ;
7812+ state. locals . clear ( ) ;
7813+ state. stack . clear ( ) ;
7814+ state. locals . extend ( ( 0 ..locals_count) . map ( |_| fun. push_insn ( block, Insn :: Param ) ) ) ;
7815+ state. stack . extend ( ( 0 ..stack_count) . map ( |_| fun. push_insn ( block, Insn :: Param ) ) ) ;
7816+ let snapshot = fun. push_insn ( block, Insn :: Snapshot { state : state. clone ( ) } ) ;
7817+ let args = state. stack_pop_n ( argc) . unwrap ( ) ;
7818+ let recv = state. stack_pop ( ) . unwrap ( ) ;
7819+ let refined_recv = fun. push_insn ( block, Insn :: RefineType { val : recv, new_type } ) ;
7820+ state. replace ( recv, refined_recv) ;
7821+ let send = fun. push_insn ( block, Insn :: Send { recv : refined_recv, cd, block : None , args, state : snapshot, reason : Uncategorized ( opcode) } ) ;
7822+ state. stack_push ( send) ;
7823+ fun. push_insn ( block, Insn :: Jump ( BranchEdge { target : join_block, args : state. as_args ( self_param) } ) ) ;
7824+ block
7825+ }
7826+ let branch_insn_idx = exit_state. insn_idx as u32 ;
7827+ let locals_count = state. locals . len ( ) ;
7828+ let stack_count = state. stack . len ( ) ;
7829+ let recv = state. stack_topn ( argc as usize ) ?; // args are on top
7830+ let entry_args = state. as_args ( self_param) ;
7831+ if let Some ( summary) = fun. polymorphic_summary ( & profiles, recv, exit_state. insn_idx ) {
7832+ let join_block = insn_idx_to_block. get ( & insn_idx) . copied ( ) . unwrap_or_else ( || fun. new_block ( insn_idx) ) ;
7833+ // Dedup by expected type so immediate/heap variants
7834+ // under the same Ruby class can still get separate branches.
7835+ let mut seen_types = Vec :: with_capacity ( summary. buckets ( ) . len ( ) ) ;
7836+ for & profiled_type in summary. buckets ( ) {
7837+ if profiled_type. is_empty ( ) { break ; }
7838+ let expected = Type :: from_profiled_type ( profiled_type) ;
7839+ if seen_types. iter ( ) . any ( |ty : & Type | ty. bit_equal ( expected) ) {
7840+ continue ;
7841+ }
7842+ seen_types. push ( expected) ;
7843+ let has_type = fun. push_insn ( block, Insn :: HasType { val : recv, expected } ) ;
7844+ let iftrue_block =
7845+ new_branch_block ( & mut fun, cd, argc as usize , opcode, expected, branch_insn_idx, & exit_state, locals_count, stack_count, join_block) ;
7846+ let target = BranchEdge { target : iftrue_block, args : entry_args. clone ( ) } ;
7847+ fun. push_insn ( block, Insn :: IfTrue { val : has_type, target } ) ;
78117848 }
7812- seen_types. push ( expected) ;
7813- let has_type = fun. push_insn ( block, Insn :: HasType { val : recv, expected } ) ;
7814- let iftrue_block = fun. new_block ( branch_insn_idx) ;
7815- let target = BranchEdge { target : iftrue_block, args : vec ! [ ] } ;
7816- fun. push_insn ( block, Insn :: IfTrue { val : has_type, target } ) ;
7817-
7818- let refined_recv = fun. push_insn ( iftrue_block, Insn :: RefineType { val : recv, new_type : expected } ) ;
7819- let send = fun. push_insn ( iftrue_block, Insn :: Send { recv : refined_recv, cd, block : None , args : args. clone ( ) , state : exit_id, reason : Uncategorized ( opcode) } ) ;
7820- fun. push_insn ( iftrue_block, Insn :: Jump ( BranchEdge { target : join_block, args : vec ! [ send] } ) ) ;
7849+ // Continue compilation from the join block at the next instruction.
7850+ // Make a copy of the current state without the args (pop the receiver
7851+ // and push the result) because we just use the locals/stack sizes to
7852+ // make the right number of Params
7853+ let mut join_state = state. clone ( ) ;
7854+ join_state. stack_pop_n ( argc as usize ) ?;
7855+ queue. push_back ( ( join_state, join_block, insn_idx, local_inval) ) ;
7856+ // In the fallthrough case, do a generic interpreter send and then join.
7857+ let args = state. stack_pop_n ( argc as usize ) ?;
7858+ let recv = state. stack_pop ( ) ?;
7859+ let reason = SendWithoutBlockPolymorphicFallback ;
7860+ let send = fun. push_insn ( block, Insn :: Send { recv, cd, block : None , args, state : exit_id, reason } ) ;
7861+ state. stack_push ( send) ;
7862+ fun. push_insn ( block, Insn :: Jump ( BranchEdge { target : join_block, args : state. as_args ( self_param) } ) ) ;
7863+ break ; // End the block
78217864 }
7822- // In the fallthrough case, do a generic interpreter send and then join.
7823- let reason = SendWithoutBlockPolymorphicFallback ;
7824- let send = fun. push_insn ( block, Insn :: Send { recv, cd, block : None , args, state : exit_id, reason } ) ;
7825- fun. push_insn ( block, Insn :: Jump ( BranchEdge { target : join_block, args : vec ! [ send] } ) ) ;
7826-
7827- // Continue compilation in the join_block
7828- block = join_block;
7829- state. stack_push ( join_param) ;
7830- } else {
7831- // Maybe monomorphic; handled in type_specialize
7832- let send = fun. push_insn ( block, Insn :: Send { recv, cd, block : None , args, state : exit_id, reason : Uncategorized ( opcode) } ) ;
7833- state. stack_push ( send) ;
78347865 }
7866+
7867+ let args = state. stack_pop_n ( argc as usize ) ?;
7868+ let recv = state. stack_pop ( ) ?;
7869+ let send = fun. push_insn ( block, Insn :: Send { recv, cd, block : None , args, state : exit_id, reason : Uncategorized ( opcode) } ) ;
7870+ state. stack_push ( send) ;
78357871 }
78367872 YARVINSN_send => {
78377873 let cd: * const rb_call_data = get_arg ( pc, 0 ) . as_ptr ( ) ;
0 commit comments