revm_bytecode/legacy/
jump_map.rs

1use bitvec::vec::BitVec;
2use primitives::hex;
3use std::{fmt::Debug, sync::Arc};
4
5/// A table of valid `jump` destinations. Cheap to clone and memory efficient, one bit per opcode.
6#[derive(Clone, Default, PartialEq, Eq, Hash, Ord, PartialOrd)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct JumpTable(pub Arc<BitVec<u8>>);
9
10impl Debug for JumpTable {
11    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
12        f.debug_struct("JumpTable")
13            .field("map", &hex::encode(self.0.as_raw_slice()))
14            .finish()
15    }
16}
17
18impl JumpTable {
19    /// Gets the raw bytes of the jump map.
20    #[inline]
21    pub fn as_slice(&self) -> &[u8] {
22        self.0.as_raw_slice()
23    }
24
25    /// Constructs a jump map from raw bytes and length.
26    ///
27    /// Bit length represents number of used bits inside slice.
28    ///
29    /// # Panics
30    ///
31    /// Panics if number of bits in slice is less than bit_len.
32    #[inline]
33    pub fn from_slice(slice: &[u8], bit_len: usize) -> Self {
34        assert!(
35            slice.len() * 8 >= bit_len,
36            "slice bit length {} is less than bit_len {}",
37            slice.len() * 8,
38            bit_len
39        );
40        let mut bitvec = BitVec::from_slice(slice);
41        unsafe { bitvec.set_len(bit_len) };
42        Self(Arc::new(bitvec))
43    }
44
45    /// Checks if `pc` is a valid jump destination.
46    #[inline]
47    pub fn is_valid(&self, pc: usize) -> bool {
48        pc < self.0.len() && unsafe { *self.0.get_unchecked(pc) }
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    #[should_panic(expected = "slice bit length 8 is less than bit_len 10")]
58    fn test_jump_table_from_slice_panic() {
59        let slice = &[0x00];
60        let _ = JumpTable::from_slice(slice, 10);
61    }
62
63    #[test]
64    fn test_jump_table_from_slice() {
65        let slice = &[0x00];
66        let jumptable = JumpTable::from_slice(slice, 3);
67        assert_eq!(jumptable.0.len(), 3);
68    }
69}