Remove constants that are no longer referenced by LOAD_CONST instructions. remove_unused_consts
(&mut self)
| 1486 | /// Remove constants that are no longer referenced by LOAD_CONST instructions. |
| 1487 | /// remove_unused_consts |
| 1488 | fn remove_unused_consts(&mut self) { |
| 1489 | let nconsts = self.metadata.consts.len(); |
| 1490 | if nconsts == 0 { |
| 1491 | return; |
| 1492 | } |
| 1493 | |
| 1494 | // Mark used constants |
| 1495 | // The first constant (index 0) is always kept (may be docstring) |
| 1496 | let mut used = vec![false; nconsts]; |
| 1497 | used[0] = true; |
| 1498 | |
| 1499 | for block in &self.blocks { |
| 1500 | for instr in &block.instructions { |
| 1501 | if let Some(Instruction::LoadConst { .. }) = instr.instr.real() { |
| 1502 | let idx = u32::from(instr.arg) as usize; |
| 1503 | if idx < nconsts { |
| 1504 | used[idx] = true; |
| 1505 | } |
| 1506 | } |
| 1507 | } |
| 1508 | } |
| 1509 | |
| 1510 | // Check if any constants can be removed |
| 1511 | let n_used: usize = used.iter().filter(|&&u| u).count(); |
| 1512 | if n_used == nconsts { |
| 1513 | return; // Nothing to remove |
| 1514 | } |
| 1515 | |
| 1516 | // Build old_to_new index mapping |
| 1517 | let mut old_to_new = vec![0usize; nconsts]; |
| 1518 | let mut new_idx = 0usize; |
| 1519 | for (old_idx, &is_used) in used.iter().enumerate() { |
| 1520 | if is_used { |
| 1521 | old_to_new[old_idx] = new_idx; |
| 1522 | new_idx += 1; |
| 1523 | } |
| 1524 | } |
| 1525 | |
| 1526 | // Build new consts list |
| 1527 | let old_consts: Vec<_> = self.metadata.consts.iter().cloned().collect(); |
| 1528 | self.metadata.consts.clear(); |
| 1529 | for (old_idx, constant) in old_consts.into_iter().enumerate() { |
| 1530 | if used[old_idx] { |
| 1531 | self.metadata.consts.insert(constant); |
| 1532 | } |
| 1533 | } |
| 1534 | |
| 1535 | // Update LOAD_CONST instruction arguments |
| 1536 | for block in &mut self.blocks { |
| 1537 | for instr in &mut block.instructions { |
| 1538 | if let Some(Instruction::LoadConst { .. }) = instr.instr.real() { |
| 1539 | let old_idx = u32::from(instr.arg) as usize; |
| 1540 | if old_idx < nconsts { |
| 1541 | instr.arg = OpArg::new(old_to_new[old_idx] as u32); |
| 1542 | } |
| 1543 | } |
| 1544 | } |
| 1545 | } |