@@ -2610,24 +2610,6 @@ impl Function {
26102610 id
26112611 }
26122612
2613- fn new_branch_block (
2614- & mut self ,
2615- insn_idx : u32 ,
2616- exit_state : & FrameState ,
2617- locals_count : usize ,
2618- stack_count : usize ,
2619- ) -> ( BlockId , InsnId , FrameState , InsnId ) {
2620- let block = self . new_block ( insn_idx) ;
2621- let self_param = self . push_insn ( block, Insn :: Param ) ;
2622- let mut state = exit_state. clone ( ) ;
2623- state. locals . clear ( ) ;
2624- state. stack . clear ( ) ;
2625- state. locals . extend ( ( 0 ..locals_count) . map ( |_| self . push_insn ( block, Insn :: Param ) ) ) ;
2626- state. stack . extend ( ( 0 ..stack_count) . map ( |_| self . push_insn ( block, Insn :: Param ) ) ) ;
2627- let snapshot = self . push_insn ( block, Insn :: Snapshot { state : state. clone ( ) } ) ;
2628- ( block, self_param, state, snapshot)
2629- }
2630-
26312613 fn remove_block ( & mut self , block_id : BlockId ) {
26322614 if BlockId ( self . blocks . len ( ) - 1 ) != block_id {
26332615 panic ! ( "Can only remove the last block" ) ;
@@ -7587,44 +7569,39 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
75877569 None
75887570 } ;
75897571
7590- let locals_count = state. locals . len ( ) ;
7591- let stack_count = state. stack . len ( ) ;
7592- let entry_args = state. as_args ( self_param) ;
7593-
75947572 // `getblockparamproxy` has two semantic paths:
75957573 // - modified: return the already-materialized block local from EP
75967574 // - unmodified: inspect the block handler and produce proxy/nil
7597- let ( modified_block, modified_self_param, mut modified_state, ..) =
7598- fun. new_branch_block ( branch_insn_idx, & exit_state, locals_count, stack_count) ;
7599- let ( unmodified_block, unmodified_self_param, mut unmodified_state, unmodified_exit_id) =
7600- fun. new_branch_block ( branch_insn_idx, & exit_state, locals_count, stack_count) ;
7575+ let modified_block = fun. new_block ( branch_insn_idx) ;
7576+ let unmodified_block = fun. new_block ( branch_insn_idx) ;
76017577 let join_block = insn_idx_to_block. get ( & insn_idx) . copied ( ) . unwrap_or_else ( || fun. new_block ( insn_idx) ) ;
7578+ let join_result = fun. push_insn ( join_block, Insn :: Param ) ;
7579+ let join_local = if level == 0 { Some ( fun. push_insn ( join_block, Insn :: Param ) ) } else { None } ;
76027580
76037581 let ep = fun. push_insn ( block, Insn :: GetEP { level } ) ;
76047582 let is_modified = fun. push_insn ( block, Insn :: IsBlockParamModified { ep } ) ;
76057583
7606- fun. push_insn ( block, Insn :: IfTrue { val : is_modified, target : BranchEdge { target : modified_block, args : entry_args . clone ( ) } } ) ;
7607- fun. push_insn ( block, Insn :: Jump ( BranchEdge { target : unmodified_block, args : entry_args } ) ) ;
7584+ fun. push_insn ( block, Insn :: IfTrue { val : is_modified, target : BranchEdge { target : modified_block, args : vec ! [ ] } } ) ;
7585+ fun. push_insn ( block, Insn :: Jump ( BranchEdge { target : unmodified_block, args : vec ! [ ] } ) ) ;
76087586
76097587 // Push modified block: load the block local via EP.
7610- let ep = fun. push_insn ( modified_block, Insn :: GetEP { level } ) ;
76117588 let modified_val = fun. get_local_from_ep ( modified_block, ep, ep_offset, level, types:: BasicObject ) ;
7612- if level == 0 {
7613- modified_state. setlocal ( ep_offset, modified_val) ;
7614- }
7615- modified_state. stack_push ( modified_val) ;
7616- fun. push_insn ( modified_block, Insn :: Jump ( BranchEdge { target : join_block, args : modified_state. as_args ( modified_self_param) } ) ) ;
7589+ let mut modified_args = vec ! [ modified_val] ;
7590+ if level == 0 { modified_args. push ( modified_val) ; }
7591+ fun. push_insn ( modified_block, Insn :: Jump ( BranchEdge { target : join_block, args : modified_args } ) ) ;
76177592
76187593 // Push unmodified block: inspect the current block handler to
76197594 // decide whether this path returns `nil` or `BlockParamProxy`.
7620- let ep = fun. push_insn ( unmodified_block, Insn :: GetEP { level } ) ;
76217595 let block_handler = fun. push_insn ( unmodified_block, Insn :: LoadField { recv : ep, id : ID ! ( _env_data_index_specval) , offset : SIZEOF_VALUE_I32 * VM_ENV_DATA_INDEX_SPECVAL , return_type : types:: CInt64 } ) ;
7596+ let original_local = if level == 0 { Some ( state. getlocal ( ep_offset) ) } else { None } ;
76227597
76237598 match profiled_block_type {
76247599 Some ( ty) if ty. nil_p ( ) => {
7625- fun. push_insn ( unmodified_block, Insn :: GuardBitEquals { val : block_handler, expected : Const :: CInt64 ( VM_BLOCK_HANDLER_NONE . into ( ) ) , reason : SideExitReason :: BlockParamProxyNotNil , state : unmodified_exit_id } ) ;
7626- unmodified_state. stack_push ( fun. push_insn ( unmodified_block, Insn :: Const { val : Const :: Value ( Qnil ) } ) ) ;
7627- fun. push_insn ( unmodified_block, Insn :: Jump ( BranchEdge { target : join_block, args : unmodified_state. as_args ( unmodified_self_param) } ) ) ;
7600+ fun. push_insn ( unmodified_block, Insn :: GuardBitEquals { val : block_handler, expected : Const :: CInt64 ( VM_BLOCK_HANDLER_NONE . into ( ) ) , reason : SideExitReason :: BlockParamProxyNotNil , state : exit_id } ) ;
7601+ let nil_val = fun. push_insn ( unmodified_block, Insn :: Const { val : Const :: Value ( Qnil ) } ) ;
7602+ let mut unmodified_args = vec ! [ nil_val] ;
7603+ if let Some ( local) = original_local { unmodified_args. push ( local) ; }
7604+ fun. push_insn ( unmodified_block, Insn :: Jump ( BranchEdge { target : join_block, args : unmodified_args } ) ) ;
76287605 }
76297606 _ => {
76307607 // This handles two cases which are nearly identical
@@ -7635,107 +7612,65 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
76357612 const _: ( ) = assert ! ( RUBY_SYMBOL_FLAG & 1 == 0 , "guard below rejects symbol block handlers" ) ;
76367613
76377614 // Bail out if the block handler is neither ISEQ nor ifunc
7638- fun. push_insn ( unmodified_block, Insn :: GuardAnyBitSet { val : block_handler, mask : Const :: CUInt64 ( 0x1 ) , mask_name : None , reason : SideExitReason :: BlockParamProxyNotIseqOrIfunc , state : unmodified_exit_id } ) ;
7615+ fun. push_insn ( unmodified_block, Insn :: GuardAnyBitSet { val : block_handler, mask : Const :: CUInt64 ( 0x1 ) , mask_name : None , reason : SideExitReason :: BlockParamProxyNotIseqOrIfunc , state : exit_id } ) ;
76397616 // TODO(Shopify/ruby#753): GC root, so we should be able to avoid unnecessary GC tracing
7640- unmodified_state. stack_push ( fun. push_insn ( unmodified_block, Insn :: Const { val : Const :: Value ( unsafe { rb_block_param_proxy } ) } ) ) ;
7641- fun. push_insn ( unmodified_block, Insn :: Jump ( BranchEdge { target : join_block, args : unmodified_state. as_args ( unmodified_self_param) } ) ) ;
7617+ let proxy_val = fun. push_insn ( unmodified_block, Insn :: Const { val : Const :: Value ( unsafe { rb_block_param_proxy } ) } ) ;
7618+ let mut unmodified_args = vec ! [ proxy_val] ;
7619+ if let Some ( local) = original_local { unmodified_args. push ( local) ; }
7620+ fun. push_insn ( unmodified_block, Insn :: Jump ( BranchEdge { target : join_block, args : unmodified_args } ) ) ;
76427621 }
76437622 }
76447623
76457624 // Continue compilation from the merged continuation block at the next
76467625 // instruction.
7647- queue. push_back ( ( unmodified_state, join_block, insn_idx, local_inval) ) ;
7648- break ;
7626+ if let Some ( local_param) = join_local {
7627+ state. setlocal ( ep_offset, local_param) ;
7628+ }
7629+ state. stack_push ( join_result) ;
7630+ block = join_block;
76497631 }
76507632 YARVINSN_getblockparam => {
7651- fn finish_getblockparam_branch (
7652- fun : & mut Function ,
7653- block : BlockId ,
7654- self_param : InsnId ,
7655- state : & mut FrameState ,
7656- join_block : BlockId ,
7657- ep_offset : u32 ,
7658- level : u32 ,
7659- val : InsnId ,
7660- ) {
7661- if level == 0 {
7662- state. setlocal ( ep_offset, val) ;
7663- }
7664- state. stack_push ( val) ;
7665- fun. push_insn ( block, Insn :: Jump ( BranchEdge {
7666- target : join_block,
7667- args : state. as_args ( self_param) ,
7668- } ) ) ;
7669- }
7670-
76717633 let ep_offset = get_arg ( pc, 0 ) . as_u32 ( ) ;
76727634 let level = get_arg ( pc, 1 ) . as_u32 ( ) ;
76737635 let branch_insn_idx = exit_state. insn_idx as u32 ;
76747636
76757637 // If the block param is already a Proc (modified), read it from EP.
76767638 // Otherwise, convert it to a Proc and store it to EP.
7639+ let modified_block = fun. new_block ( branch_insn_idx) ;
7640+ let unmodified_block = fun. new_block ( branch_insn_idx) ;
7641+ let join_block = insn_idx_to_block. get ( & insn_idx) . copied ( ) . unwrap_or_else ( || fun. new_block ( insn_idx) ) ;
7642+ let join_param = fun. push_insn ( join_block, Insn :: Param ) ;
7643+
76777644 let ep = fun. push_insn ( block, Insn :: GetEP { level } ) ;
76787645 let is_modified = fun. push_insn ( block, Insn :: IsBlockParamModified { ep } ) ;
76797646
7680- let locals_count = state. locals . len ( ) ;
7681- let stack_count = state. stack . len ( ) ;
7682- let entry_args = state. as_args ( self_param) ;
7683-
7684- // Set up branch and join blocks.
7685- let ( modified_block, modified_self_param, mut modified_state, ..) =
7686- fun. new_branch_block ( branch_insn_idx, & exit_state, locals_count, stack_count) ;
7687- let ( unmodified_block, unmodified_self_param, mut unmodified_state, unmodified_exit_id) =
7688- fun. new_branch_block ( branch_insn_idx, & exit_state, locals_count, stack_count) ;
7689- let join_block = insn_idx_to_block. get ( & insn_idx) . copied ( ) . unwrap_or_else ( || fun. new_block ( insn_idx) ) ;
7690-
76917647 fun. push_insn ( block, Insn :: IfTrue {
76927648 val : is_modified,
7693- target : BranchEdge { target : modified_block, args : entry_args . clone ( ) } ,
7649+ target : BranchEdge { target : modified_block, args : vec ! [ ] } ,
76947650 } ) ;
76957651 fun. push_insn ( block, Insn :: Jump ( BranchEdge {
76967652 target : unmodified_block,
7697- args : entry_args ,
7653+ args : vec ! [ ] ,
76987654 } ) ) ;
76997655
77007656 // Push modified block: read Proc from EP.
7701- let ep = fun. push_insn ( modified_block, Insn :: GetEP { level } ) ;
7702- let modified_val = fun. get_local_from_ep ( modified_block,
7703- ep,
7704- ep_offset,
7705- level,
7706- types:: BasicObject ,
7707- ) ;
7708- finish_getblockparam_branch (
7709- & mut fun,
7710- modified_block,
7711- modified_self_param,
7712- & mut modified_state,
7713- join_block,
7714- ep_offset,
7715- level,
7716- modified_val,
7717- ) ;
7657+ let modified_val = fun. get_local_from_ep ( modified_block, ep, ep_offset, level, types:: BasicObject ) ;
7658+ fun. push_insn ( modified_block, Insn :: Jump ( BranchEdge { target : join_block, args : vec ! [ modified_val] } ) ) ;
77187659
77197660 // Push unmodified block: convert block handler to Proc.
77207661 let unmodified_val = fun. push_insn ( unmodified_block, Insn :: GetBlockParam {
77217662 ep_offset,
77227663 level,
7723- state : unmodified_exit_id ,
7664+ state : exit_id ,
77247665 } ) ;
7725- finish_getblockparam_branch (
7726- & mut fun,
7727- unmodified_block,
7728- unmodified_self_param,
7729- & mut unmodified_state,
7730- join_block,
7731- ep_offset,
7732- level,
7733- unmodified_val,
7734- ) ;
7666+ fun. push_insn ( unmodified_block, Insn :: Jump ( BranchEdge { target : join_block, args : vec ! [ unmodified_val] } ) ) ;
77357667
77367668 // Continue compilation from the join block at the next instruction.
7737- queue. push_back ( ( unmodified_state, join_block, insn_idx, local_inval) ) ;
7738- break ;
7669+ if level == 0 {
7670+ state. setlocal ( ep_offset, join_param) ;
7671+ }
7672+ state. stack_push ( join_param) ;
7673+ block = join_block;
77397674 }
77407675 YARVINSN_pop => { state. stack_pop ( ) ?; }
77417676 YARVINSN_dup => { state. stack_push ( state. stack_top ( ) ?) ; }
0 commit comments