revm_bytecode/legacy/
analysis.rs

1use super::JumpTable;
2use crate::opcode;
3use bitvec::{bitvec, order::Lsb0, vec::BitVec};
4use std::sync::Arc;
5
6/// Analyze the bytecode to find the jumpdests. Used to create a jump table
7/// that is needed for [`crate::LegacyAnalyzedBytecode`].
8/// This function contains a hot loop and should be optimized as much as possible.
9///
10/// Undefined behavior if the bytecode does not end with a valid STOP opcode. Please check
11/// [`crate::LegacyAnalyzedBytecode::new`] for details on how the bytecode is validated.
12pub fn analyze_legacy(bytetecode: &[u8]) -> JumpTable {
13    let mut jumps: BitVec<u8> = bitvec![u8, Lsb0; 0; bytetecode.len()];
14
15    let range = bytetecode.as_ptr_range();
16    let start = range.start;
17    let mut iterator = start;
18    let end = range.end;
19    while iterator < end {
20        let opcode = unsafe { *iterator };
21        if opcode::JUMPDEST == opcode {
22            // SAFETY: Jumps are max length of the code
23            unsafe { jumps.set_unchecked(iterator.offset_from(start) as usize, true) }
24            iterator = unsafe { iterator.offset(1) };
25        } else {
26            let push_offset = opcode.wrapping_sub(opcode::PUSH1);
27            if push_offset < 32 {
28                // SAFETY: Iterator access range is checked in the while loop
29                iterator = unsafe { iterator.offset((push_offset + 2) as isize) };
30            } else {
31                // SAFETY: Iterator access range is checked in the while loop
32                iterator = unsafe { iterator.offset(1) };
33            }
34        }
35    }
36
37    JumpTable(Arc::new(jumps))
38}