Label exception targets: walk CFG with except stack, set per-instruction handler info and block preserve_lasti flag. Converts POP_BLOCK to NOP. flowgraph.c label_exception_targets + push_except_block
(blocks: &mut [Block])
| 2915 | /// handler info and block preserve_lasti flag. Converts POP_BLOCK to NOP. |
| 2916 | /// flowgraph.c label_exception_targets + push_except_block |
| 2917 | pub(crate) fn label_exception_targets(blocks: &mut [Block]) { |
| 2918 | #[derive(Clone)] |
| 2919 | struct ExceptEntry { |
| 2920 | handler_block: BlockIdx, |
| 2921 | preserve_lasti: bool, |
| 2922 | } |
| 2923 | |
| 2924 | let num_blocks = blocks.len(); |
| 2925 | if num_blocks == 0 { |
| 2926 | return; |
| 2927 | } |
| 2928 | |
| 2929 | let mut visited = vec![false; num_blocks]; |
| 2930 | let mut block_stacks: Vec<Option<Vec<ExceptEntry>>> = vec![None; num_blocks]; |
| 2931 | |
| 2932 | // Entry block |
| 2933 | visited[0] = true; |
| 2934 | block_stacks[0] = Some(Vec::new()); |
| 2935 | |
| 2936 | let mut todo = vec![BlockIdx(0)]; |
| 2937 | |
| 2938 | while let Some(block_idx) = todo.pop() { |
| 2939 | let bi = block_idx.idx(); |
| 2940 | let mut stack = block_stacks[bi].take().unwrap_or_default(); |
| 2941 | let mut last_yield_except_depth: i32 = -1; |
| 2942 | |
| 2943 | let instr_count = blocks[bi].instructions.len(); |
| 2944 | for i in 0..instr_count { |
| 2945 | // Read all needed fields (each temporary borrow ends immediately) |
| 2946 | let target = blocks[bi].instructions[i].target; |
| 2947 | let arg = blocks[bi].instructions[i].arg; |
| 2948 | let is_push = blocks[bi].instructions[i].instr.is_block_push(); |
| 2949 | let is_pop = blocks[bi].instructions[i].instr.is_pop_block(); |
| 2950 | |
| 2951 | if is_push { |
| 2952 | // Determine preserve_lasti from instruction type (push_except_block) |
| 2953 | let preserve_lasti = matches!( |
| 2954 | blocks[bi].instructions[i].instr.pseudo(), |
| 2955 | Some( |
| 2956 | PseudoInstruction::SetupWith { .. } |
| 2957 | | PseudoInstruction::SetupCleanup { .. } |
| 2958 | ) |
| 2959 | ); |
| 2960 | |
| 2961 | // Set preserve_lasti on handler block |
| 2962 | if preserve_lasti && target != BlockIdx::NULL { |
| 2963 | blocks[target.idx()].preserve_lasti = true; |
| 2964 | } |
| 2965 | |
| 2966 | // Propagate except stack to handler block if not visited |
| 2967 | if target != BlockIdx::NULL && !visited[target.idx()] { |
| 2968 | visited[target.idx()] = true; |
| 2969 | block_stacks[target.idx()] = Some(stack.clone()); |
| 2970 | todo.push(target); |
| 2971 | } |
| 2972 | |
| 2973 | // Push handler onto except stack |
| 2974 | stack.push(ExceptEntry { |
no test coverage detected