diff --git a/crates/codegen/src/compile.rs b/crates/codegen/src/compile.rs index 0ad465fb24c..3082219298c 100644 --- a/crates/codegen/src/compile.rs +++ b/crates/codegen/src/compile.rs @@ -12,7 +12,7 @@ use crate::{ IndexMap, IndexSet, ToPythonName, error::{CodegenError, CodegenErrorType, InternalError, PatternUnreachableReason}, - ir::{self, BlockIdx}, + ir::{self, Block, BlockIdx, Blocks}, preprocess, symboltable::{self, CompilerScope, Symbol, SymbolFlags, SymbolScope, SymbolTable}, unparse::UnparseExpr, @@ -470,7 +470,7 @@ impl Compiler { flags: CodeFlags::empty(), source_path: source_file.name().to_owned(), private: None, - blocks: vec![ir::Block::default()], + blocks: Blocks::from([Block::default()]), current_block: BlockIdx::new(0), instr_sequence: ir::InstructionSequence::new(), instr_sequence_label_map: ir::InstructionSequenceLabelMap::new(), @@ -547,8 +547,9 @@ impl Compiler { saved_annotations_instr_sequence, ) = { let code = self.current_code_info(); + ( - mem::replace(&mut code.blocks, vec![ir::Block::default()]), + mem::replace(&mut code.blocks, Blocks::from([Block::default()])), mem::replace(&mut code.current_block, BlockIdx::new(0)), mem::replace(&mut code.instr_sequence, ir::InstructionSequence::new()), mem::replace( @@ -1348,7 +1349,7 @@ impl Compiler { flags, source_path, private, - blocks: vec![ir::Block::default()], + blocks: Blocks::from([Block::default()]), current_block: BlockIdx::new(0), instr_sequence: ir::InstructionSequence::new(), instr_sequence_label_map: ir::InstructionSequenceLabelMap::new(), @@ -11024,7 +11025,7 @@ impl Compiler { unwrap_internal(self, result); let code = self.current_code_info(); let idx = BlockIdx::new(code.blocks.len().to_u32()); - code.blocks.push(ir::Block::default()); + code.blocks.push(Block::default()); let result = code.push_unmapped_instr_sequence_label(); unwrap_internal(self, result); idx @@ -11039,7 +11040,7 @@ impl Compiler { unwrap_internal(self, result); let code = self.current_code_info(); let idx = BlockIdx::new(code.blocks.len().to_u32()); - code.blocks.push(ir::Block::default()); + code.blocks.push(Block::default()); let result = code.push_unlabeled_instr_sequence_block(); unwrap_internal(self, result); idx diff --git a/crates/codegen/src/ir.rs b/crates/codegen/src/ir.rs index 58e68b48725..e7b50659e8e 100644 --- a/crates/codegen/src/ir.rs +++ b/crates/codegen/src/ir.rs @@ -1,4 +1,4 @@ -use core::ops; +use core::ops::{Deref, DerefMut, Index, IndexMut}; use crate::{IndexMap, IndexSet, error::InternalError}; use malachite_bigint::BigInt; @@ -141,7 +141,7 @@ impl ConstantPool { } } -impl ops::Index for ConstantPool { +impl Index for ConstantPool { type Output = ConstantData; fn index(&self, idx: usize) -> &Self::Output { @@ -190,44 +190,34 @@ impl BlockIdx { Self(value) } - /// Returns the inner value as a [`usize`]. + /// Returns the inner [`u32`] value. #[must_use] - pub const fn idx(self) -> usize { - self.0 as usize + pub const fn as_u32(self) -> u32 { + self.0 } -} -impl From for u32 { - fn from(block_idx: BlockIdx) -> Self { - block_idx.0 - } -} - -impl ops::Index for [Block] { - type Output = Block; - - fn index(&self, idx: BlockIdx) -> &Block { - &self[idx.idx()] + /// Returns the inner value as a [`usize`]. + #[must_use] + pub const fn as_usize(self) -> usize { + self.0 as usize } -} -impl ops::IndexMut for [Block] { - fn index_mut(&mut self, idx: BlockIdx) -> &mut Block { - &mut self[idx.idx()] + /// Returns the inner value as a [`usize`]. + #[must_use] + pub const fn idx(self) -> usize { + self.as_usize() } } -impl ops::Index for Vec { - type Output = Block; - - fn index(&self, idx: BlockIdx) -> &Block { - &self[idx.idx()] +impl From for u32 { + fn from(block_idx: BlockIdx) -> Self { + block_idx.as_u32() } } -impl ops::IndexMut for Vec { - fn index_mut(&mut self, idx: BlockIdx) -> &mut Block { - &mut self[idx.idx()] +impl From for usize { + fn from(block_idx: BlockIdx) -> Self { + block_idx.as_usize() } } @@ -449,16 +439,16 @@ fn basicblock_insert_instruction( /// flowgraph.c basicblock_append_instructions fn basicblock_append_block_instructions( - blocks: &mut [Block], + blocks: &mut Blocks, to: BlockIdx, from: BlockIdx, ) -> crate::InternalResult<()> { debug_assert_ne!(to, from); - let from_len = blocks[from.idx()].instruction_used; + let from_len = blocks[from].instruction_used; for i in 0..from_len { - let info = blocks[from.idx()].instructions[i]; - let off = basicblock_next_instr(&mut blocks[to.idx()])?; - blocks[to.idx()].instructions[off] = info; + let info = blocks[from].instructions[i]; + let off = basicblock_next_instr(&mut blocks[to])?; + blocks[to].instructions[off] = info; } Ok(()) } @@ -765,7 +755,7 @@ fn instruction_sequence_apply_label_map( /// flowgraph.c _PyCfg_ToInstructionSequence fn cfg_to_instruction_sequence( - blocks: &mut [Block], + blocks: &mut Blocks, instr_sequence: &mut InstructionSequence, ) -> crate::InternalResult<()> { let mut label_id = 0; @@ -1314,6 +1304,100 @@ impl Block { } } +#[derive(Clone, Debug, Default)] +pub struct Blocks(Vec); + +impl Blocks { + pub fn try_reserve( + &mut self, + additional: usize, + ) -> Result<(), alloc::collections::TryReserveError> { + self.0.try_reserve(additional) + } + + pub fn push(&mut self, value: Block) { + self.0.push(value) + } +} + +impl From> for Blocks { + fn from(value: Vec) -> Self { + Self(value) + } +} + +impl From> for Blocks { + fn from(value: Box<[Block]>) -> Self { + Self(value.into()) + } +} + +impl From<&[Block]> for Blocks { + fn from(value: &[Block]) -> Self { + Self(value.to_vec()) + } +} + +impl From<&mut [Block]> for Blocks { + fn from(value: &mut [Block]) -> Self { + Self(value.to_vec()) + } +} + +impl From<[Block; N]> for Blocks { + fn from(value: [Block; N]) -> Self { + Self(value.into()) + } +} + +impl From<&[Block; N]> for Blocks { + fn from(value: &[Block; N]) -> Self { + Self(value.to_vec()) + } +} + +impl Deref for Blocks { + type Target = [Block]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Blocks { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Index for Blocks { + type Output = Block; + + fn index(&self, idx: usize) -> &Self::Output { + &self.0[idx] + } +} + +impl IndexMut for Blocks { + fn index_mut(&mut self, idx: usize) -> &mut Self::Output { + &mut self.0[idx] + } +} + +impl Index for Blocks { + type Output = Block; + + fn index(&self, block_idx: BlockIdx) -> &Self::Output { + &self.0[block_idx.as_usize()] + } +} + +impl IndexMut for Blocks { + fn index_mut(&mut self, block_idx: BlockIdx) -> &mut Self::Output { + &mut self.0[block_idx.as_usize()] + } +} + pub(crate) const START_DEPTH_UNSET: i32 = i32::MIN; const CO_MAXBLOCKS: usize = 20; @@ -1541,7 +1625,7 @@ pub struct CodeInfo { pub source_path: String, pub private: Option, // For private name mangling, mostly for class - pub blocks: Vec, + pub blocks: Blocks, pub current_block: BlockIdx, pub(crate) instr_sequence: InstructionSequence, pub(crate) instr_sequence_label_map: InstructionSequenceLabelMap, @@ -1751,7 +1835,7 @@ impl CodeInfo { fn optimize_code_unit( metadata: &mut CodeUnitMetadata, - blocks: &mut Vec, + blocks: &mut Blocks, instr_sequence: InstructionSequence, nlocals: usize, nparams: usize, @@ -1776,7 +1860,7 @@ fn optimize_code_unit( fn optimize_cfg( metadata: &mut CodeUnitMetadata, - blocks: &mut Vec, + blocks: &mut Blocks, firstlineno: OneIndexed, ) -> crate::InternalResult<()> { // flowgraph.c optimize_cfg @@ -1798,7 +1882,7 @@ fn optimize_cfg( optimize_load_const(metadata, blocks)?; let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { - let next_block = blocks[block_idx.idx()].next; + let next_block = blocks[block_idx].next; optimize_basic_block(blocks, metadata, block_idx)?; block_idx = next_block; } @@ -1816,7 +1900,7 @@ fn optimize_cfg( fn optimized_cfg_to_instruction_sequence( metadata: &CodeUnitMetadata, flags: CodeFlags, - blocks: &mut Vec, + blocks: &mut Blocks, ) -> crate::InternalResult<(u32, usize, InstructionSequence)> { // Phase 2: _PyCfg_OptimizedCfgToInstructionSequence (flowgraph.c) convert_pseudo_conditional_jumps(blocks)?; @@ -1938,7 +2022,7 @@ fn is_generator(flags: CodeFlags) -> bool { /// flowgraph.c insert_prefix_instructions fn insert_prefix_instructions( metadata: &CodeUnitMetadata, - blocks: &mut [Block], + blocks: &mut Blocks, cellfixedoffsets: &[i32], nfreevars: usize, flags: CodeFlags, @@ -2036,7 +2120,7 @@ fn insert_prefix_instructions( /// flowgraph.c prepare_localsplus fn prepare_localsplus( metadata: &CodeUnitMetadata, - blocks: &mut [Block], + blocks: &mut Blocks, flags: CodeFlags, ) -> crate::InternalResult { let nlocals = metadata.varnames.len(); @@ -2060,11 +2144,11 @@ fn prepare_localsplus( } /// flowgraph.c remove_unreachable -fn remove_unreachable(blocks: &mut [Block]) -> crate::InternalResult<()> { +fn remove_unreachable(blocks: &mut Blocks) -> crate::InternalResult<()> { let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { - blocks[block_idx.idx()].predecessors = 0; - block_idx = blocks[block_idx.idx()].next; + blocks[block_idx].predecessors = 0; + block_idx = blocks[block_idx].next; } let mut stack = make_cfg_traversal_stack(blocks)?; @@ -2075,12 +2159,12 @@ fn remove_unreachable(blocks: &mut [Block]) -> crate::InternalResult<()> { let idx = current.idx(); let next = blocks[idx].next; if next != BlockIdx::NULL && bb_has_fallthrough(&blocks[idx]) { - if !blocks[next.idx()].visited { - debug_assert_eq!(blocks[next.idx()].predecessors, 0); + if !blocks[next].visited { + debug_assert_eq!(blocks[next].predecessors, 0); stack.push(next); - blocks[next.idx()].visited = true; + blocks[next].visited = true; } - blocks[next.idx()].predecessors += 1; + blocks[next].predecessors += 1; } let instr_count = blocks[idx].instruction_used; @@ -3612,7 +3696,7 @@ fn basicblock_optimize_load_const( /// flowgraph.c optimize_load_const fn optimize_load_const( metadata: &mut CodeUnitMetadata, - blocks: &mut [Block], + blocks: &mut Blocks, ) -> crate::InternalResult<()> { let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { @@ -3626,7 +3710,7 @@ fn optimize_load_const( /// flowgraph.c optimize_basic_block fn optimize_basic_block( - blocks: &mut [Block], + blocks: &mut Blocks, metadata: &mut CodeUnitMetadata, block_idx: BlockIdx, ) -> crate::InternalResult<()> { @@ -3871,7 +3955,7 @@ fn optimize_basic_block( /// flowgraph.c remove_redundant_nops_and_pairs #[allow(clippy::unnecessary_wraps)] -fn remove_redundant_nops_and_pairs(blocks: &mut [Block]) -> crate::InternalResult<()> { +fn remove_redundant_nops_and_pairs(blocks: &mut Blocks) -> crate::InternalResult<()> { let mut done = false; while !done { @@ -3910,17 +3994,17 @@ fn remove_redundant_nops_and_pairs(blocks: &mut [Block]) -> crate::InternalResul if is_redundant_pair { let (prev_block, prev_instr_idx) = prev_instr.expect("redundant pair has previous"); - set_to_nop(&mut blocks[prev_block.idx()].instructions[prev_instr_idx]); - set_to_nop(&mut blocks[block_idx.idx()].instructions[instr_idx]); + set_to_nop(&mut blocks[prev_block].instructions[prev_instr_idx]); + set_to_nop(&mut blocks[block_idx].instructions[instr_idx]); done = false; } } let instr_is_jump = instr.is_some_and(|(instr_block, instr_idx)| { - is_jump(&blocks[instr_block.idx()].instructions[instr_idx]) + is_jump(&blocks[instr_block].instructions[instr_idx]) }); - let block = &blocks[block_idx.idx()]; + let block = &blocks[block_idx]; if instr_is_jump || !bb_has_fallthrough(block) { instr = None; } @@ -3933,7 +4017,7 @@ fn remove_redundant_nops_and_pairs(blocks: &mut [Block]) -> crate::InternalResul /// flowgraph.c remove_unused_consts #[allow(clippy::needless_range_loop)] fn remove_unused_consts( - blocks: &mut [Block], + blocks: &mut Blocks, consts: &mut ConstantPool, ) -> crate::InternalResult<()> { let nconsts = consts.len(); @@ -4031,7 +4115,7 @@ fn remove_unused_consts( Ok(()) } -fn optimize_load_fast(blocks: &mut [Block]) -> crate::InternalResult<()> { +fn optimize_load_fast(blocks: &mut Blocks) -> crate::InternalResult<()> { let mut max_instrs = 0; let mut current = BlockIdx(0); while current != BlockIdx::NULL { @@ -4280,7 +4364,7 @@ fn optimize_load_fast(blocks: &mut [Block]) -> crate::InternalResult<()> { } /// flowgraph.c calculate_stackdepth -fn calculate_stackdepth(blocks: &mut [Block]) -> crate::InternalResult { +fn calculate_stackdepth(blocks: &mut Blocks) -> crate::InternalResult { let mut current = BlockIdx(0); while current != BlockIdx::NULL { blocks[current.idx()].start_depth = START_DEPTH_UNSET; @@ -4415,7 +4499,7 @@ impl CodeInfo { )); let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { - let next_block = self.blocks[block_idx.idx()].next; + let next_block = self.blocks[block_idx].next; optimize_basic_block(&mut self.blocks, &mut self.metadata, block_idx)?; block_idx = next_block; } @@ -4536,7 +4620,7 @@ fn make_super_instruction( } /// flowgraph.c insert_superinstructions -fn insert_superinstructions(blocks: &mut [Block]) -> crate::InternalResult { +fn insert_superinstructions(blocks: &mut Blocks) -> crate::InternalResult { let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { let next_block = blocks[block_idx.idx()].next; @@ -4685,22 +4769,22 @@ fn local_as_ref_local(local: usize) -> isize { /// flowgraph.c load_fast_push_block fn load_fast_push_block( worklist: &mut CfgTraversalStack, - blocks: &mut [Block], + blocks: &mut Blocks, target: BlockIdx, start_depth: usize, ) { debug_assert!(target != BlockIdx::NULL); - debug_assert!(blocks[target.idx()].start_depth >= 0); - debug_assert_eq!(blocks[target.idx()].start_depth as usize, start_depth,); - if !blocks[target.idx()].visited { - blocks[target.idx()].visited = true; + debug_assert!(blocks[target].start_depth >= 0); + debug_assert_eq!(blocks[target].start_depth as usize, start_depth,); + if !blocks[target].visited { + blocks[target].visited = true; worklist.push(target); } } fn stackdepth_push( stack: &mut CfgTraversalStack, - blocks: &mut [Block], + blocks: &mut Blocks, target: BlockIdx, depth: i32, ) -> crate::InternalResult<()> { @@ -5060,25 +5144,25 @@ fn assemble_exception_table( /// Mark exception handler target blocks. /// flowgraph.c mark_except_handlers #[allow(clippy::unnecessary_wraps)] -pub(crate) fn mark_except_handlers(blocks: &mut [Block]) -> crate::InternalResult<()> { +pub(crate) fn mark_except_handlers(blocks: &mut Blocks) -> crate::InternalResult<()> { #[cfg(debug_assertions)] { let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { - assert!(!blocks[block_idx.idx()].except_handler); - block_idx = blocks[block_idx.idx()].next; + assert!(!blocks[block_idx].except_handler); + block_idx = blocks[block_idx].next; } } let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { - let next = blocks[block_idx.idx()].next; - let instr_count = blocks[block_idx.idx()].instruction_used; + let next = blocks[block_idx].next; + let instr_count = blocks[block_idx].instruction_used; for i in 0..instr_count { - let instr = blocks[block_idx.idx()].instructions[i]; + let instr = blocks[block_idx].instructions[i]; if is_block_push(&instr) { debug_assert!(instr.target != BlockIdx::NULL); - blocks[instr.target.idx()].except_handler = true; + blocks[instr.target].except_handler = true; } } block_idx = next; @@ -5103,7 +5187,7 @@ pub(crate) fn mark_except_handlers(blocks: &mut [Block]) -> crate::InternalResul /// optimize_cfg). This matches CPython's behavior and is necessary for /// optimize_load_fast to terminate fall-through at those placeholders. /// flowgraph.c mark_warm -fn mark_warm(blocks: &mut [Block]) -> crate::InternalResult<()> { +fn mark_warm(blocks: &mut Blocks) -> crate::InternalResult<()> { let mut stack = make_cfg_traversal_stack(blocks)?; stack.push(BlockIdx(0)); blocks[0].visited = true; @@ -5113,8 +5197,7 @@ fn mark_warm(blocks: &mut [Block]) -> crate::InternalResult<()> { blocks[idx].warm = true; let next = blocks[idx].next; - if next != BlockIdx::NULL && bb_has_fallthrough(&blocks[idx]) && !blocks[next.idx()].visited - { + if next != BlockIdx::NULL && bb_has_fallthrough(&blocks[idx]) && !blocks[next].visited { stack.push(next); blocks[next.idx()].visited = true; } @@ -5135,7 +5218,7 @@ fn mark_warm(blocks: &mut [Block]) -> crate::InternalResult<()> { Ok(()) } -fn mark_cold(blocks: &mut [Block]) -> crate::InternalResult<()> { +fn mark_cold(blocks: &mut Blocks) -> crate::InternalResult<()> { let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { let block = &mut blocks[block_idx.idx()]; @@ -5189,7 +5272,7 @@ fn mark_cold(blocks: &mut [Block]) -> crate::InternalResult<()> { } /// flowgraph.c push_cold_blocks_to_end -fn push_cold_blocks_to_end(blocks: &mut Vec) -> crate::InternalResult<()> { +fn push_cold_blocks_to_end(blocks: &mut Blocks) -> crate::InternalResult<()> { if blocks[0].next == BlockIdx::NULL { return Ok(()); } @@ -5200,21 +5283,21 @@ fn push_cold_blocks_to_end(blocks: &mut Vec) -> crate::InternalResult<()> // If a cold block falls through to a warm block, add an explicit jump let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { - let next = blocks[block_idx.idx()].next; - if blocks[block_idx.idx()].cold - && bb_has_fallthrough(&blocks[block_idx.idx()]) + let next = blocks[block_idx].next; + if blocks[block_idx].cold + && bb_has_fallthrough(&blocks[block_idx]) && next != BlockIdx::NULL - && blocks[next.idx()].warm + && blocks[next].warm { let explicit_jump = blocks_new_block(blocks)?; - if !is_label(blocks[next.idx()].cpython_label) { - blocks[next.idx()].cpython_label = InstructionSequenceLabel::from_index(next_label); + if !is_label(blocks[next].cpython_label) { + blocks[next].cpython_label = InstructionSequenceLabel::from_index(next_label); next_label += 1; } - let jump_label = blocks[next.idx()].cpython_label; + let jump_label = blocks[next].cpython_label; debug_assert!(is_label(jump_label)); basicblock_addop( - &mut blocks[explicit_jump.idx()], + &mut blocks[explicit_jump], InstructionInfo { instr: PseudoOpcode::JumpNoInterrupt.into(), arg: instruction_sequence_label_oparg(jump_label), @@ -5225,16 +5308,16 @@ fn push_cold_blocks_to_end(blocks: &mut Vec) -> crate::InternalResult<()> lineno_override: Some(NO_LOCATION_OVERRIDE), }, )?; - blocks[explicit_jump.idx()].cold = true; - blocks[explicit_jump.idx()].next = next; - blocks[explicit_jump.idx()].predecessors = 1; - blocks[block_idx.idx()].next = explicit_jump; - let target = blocks[explicit_jump.idx()].next; - let last = basicblock_last_instr_mut(&mut blocks[explicit_jump.idx()]) + blocks[explicit_jump].cold = true; + blocks[explicit_jump].next = next; + blocks[explicit_jump].predecessors = 1; + blocks[block_idx].next = explicit_jump; + let target = blocks[explicit_jump].next; + let last = basicblock_last_instr_mut(&mut blocks[explicit_jump]) .expect("missing explicit jump"); last.target = target; } - block_idx = blocks[block_idx.idx()].next; + block_idx = blocks[block_idx].next; } assert!(!blocks[0].cold); @@ -5242,45 +5325,41 @@ fn push_cold_blocks_to_end(blocks: &mut Vec) -> crate::InternalResult<()> let mut cold_blocks_tail: BlockIdx = BlockIdx::NULL; let mut block_idx = BlockIdx(0); - while blocks[block_idx.idx()].next != BlockIdx::NULL { - debug_assert!(!blocks[block_idx.idx()].cold); - while blocks[block_idx.idx()].next != BlockIdx::NULL - && !blocks[blocks[block_idx.idx()].next.idx()].cold - { - block_idx = blocks[block_idx.idx()].next; + while blocks[block_idx].next != BlockIdx::NULL { + debug_assert!(!blocks[block_idx].cold); + while blocks[block_idx].next != BlockIdx::NULL && !blocks[blocks[block_idx].next].cold { + block_idx = blocks[block_idx].next; } - if blocks[block_idx.idx()].next == BlockIdx::NULL { + if blocks[block_idx].next == BlockIdx::NULL { break; } - debug_assert!(!blocks[block_idx.idx()].cold); - debug_assert!(blocks[blocks[block_idx.idx()].next.idx()].cold); + debug_assert!(!blocks[block_idx].cold); + debug_assert!(blocks[blocks[block_idx].next].cold); - let mut block_end = blocks[block_idx.idx()].next; - while blocks[block_end.idx()].next != BlockIdx::NULL - && blocks[blocks[block_end.idx()].next.idx()].cold - { - block_end = blocks[block_end.idx()].next; + let mut block_end = blocks[block_idx].next; + while blocks[block_end].next != BlockIdx::NULL && blocks[blocks[block_end].next].cold { + block_end = blocks[block_end].next; } - debug_assert!(blocks[block_end.idx()].cold); + debug_assert!(blocks[block_end].cold); debug_assert!( - blocks[block_end.idx()].next == BlockIdx::NULL - || !blocks[blocks[block_end.idx()].next.idx()].cold + blocks[block_end].next == BlockIdx::NULL || !blocks[blocks[block_end].next].cold ); if cold_blocks == BlockIdx::NULL { - cold_blocks = blocks[block_idx.idx()].next; + cold_blocks = blocks[block_idx].next; } else { - blocks[cold_blocks_tail.idx()].next = blocks[block_idx.idx()].next; + blocks[cold_blocks_tail].next = blocks[block_idx].next; } + cold_blocks_tail = block_end; - blocks[block_idx.idx()].next = blocks[block_end.idx()].next; - blocks[block_end.idx()].next = BlockIdx::NULL; + blocks[block_idx].next = blocks[block_end].next; + blocks[block_end].next = BlockIdx::NULL; } - debug_assert!(blocks[block_idx.idx()].next == BlockIdx::NULL); - blocks[block_idx.idx()].next = cold_blocks; + debug_assert!(blocks[block_idx].next == BlockIdx::NULL); + blocks[block_idx].next = cold_blocks; if cold_blocks != BlockIdx::NULL { remove_redundant_nops_and_jumps(blocks)?; @@ -5289,10 +5368,10 @@ fn push_cold_blocks_to_end(blocks: &mut Vec) -> crate::InternalResult<()> } /// flowgraph.c check_cfg -fn check_cfg(blocks: &[Block]) -> crate::InternalResult<()> { +fn check_cfg(blocks: &Blocks) -> crate::InternalResult<()> { let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { - let block = &blocks[block_idx.idx()]; + let block = &blocks[block_idx]; for i in 0..block.instruction_used { let opcode = block.instructions[i].instr; debug_assert!(!opcode.is_assembler()); @@ -5307,7 +5386,7 @@ fn check_cfg(blocks: &[Block]) -> crate::InternalResult<()> { /// flowgraph.c jump_thread fn jump_thread( - blocks: &mut [Block], + blocks: &mut Blocks, block_idx: BlockIdx, instr_idx: usize, target: &InstructionInfo, @@ -5328,7 +5407,7 @@ fn jump_thread( /// flowgraph.c basicblock_add_jump fn basicblock_add_jump( - blocks: &mut [Block], + blocks: &mut Blocks, block_idx: BlockIdx, instr: AnyInstruction, target: BlockIdx, @@ -5382,7 +5461,7 @@ fn is_conditional_jump_opcode(instr: AnyInstruction) -> bool { } /// flowgraph.c convert_pseudo_conditional_jumps -fn convert_pseudo_conditional_jumps(blocks: &mut [Block]) -> crate::InternalResult<()> { +fn convert_pseudo_conditional_jumps(blocks: &mut Blocks) -> crate::InternalResult<()> { let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { let next = blocks[block_idx.idx()].next; @@ -5440,10 +5519,7 @@ fn convert_pseudo_conditional_jumps(blocks: &mut [Block]) -> crate::InternalResu } /// flowgraph.c normalize_jumps_in_block -fn normalize_jumps_in_block( - blocks: &mut Vec, - block_idx: BlockIdx, -) -> crate::InternalResult<()> { +fn normalize_jumps_in_block(blocks: &mut Blocks, block_idx: BlockIdx) -> crate::InternalResult<()> { let idx = block_idx.idx(); let Some(last_ins) = basicblock_last_instr(&blocks[idx]).copied() else { return Ok(()); @@ -5521,7 +5597,7 @@ fn normalize_jumps_in_block( } /// flowgraph.c normalize_jumps -fn normalize_jumps(blocks: &mut Vec) -> crate::InternalResult<()> { +fn normalize_jumps(blocks: &mut Blocks) -> crate::InternalResult<()> { let mut current = BlockIdx(0); while current != BlockIdx::NULL { blocks[current.idx()].visited = false; @@ -5540,10 +5616,10 @@ fn normalize_jumps(blocks: &mut Vec) -> crate::InternalResult<()> { /// flowgraph.c basicblock_inline_small_or_no_lineno_blocks fn basicblock_inline_small_or_no_lineno_blocks( - blocks: &mut [Block], + blocks: &mut Blocks, block_idx: BlockIdx, ) -> crate::InternalResult { - let Some(last) = basicblock_last_instr(&blocks[block_idx.idx()]).copied() else { + let Some(last) = basicblock_last_instr(&blocks[block_idx]).copied() else { return Ok(false); }; if !last.instr.is_unconditional_jump() { @@ -5552,19 +5628,19 @@ fn basicblock_inline_small_or_no_lineno_blocks( let target = last.target; debug_assert!(target != BlockIdx::NULL); - let small_exit_block = basicblock_exits_scope(&blocks[target.idx()]) - && blocks[target.idx()].instruction_used <= MAX_COPY_SIZE; - let no_lineno_no_fallthrough = basicblock_has_no_lineno(&blocks[target.idx()]) - && !bb_has_fallthrough(&blocks[target.idx()]); + let small_exit_block = + basicblock_exits_scope(&blocks[target]) && blocks[target].instruction_used <= MAX_COPY_SIZE; + let no_lineno_no_fallthrough = + basicblock_has_no_lineno(&blocks[target]) && !bb_has_fallthrough(&blocks[target]); if small_exit_block || no_lineno_no_fallthrough { debug_assert!(is_jump(&last)); let removed_jump_opcode = last.instr; - let last = basicblock_last_instr_mut(&mut blocks[block_idx.idx()]) + let last = basicblock_last_instr_mut(&mut blocks[block_idx]) .expect("non-empty block has last instruction"); set_to_nop(last); basicblock_append_block_instructions(blocks, block_idx, target)?; if no_lineno_no_fallthrough { - let last = basicblock_last_instr_mut(&mut blocks[block_idx.idx()]).unwrap(); + let last = basicblock_last_instr_mut(&mut blocks[block_idx]).unwrap(); if last.instr.is_unconditional_jump() && matches!( removed_jump_opcode.into(), @@ -5574,14 +5650,14 @@ fn basicblock_inline_small_or_no_lineno_blocks( last.instr = PseudoOpcode::Jump.into(); } } - blocks[target.idx()].predecessors -= 1; + blocks[target].predecessors -= 1; return Ok(true); } Ok(false) } /// flowgraph.c inline_small_or_no_lineno_blocks -fn inline_small_or_no_lineno_blocks(blocks: &mut [Block]) -> crate::InternalResult { +fn inline_small_or_no_lineno_blocks(blocks: &mut Blocks) -> crate::InternalResult { loop { let mut changes = false; let mut current = BlockIdx(0); @@ -5603,7 +5679,7 @@ fn inline_small_or_no_lineno_blocks(blocks: &mut [Block]) -> crate::InternalResu /// flowgraph.c basicblock_remove_redundant_nops #[allow(clippy::unnecessary_wraps)] fn basicblock_remove_redundant_nops( - blocks: &mut [Block], + blocks: &mut Blocks, block_idx: BlockIdx, ) -> crate::InternalResult { let bi = block_idx.idx(); @@ -5674,7 +5750,7 @@ fn basicblock_remove_redundant_nops( /// flowgraph.c remove_redundant_nops #[allow(clippy::unnecessary_wraps)] -fn remove_redundant_nops(blocks: &mut [Block]) -> crate::InternalResult { +fn remove_redundant_nops(blocks: &mut Blocks) -> crate::InternalResult { let mut changes = 0; let mut current = BlockIdx(0); while current != BlockIdx::NULL { @@ -5688,12 +5764,12 @@ fn remove_redundant_nops(blocks: &mut [Block]) -> crate::InternalResult { /// flowgraph.c no_redundant_nops #[cfg(debug_assertions)] -fn no_redundant_nops(blocks: &mut [Block]) -> bool { +fn no_redundant_nops(blocks: &mut Blocks) -> bool { matches!(remove_redundant_nops(blocks), Ok(0)) } /// flowgraph.c remove_redundant_jumps -fn remove_redundant_jumps(blocks: &mut [Block]) -> crate::InternalResult { +fn remove_redundant_jumps(blocks: &mut Blocks) -> crate::InternalResult { let mut changes = 0; let mut current = BlockIdx(0); while current != BlockIdx::NULL { @@ -5722,7 +5798,7 @@ fn remove_redundant_jumps(blocks: &mut [Block]) -> crate::InternalResult /// flowgraph.c no_redundant_jumps #[cfg(debug_assertions)] -fn no_redundant_jumps(blocks: &[Block]) -> bool { +fn no_redundant_jumps(blocks: &Blocks) -> bool { let mut current = BlockIdx(0); while current != BlockIdx::NULL { let block = &blocks[current.idx()]; @@ -5750,7 +5826,7 @@ fn no_redundant_jumps(blocks: &[Block]) -> bool { true } -fn remove_redundant_nops_and_jumps(blocks: &mut [Block]) -> crate::InternalResult<()> { +fn remove_redundant_nops_and_jumps(blocks: &mut Blocks) -> crate::InternalResult<()> { loop { // Convergence is guaranteed because the number of redundant jumps and // nops only decreases. @@ -5764,7 +5840,7 @@ fn remove_redundant_nops_and_jumps(blocks: &mut [Block]) -> crate::InternalResul } /// flowgraph.c make_cfg_traversal_stack -fn make_cfg_traversal_stack(blocks: &mut [Block]) -> crate::InternalResult { +fn make_cfg_traversal_stack(blocks: &mut Blocks) -> crate::InternalResult { debug_assert!(!blocks.is_empty()); let mut nblocks = 0; let mut current = BlockIdx(0); @@ -5784,7 +5860,7 @@ fn make_cfg_traversal_stack(blocks: &mut [Block]) -> crate::InternalResult) -> crate::InternalResult { +fn blocks_new_block(blocks: &mut Blocks) -> crate::InternalResult { blocks .try_reserve(1) .map_err(|_| InternalError::MalformedControlFlowGraph)?; @@ -5800,7 +5876,7 @@ fn blocks_new_block(blocks: &mut Vec) -> crate::InternalResult /// flowgraph.c struct _PyCfgBuilder struct CfgBuilder { - blocks: Vec, + blocks: Blocks, entry: BlockIdx, block_list: BlockIdx, current: BlockIdx, @@ -5837,7 +5913,7 @@ fn init_cfg_builder(g: &mut CfgBuilder) -> crate::InternalResult<()> { /// flowgraph.c _PyCfgBuilder_New fn cfg_builder_new() -> crate::InternalResult { let mut builder = CfgBuilder { - blocks: Vec::new(), + blocks: Blocks::default(), entry: BlockIdx::NULL, block_list: BlockIdx::NULL, current: BlockIdx::NULL, @@ -5887,7 +5963,7 @@ fn cfg_builder_use_label( /// flowgraph.c _PyCfgBuilder_Addop fn cfg_builder_addop(g: &mut CfgBuilder, info: InstructionInfo) -> crate::InternalResult<()> { cfg_builder_maybe_start_new_block(g)?; - basicblock_addop(&mut g.blocks[g.current.idx()], info) + basicblock_addop(&mut g.blocks[g.current], info) } /// flowgraph.c cfg_builder_check @@ -5935,7 +6011,7 @@ fn cfg_builder_check_size(g: &CfgBuilder) -> crate::InternalResult<()> { } /// flowgraph.c translate_jump_labels_to_targets -fn translate_jump_labels_to_targets(blocks: &mut [Block]) -> crate::InternalResult<()> { +fn translate_jump_labels_to_targets(blocks: &mut Blocks) -> crate::InternalResult<()> { let max_label = get_max_label(blocks); let label_count = (max_label + 1) as usize; if label_count > usize::MAX / core::mem::size_of::() { @@ -5947,7 +6023,7 @@ fn translate_jump_labels_to_targets(blocks: &mut [Block]) -> crate::InternalResu let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { - let block = &blocks[block_idx.idx()]; + let block = &blocks[block_idx]; if is_label(block.cpython_label) { let label_id = block.cpython_label; debug_assert!(label_id.0 <= max_label); @@ -5958,20 +6034,17 @@ fn translate_jump_labels_to_targets(blocks: &mut [Block]) -> crate::InternalResu block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { - let next = blocks[block_idx.idx()].next; - for i in 0..blocks[block_idx.idx()].instruction_used { - let info = &mut blocks[block_idx.idx()].instructions[i]; + let next = blocks[block_idx].next; + for i in 0..blocks[block_idx].instruction_used { + let info = &mut blocks[block_idx].instructions[i]; debug_assert_eq!(info.target, BlockIdx::NULL); if info.instr.has_target() { let lbl = u32::from(info.arg) as i32; debug_assert!(lbl >= 0 && lbl <= max_label); let target = label_to_block[lbl as usize]; debug_assert!(target != BlockIdx::NULL); - debug_assert_eq!( - blocks[target.idx()].cpython_label, - InstructionSequenceLabel(lbl) - ); info.target = target; + debug_assert_eq!(blocks[target].cpython_label, InstructionSequenceLabel(lbl)); } } block_idx = next; @@ -5982,7 +6055,7 @@ fn translate_jump_labels_to_targets(blocks: &mut [Block]) -> crate::InternalResu /// flowgraph.c _PyCfg_FromInstructionSequence fn cfg_from_instruction_sequence( mut instr_sequence: InstructionSequence, -) -> crate::InternalResult> { +) -> crate::InternalResult { instruction_sequence_apply_label_map(&mut instr_sequence)?; let mut builder = cfg_builder_new()?; @@ -6061,7 +6134,7 @@ fn cfg_from_instruction_sequence( /// flowgraph.c maybe_push fn maybe_push( - blocks: &mut [Block], + blocks: &mut Blocks, worklist: &mut CfgTraversalStack, block: BlockIdx, unsafe_mask: u64, @@ -6081,7 +6154,7 @@ fn maybe_push( /// flowgraph.c scan_block_for_locals fn scan_block_for_locals( - blocks: &mut [Block], + blocks: &mut Blocks, block_idx: BlockIdx, worklist: &mut CfgTraversalStack, ) { @@ -6150,7 +6223,7 @@ fn scan_block_for_locals( } /// flowgraph.c fast_scan_many_locals -fn fast_scan_many_locals(blocks: &mut [Block], nlocals: usize) -> crate::InternalResult<()> { +fn fast_scan_many_locals(blocks: &mut Blocks, nlocals: usize) -> crate::InternalResult<()> { debug_assert!(nlocals > LOCAL_UNSAFE_MASK_BITS); let mut states = Vec::new(); states @@ -6198,7 +6271,7 @@ fn fast_scan_many_locals(blocks: &mut [Block], nlocals: usize) -> crate::Interna /// flowgraph.c add_checks_for_loads_of_uninitialized_variables fn add_checks_for_loads_of_uninitialized_variables( - blocks: &mut [Block], + blocks: &mut Blocks, mut nlocals: usize, nparams: usize, ) -> crate::InternalResult<()> { @@ -6232,9 +6305,9 @@ fn add_checks_for_loads_of_uninitialized_variables( } /// Follow chain of empty blocks to find first non-empty block. -fn next_nonempty_block(blocks: &[Block], mut idx: BlockIdx) -> BlockIdx { - while idx != BlockIdx::NULL && blocks[idx.idx()].instruction_used == 0 { - idx = blocks[idx.idx()].next; +fn next_nonempty_block(blocks: &Blocks, mut idx: BlockIdx) -> BlockIdx { + while idx != BlockIdx::NULL && blocks[idx].instruction_used == 0 { + idx = blocks[idx].next; } idx } @@ -6333,10 +6406,7 @@ fn basicblock_has_no_lineno(block: &Block) -> bool { } /// flowgraph.c copy_basicblock -fn copy_basicblock( - blocks: &mut Vec, - block_idx: BlockIdx, -) -> crate::InternalResult { +fn copy_basicblock(blocks: &mut Blocks, block_idx: BlockIdx) -> crate::InternalResult { debug_assert!(bb_no_fallthrough(&blocks[block_idx.idx()])); let result = blocks_new_block(blocks)?; basicblock_append_block_instructions(blocks, result, block_idx)?; @@ -6344,7 +6414,7 @@ fn copy_basicblock( } /// flowgraph.c get_max_label -fn get_max_label(blocks: &[Block]) -> i32 { +fn get_max_label(blocks: &Blocks) -> i32 { let mut lbl = -1; let mut current = BlockIdx(0); while current != BlockIdx::NULL { @@ -6355,61 +6425,58 @@ fn get_max_label(blocks: &[Block]) -> i32 { lbl } -fn duplicate_exits_without_lineno(blocks: &mut Vec) -> crate::InternalResult<()> { +fn duplicate_exits_without_lineno(blocks: &mut Blocks) -> crate::InternalResult<()> { let mut next_lbl = get_max_label(blocks) + 1; let entryblock = BlockIdx(0); let mut b = entryblock; while b != BlockIdx::NULL { - let Some(last) = basicblock_last_instr(&blocks[b.idx()]).copied() else { - b = blocks[b.idx()].next; + let Some(last) = basicblock_last_instr(&blocks[b]).copied() else { + b = blocks[b].next; continue; }; if is_jump(&last) { debug_assert!(last.target != BlockIdx::NULL); let target = next_nonempty_block(blocks, last.target); debug_assert!(target != BlockIdx::NULL); - if is_exit_or_eval_check_without_lineno(&blocks[target.idx()]) - && blocks[target.idx()].predecessors > 1 + if is_exit_or_eval_check_without_lineno(&blocks[target]) + && blocks[target].predecessors > 1 { let new_target = copy_basicblock(blocks, target)?; instr_set_location( - &mut blocks[new_target.idx()].instructions[0], + &mut blocks[new_target].instructions[0], instr_location(&last), ); - let last_mut = basicblock_last_instr_mut(&mut blocks[b.idx()]).unwrap(); + let last_mut = basicblock_last_instr_mut(&mut blocks[b]).unwrap(); last_mut.target = new_target; - blocks[target.idx()].predecessors -= 1; - blocks[new_target.idx()].predecessors = 1; - blocks[new_target.idx()].next = blocks[target.idx()].next; - blocks[new_target.idx()].cpython_label = InstructionSequenceLabel(next_lbl); + blocks[target].predecessors -= 1; + blocks[new_target].predecessors = 1; + blocks[new_target].next = blocks[target].next; + blocks[new_target].cpython_label = InstructionSequenceLabel(next_lbl); next_lbl += 1; - blocks[target.idx()].next = new_target; + blocks[target].next = new_target; } } - b = blocks[b.idx()].next; + b = blocks[b].next; } b = entryblock; while b != BlockIdx::NULL { - let next = blocks[b.idx()].next; - if bb_has_fallthrough(&blocks[b.idx()]) + let next = blocks[b].next; + if bb_has_fallthrough(&blocks[b]) && next != BlockIdx::NULL - && blocks[b.idx()].instruction_used != 0 - && is_exit_or_eval_check_without_lineno(&blocks[next.idx()]) + && blocks[b].instruction_used != 0 + && is_exit_or_eval_check_without_lineno(&blocks[next]) { - let last = *basicblock_last_instr(&blocks[b.idx()]).expect("block has instructions"); - instr_set_location( - &mut blocks[next.idx()].instructions[0], - instr_location(&last), - ); + let last = *basicblock_last_instr(&blocks[b]).expect("block has instructions"); + instr_set_location(&mut blocks[next].instructions[0], instr_location(&last)); } - b = blocks[b.idx()].next; + b = blocks[b].next; } Ok(()) } -fn propagate_line_numbers(blocks: &mut [Block]) { +fn propagate_line_numbers(blocks: &mut Blocks) { let mut current = BlockIdx(0); while current != BlockIdx::NULL { let idx = current.idx(); @@ -6431,30 +6498,30 @@ fn propagate_line_numbers(blocks: &mut [Block]) { if bb_has_fallthrough(&blocks[idx]) { debug_assert!(next != BlockIdx::NULL); if next != BlockIdx::NULL - && blocks[next.idx()].predecessors == 1 - && blocks[next.idx()].instruction_used != 0 - && instruction_is_no_location(&blocks[next.idx()].instructions[0]) + && blocks[next].predecessors == 1 + && blocks[next].instruction_used != 0 + && instruction_is_no_location(&blocks[next].instructions[0]) { - instr_set_location(&mut blocks[next.idx()].instructions[0], prev_location); + instr_set_location(&mut blocks[next].instructions[0], prev_location); } } if is_jump(&last) { let target = last.target; debug_assert!(target != BlockIdx::NULL); - if blocks[target.idx()].predecessors == 1 { - let instr = basicblock_raw_first_instr_mut(&mut blocks[target.idx()]); + if blocks[target].predecessors == 1 { + let instr = basicblock_raw_first_instr_mut(&mut blocks[target]); if instruction_is_no_location(instr) { instr_set_location(instr, prev_location); } } } - current = blocks[current.idx()].next; + current = blocks[current].next; } } fn resolve_line_numbers( - blocks: &mut Vec, + blocks: &mut Blocks, _firstlineno: OneIndexed, ) -> crate::InternalResult<()> { duplicate_exits_without_lineno(blocks)?; @@ -6481,7 +6548,7 @@ fn copy_except_stack(stack: &CfgExceptStack) -> crate::InternalResult Option { +fn except_stack_top(stack: &CfgExceptStack, blocks: &Blocks) -> Option { debug_assert!(stack.depth <= CO_MAXBLOCKS + 1); let handler_block = stack.handlers[stack.depth]; if handler_block == BlockIdx::NULL { @@ -6489,7 +6556,7 @@ fn except_stack_top(stack: &CfgExceptStack, blocks: &[Block]) -> Option Option Option { debug_assert!(is_block_push(&setup)); let instr = setup.instr; @@ -6507,7 +6574,7 @@ fn push_except_block( instr.pseudo(), Some(PseudoInstruction::SetupWith { .. } | PseudoInstruction::SetupCleanup { .. }) ) { - blocks[target.idx()].preserve_lasti = true; + blocks[target].preserve_lasti = true; } debug_assert!(stack.depth <= CO_MAXBLOCKS); stack.depth += 1; @@ -6517,14 +6584,14 @@ fn push_except_block( } /// flowgraph.c pop_except_block -fn pop_except_block(stack: &mut CfgExceptStack, blocks: &[Block]) -> Option { +fn pop_except_block(stack: &mut CfgExceptStack, blocks: &Blocks) -> Option { debug_assert!(stack.depth > 0); stack.depth -= 1; debug_assert!(stack.depth <= CO_MAXBLOCKS); except_stack_top(stack, blocks) } -pub(crate) fn label_exception_targets(blocks: &mut [Block]) -> crate::InternalResult<()> { +pub(crate) fn label_exception_targets(blocks: &mut Blocks) -> crate::InternalResult<()> { let mut todo = make_cfg_traversal_stack(blocks)?; todo.push(BlockIdx(0)); @@ -6553,12 +6620,12 @@ pub(crate) fn label_exception_targets(blocks: &mut [Block]) -> crate::InternalRe if is_block_push(&info) { debug_assert!(target != BlockIdx::NULL); - if !blocks[target.idx()].visited { - blocks[target.idx()].except_stack = Some(copy_except_stack( + if !blocks[target].visited { + blocks[target].except_stack = Some(copy_except_stack( stack.as_ref().expect("active exception stack"), )?); todo.push(target); - blocks[target.idx()].visited = true; + blocks[target].visited = true; } handler = push_except_block( stack.as_mut().expect("active exception stack"), @@ -6576,20 +6643,20 @@ pub(crate) fn label_exception_targets(blocks: &mut [Block]) -> crate::InternalRe // when this block can also fall through, otherwise transfer it // to the jump target. debug_assert!(target != BlockIdx::NULL); - if !blocks[target.idx()].visited { + if !blocks[target].visited { if bb_has_fallthrough(&blocks[bi]) { - blocks[target.idx()].except_stack = Some(copy_except_stack( + blocks[target].except_stack = Some(copy_except_stack( stack.as_ref().expect("active exception stack"), )?); } else { - blocks[target.idx()].except_stack = stack.take(); + blocks[target].except_stack = stack.take(); stack_transferred = true; todo.push(target); - blocks[target.idx()].visited = true; + blocks[target].visited = true; break; } todo.push(target); - blocks[target.idx()].visited = true; + blocks[target].visited = true; } } else if matches!(instr.real(), Some(Instruction::YieldValue { .. })) { blocks[bi].instructions[i].except_handler = handler; @@ -6614,10 +6681,10 @@ pub(crate) fn label_exception_targets(blocks: &mut [Block]) -> crate::InternalRe let next = blocks[bi].next; if !stack_transferred && bb_has_fallthrough(&blocks[bi]) { debug_assert!(next != BlockIdx::NULL); - if next != BlockIdx::NULL && !blocks[next.idx()].visited { - blocks[next.idx()].except_stack = stack.take(); + if next != BlockIdx::NULL && !blocks[next].visited { + blocks[next].except_stack = stack.take(); todo.push(next); - blocks[next.idx()].visited = true; + blocks[next].visited = true; } } } @@ -6625,7 +6692,7 @@ pub(crate) fn label_exception_targets(blocks: &mut [Block]) -> crate::InternalRe { let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { - let block = &blocks[block_idx.idx()]; + let block = &blocks[block_idx]; debug_assert!(block.except_stack.is_none()); block_idx = block.next; } @@ -6635,7 +6702,7 @@ pub(crate) fn label_exception_targets(blocks: &mut [Block]) -> crate::InternalRe /// Convert remaining pseudo ops to real instructions or NOP. /// flowgraph.c convert_pseudo_ops -pub(crate) fn convert_pseudo_ops(blocks: &mut [Block]) -> crate::InternalResult<()> { +pub(crate) fn convert_pseudo_ops(blocks: &mut Blocks) -> crate::InternalResult<()> { let mut block_idx = BlockIdx(0); while block_idx != BlockIdx::NULL { let next = blocks[block_idx.idx()].next; @@ -6703,7 +6770,7 @@ pub(crate) fn build_cellfixedoffsets( #[allow(clippy::needless_range_loop)] pub(crate) fn fix_cell_offsets( metadata: &CodeUnitMetadata, - blocks: &mut [Block], + blocks: &mut Blocks, cellfixedoffsets: &mut [i32], ) -> usize { let nlocals = metadata.varnames.len(); @@ -6802,7 +6869,7 @@ mod tests { flags: CodeFlags::empty(), source_path: "source_path".to_owned(), private: None, - blocks: vec![block], + blocks: Blocks::from([block]), current_block: BlockIdx::new(0), instr_sequence: instruction_sequence_new(), instr_sequence_label_map: InstructionSequenceLabelMap::new(), @@ -6881,7 +6948,7 @@ mod tests { assert_eq!(stack.handlers.len(), CO_MAXBLOCKS + 2); assert_eq!(stack.handlers[0], BlockIdx::NULL); - let mut blocks = vec![Block::default(), Block::default()]; + let mut blocks = Blocks::from([Block::default(), Block::default()]); assert!(except_stack_top(&stack, &blocks).is_none()); let setup = InstructionInfo { @@ -6942,7 +7009,7 @@ mod tests { #[test] fn cfg_traversal_stack_resets_visited_and_allocates_for_blocks() { - let mut blocks = vec![Block::default(), Block::default()]; + let mut blocks = Blocks::from([Block::default(), Block::default()]); blocks[0].next = BlockIdx::new(1); blocks[0].visited = true; blocks[1].visited = true; @@ -7156,7 +7223,7 @@ mod tests { handler_block: BlockIdx::new(5), preserve_lasti: false, }; - let mut blocks = vec![Block::default(), Block::default()]; + let mut blocks = Blocks::from([Block::default(), Block::default()]); let mut stale = test_instr(Instruction::Nop, 41); stale.except_handler = Some(handler); test_block_push(&mut blocks[0], stale); @@ -7180,7 +7247,7 @@ mod tests { assert_eq!(info.target, BlockIdx::new(1)); - let mut blocks = vec![Block::default(), Block::default()]; + let mut blocks = Blocks::from([Block::default(), Block::default()]); test_block_push(&mut blocks[0], info); blocks[0].next = BlockIdx::new(1); @@ -7195,7 +7262,7 @@ mod tests { fn cfg_to_instruction_sequence_requires_target_for_target_opcodes() { let mut block = Block::default(); test_block_push(&mut block, test_jump(BlockIdx::NULL, 51)); - let mut blocks = vec![block]; + let mut blocks = Blocks::from([block]); let mut instr_sequence = instruction_sequence_new(); let _ = cfg_to_instruction_sequence(&mut blocks, &mut instr_sequence); @@ -7393,7 +7460,7 @@ mod tests { #[test] fn resolve_line_numbers_duplicates_exit_blocks_like_cpython() { let exit = BlockIdx::new(2); - let mut blocks = vec![Block::default(), Block::default(), Block::default()]; + let mut blocks = Blocks::from([Block::default(), Block::default(), Block::default()]); blocks[0].cpython_label = InstructionSequenceLabel::from_index(0); blocks[1].cpython_label = InstructionSequenceLabel::from_index(1); blocks[2].cpython_label = InstructionSequenceLabel::from_index(2); @@ -7412,15 +7479,12 @@ mod tests { let duplicate = blocks[0].instructions[0].target; assert_ne!(duplicate, exit); assert_eq!( - blocks[duplicate.idx()].cpython_label, + blocks[duplicate].cpython_label, InstructionSequenceLabel::from_index(3) ); - assert_eq!( - instruction_lineno(&blocks[duplicate.idx()].instructions[0]), - 10 - ); + assert_eq!(instruction_lineno(&blocks[duplicate].instructions[0]), 10); assert_eq!(blocks[1].instructions[0].target, exit); - assert_eq!(instruction_lineno(&blocks[exit.idx()].instructions[0]), 20); + assert_eq!(instruction_lineno(&blocks[exit].instructions[0]), 20); } #[test] @@ -7431,7 +7495,7 @@ mod tests { block.instructions[1].lineno_override = Some(NEXT_LOCATION_OVERRIDE); test_block_push(&mut block, test_instr(Instruction::ReturnValue, 30)); block.instructions[2].lineno_override = Some(NO_LOCATION_OVERRIDE); - let mut blocks = vec![block]; + let mut blocks = [block].into(); remove_unreachable(&mut blocks).expect("remove_unreachable succeeds"); propagate_line_numbers(&mut blocks); @@ -7452,7 +7516,7 @@ mod tests { #[test] fn propagate_line_numbers_updates_empty_jump_target_raw_slot_like_cpython() { - let mut blocks = vec![Block::default(), Block::default(), Block::default()]; + let mut blocks = Blocks::from([Block::default(), Block::default(), Block::default()]); blocks[0].next = BlockIdx::new(2); test_block_push(&mut blocks[0], test_cond_jump(BlockIdx::new(1), 10)); test_block_push(&mut blocks[1], test_instr(Instruction::Nop, 20)); @@ -7486,12 +7550,12 @@ mod tests { #[test] fn jump_threading_rechecks_new_jump_like_cpython() { - let mut blocks = vec![ + let mut blocks = Blocks::from([ Block::default(), Block::default(), Block::default(), Block::default(), - ]; + ]); for (i, block) in blocks.iter_mut().enumerate() { block.cpython_label = InstructionSequenceLabel::from_index(i as i32); }