(blocks: &mut Vec<Block>, predecessors: &mut Vec<u32>)
| 2721 | } |
| 2722 | |
| 2723 | fn duplicate_exits_without_lineno(blocks: &mut Vec<Block>, predecessors: &mut Vec<u32>) { |
| 2724 | let mut current = BlockIdx(0); |
| 2725 | while current != BlockIdx::NULL { |
| 2726 | let block = &blocks[current.idx()]; |
| 2727 | let last = match block.instructions.last() { |
| 2728 | Some(ins) if ins.target != BlockIdx::NULL && is_jump_instruction(ins) => ins, |
| 2729 | _ => { |
| 2730 | current = blocks[current.idx()].next; |
| 2731 | continue; |
| 2732 | } |
| 2733 | }; |
| 2734 | |
| 2735 | let target = next_nonempty_block(blocks, last.target); |
| 2736 | if target == BlockIdx::NULL || !is_exit_without_lineno(&blocks[target.idx()]) { |
| 2737 | current = blocks[current.idx()].next; |
| 2738 | continue; |
| 2739 | } |
| 2740 | if predecessors[target.idx()] <= 1 { |
| 2741 | current = blocks[current.idx()].next; |
| 2742 | continue; |
| 2743 | } |
| 2744 | |
| 2745 | // Copy the exit block and splice it into the linked list after current |
| 2746 | let new_idx = BlockIdx(blocks.len() as u32); |
| 2747 | let mut new_block = blocks[target.idx()].clone(); |
| 2748 | let jump_loc = last.location; |
| 2749 | let jump_end_loc = last.end_location; |
| 2750 | propagate_locations_in_block(&mut new_block, jump_loc, jump_end_loc); |
| 2751 | let old_next = blocks[current.idx()].next; |
| 2752 | new_block.next = old_next; |
| 2753 | blocks.push(new_block); |
| 2754 | blocks[current.idx()].next = new_idx; |
| 2755 | |
| 2756 | // Update the jump target |
| 2757 | let last_mut = blocks[current.idx()].instructions.last_mut().unwrap(); |
| 2758 | last_mut.target = new_idx; |
| 2759 | predecessors[target.idx()] -= 1; |
| 2760 | predecessors.push(1); |
| 2761 | |
| 2762 | // Skip past the newly inserted block |
| 2763 | current = old_next; |
| 2764 | } |
| 2765 | |
| 2766 | current = BlockIdx(0); |
| 2767 | while current != BlockIdx::NULL { |
| 2768 | let block = &blocks[current.idx()]; |
| 2769 | if let Some(last) = block.instructions.last() |
| 2770 | && block_has_fallthrough(block) |
| 2771 | { |
| 2772 | let target = next_nonempty_block(blocks, block.next); |
| 2773 | if target != BlockIdx::NULL |
| 2774 | && predecessors[target.idx()] == 1 |
| 2775 | && is_exit_without_lineno(&blocks[target.idx()]) |
| 2776 | { |
| 2777 | let last_location = last.location; |
| 2778 | let last_end_location = last.end_location; |
| 2779 | propagate_locations_in_block( |
| 2780 | &mut blocks[target.idx()], |
no test coverage detected