revm_bytecode/legacy/
jump_map.rs

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