(&mut self)
| 1700 | } |
| 1701 | |
| 1702 | fn max_stackdepth(&mut self) -> crate::InternalResult<u32> { |
| 1703 | let mut maxdepth = 0u32; |
| 1704 | let mut stack = Vec::with_capacity(self.blocks.len()); |
| 1705 | let mut start_depths = vec![u32::MAX; self.blocks.len()]; |
| 1706 | stackdepth_push(&mut stack, &mut start_depths, BlockIdx(0), 0); |
| 1707 | const DEBUG: bool = false; |
| 1708 | 'process_blocks: while let Some(block_idx) = stack.pop() { |
| 1709 | let idx = block_idx.idx(); |
| 1710 | let mut depth = start_depths[idx]; |
| 1711 | if DEBUG { |
| 1712 | eprintln!("===BLOCK {}===", block_idx.0); |
| 1713 | } |
| 1714 | let block = &self.blocks[block_idx]; |
| 1715 | for ins in &block.instructions { |
| 1716 | let instr = &ins.instr; |
| 1717 | let effect = instr.stack_effect(ins.arg.into()); |
| 1718 | if DEBUG { |
| 1719 | let display_arg = if ins.target == BlockIdx::NULL { |
| 1720 | ins.arg |
| 1721 | } else { |
| 1722 | OpArg::new(ins.target.0) |
| 1723 | }; |
| 1724 | let instr_display = instr.display(display_arg, self); |
| 1725 | eprint!("{instr_display}: {depth} {effect:+} => "); |
| 1726 | } |
| 1727 | let new_depth = depth.checked_add_signed(effect).ok_or({ |
| 1728 | if effect < 0 { |
| 1729 | InternalError::StackUnderflow |
| 1730 | } else { |
| 1731 | InternalError::StackOverflow |
| 1732 | } |
| 1733 | })?; |
| 1734 | if DEBUG { |
| 1735 | eprintln!("{new_depth}"); |
| 1736 | } |
| 1737 | if new_depth > maxdepth { |
| 1738 | maxdepth = new_depth |
| 1739 | } |
| 1740 | // Process target blocks for branching instructions |
| 1741 | if ins.target != BlockIdx::NULL { |
| 1742 | if instr.is_block_push() { |
| 1743 | // SETUP_* pseudo ops: target is a handler block. |
| 1744 | // Handler entry depth uses the jump-path stack effect: |
| 1745 | // SETUP_FINALLY: +1 (pushes exc) |
| 1746 | // SETUP_CLEANUP: +2 (pushes lasti + exc) |
| 1747 | // SETUP_WITH: +1 (pops __enter__ result, pushes lasti + exc) |
| 1748 | let handler_effect: u32 = match instr.pseudo() { |
| 1749 | Some(PseudoInstruction::SetupCleanup { .. }) => 2, |
| 1750 | _ => 1, // SetupFinally and SetupWith |
| 1751 | }; |
| 1752 | let handler_depth = depth + handler_effect; |
| 1753 | if handler_depth > maxdepth { |
| 1754 | maxdepth = handler_depth; |
| 1755 | } |
| 1756 | stackdepth_push(&mut stack, &mut start_depths, ins.target, handler_depth); |
| 1757 | } else { |
| 1758 | // SEND jumps to END_SEND with receiver still on stack. |
| 1759 | // END_SEND performs the receiver pop. |
no test coverage detected