foundry_evm_core/
ic.rs

1use crate::bytecode::InstIter;
2use alloy_primitives::map::rustc_hash::FxHashMap;
3use serde::Serialize;
4
5/// Maps from program counter to instruction counter.
6///
7/// Inverse of [`IcPcMap`].
8#[derive(Debug, Clone, Serialize)]
9#[serde(transparent)]
10pub struct PcIcMap {
11    pub inner: FxHashMap<u32, u32>,
12}
13
14impl PcIcMap {
15    /// Creates a new `PcIcMap` for the given code.
16    pub fn new(code: &[u8]) -> Self {
17        Self { inner: make_map::<true>(code) }
18    }
19
20    /// Returns the length of the map.
21    pub fn len(&self) -> usize {
22        self.inner.len()
23    }
24
25    /// Returns `true` if the map is empty.
26    pub fn is_empty(&self) -> bool {
27        self.inner.is_empty()
28    }
29
30    /// Returns the instruction counter for the given program counter.
31    pub fn get(&self, pc: u32) -> Option<u32> {
32        self.inner.get(&pc).copied()
33    }
34}
35
36/// Map from instruction counter to program counter.
37///
38/// Inverse of [`PcIcMap`].
39pub struct IcPcMap {
40    pub inner: FxHashMap<u32, u32>,
41}
42
43impl IcPcMap {
44    /// Creates a new `IcPcMap` for the given code.
45    pub fn new(code: &[u8]) -> Self {
46        Self { inner: make_map::<false>(code) }
47    }
48
49    /// Returns the length of the map.
50    pub fn len(&self) -> usize {
51        self.inner.len()
52    }
53
54    /// Returns `true` if the map is empty.
55    pub fn is_empty(&self) -> bool {
56        self.inner.is_empty()
57    }
58
59    /// Returns the program counter for the given instruction counter.
60    pub fn get(&self, ic: u32) -> Option<u32> {
61        self.inner.get(&ic).copied()
62    }
63}
64
65fn make_map<const PC_FIRST: bool>(code: &[u8]) -> FxHashMap<u32, u32> {
66    assert!(code.len() <= u32::MAX as usize, "bytecode is too big");
67    let mut map = FxHashMap::with_capacity_and_hasher(code.len(), Default::default());
68    for (ic, (pc, _)) in InstIter::new(code).with_pc().enumerate() {
69        if PC_FIRST {
70            map.insert(pc as u32, ic as u32);
71        } else {
72            map.insert(ic as u32, pc as u32);
73        }
74    }
75    map.shrink_to_fit();
76    map
77}