revm_interpreter/interpreter/
ext_bytecode.rs

1use super::{EofCodeInfo, EofContainer, EofData, Immediates, Jumps, LegacyBytecode};
2use crate::{interpreter_types::LoopControl, InterpreterAction};
3use bytecode::{eof::CodeInfo, utils::read_u16, Bytecode};
4use core::{ops::Deref, ptr};
5use primitives::{Bytes, B256};
6
7#[cfg(feature = "serde")]
8mod serde;
9
10#[derive(Debug)]
11pub struct ExtBytecode {
12    base: Bytecode,
13    bytecode_hash: Option<B256>,
14    /// Actions that the EVM should do. It contains return value of the Interpreter or inputs for `CALL` or `CREATE` instructions.
15    /// For `RETURN` or `REVERT` instructions it contains the result of the instruction.
16    pub action: Option<InterpreterAction>,
17    previous_pointer: Option<*const u8>,
18    instruction_pointer: *const u8,
19}
20
21impl Deref for ExtBytecode {
22    type Target = Bytecode;
23
24    fn deref(&self) -> &Self::Target {
25        &self.base
26    }
27}
28
29impl ExtBytecode {
30    /// Create new extended bytecode and set the instruction pointer to the start of the bytecode.
31    pub fn new(base: Bytecode) -> Self {
32        let instruction_pointer = base.bytecode_ptr();
33        Self {
34            base,
35            instruction_pointer,
36            bytecode_hash: None,
37            action: None,
38            previous_pointer: None,
39        }
40    }
41
42    /// Creates new `ExtBytecode` with the given hash.
43    pub fn new_with_hash(base: Bytecode, hash: B256) -> Self {
44        let instruction_pointer = base.bytecode_ptr();
45        Self {
46            base,
47            instruction_pointer,
48            bytecode_hash: Some(hash),
49            action: None,
50            previous_pointer: None,
51        }
52    }
53
54    /// Regenerates the bytecode hash.
55    pub fn regenerate_hash(&mut self) -> B256 {
56        let hash = self.base.hash_slow();
57        self.bytecode_hash = Some(hash);
58        hash
59    }
60
61    /// Returns the bytecode hash.
62    pub fn hash(&mut self) -> Option<B256> {
63        self.bytecode_hash
64    }
65}
66
67impl LoopControl for ExtBytecode {
68    #[inline]
69    fn is_end(&self) -> bool {
70        self.instruction_pointer.is_null()
71    }
72
73    #[inline]
74    fn revert_to_previous_pointer(&mut self) {
75        if let Some(previous_pointer) = self.previous_pointer {
76            self.instruction_pointer = previous_pointer;
77        }
78    }
79
80    #[inline]
81    fn set_action(&mut self, action: InterpreterAction) {
82        self.action = Some(action);
83        self.previous_pointer = Some(core::mem::replace(
84            &mut self.instruction_pointer,
85            ptr::null(),
86        ));
87    }
88
89    #[inline]
90    fn action(&mut self) -> &mut Option<InterpreterAction> {
91        &mut self.action
92    }
93}
94
95impl Jumps for ExtBytecode {
96    #[inline]
97    fn relative_jump(&mut self, offset: isize) {
98        self.instruction_pointer = unsafe { self.instruction_pointer.offset(offset) };
99    }
100
101    #[inline]
102    fn absolute_jump(&mut self, offset: usize) {
103        self.instruction_pointer = unsafe { self.base.bytes_ref().as_ptr().add(offset) };
104    }
105
106    #[inline]
107    fn is_valid_legacy_jump(&mut self, offset: usize) -> bool {
108        self.base
109            .legacy_jump_table()
110            .expect("Panic if not legacy")
111            .is_valid(offset)
112    }
113
114    #[inline]
115    fn opcode(&self) -> u8 {
116        // SAFETY: `instruction_pointer` always point to bytecode.
117        unsafe { *self.instruction_pointer }
118    }
119
120    #[inline]
121    fn pc(&self) -> usize {
122        // SAFETY: `instruction_pointer` should be at an offset from the start of the bytes.
123        // In practice this is always true unless a caller modifies the `instruction_pointer` field manually.
124        unsafe {
125            self.instruction_pointer
126                .offset_from(self.base.bytes_ref().as_ptr()) as usize
127        }
128    }
129}
130
131impl Immediates for ExtBytecode {
132    #[inline]
133    fn read_u16(&self) -> u16 {
134        unsafe { read_u16(self.instruction_pointer) }
135    }
136
137    #[inline]
138    fn read_u8(&self) -> u8 {
139        unsafe { *self.instruction_pointer }
140    }
141
142    #[inline]
143    fn read_slice(&self, len: usize) -> &[u8] {
144        unsafe { core::slice::from_raw_parts(self.instruction_pointer, len) }
145    }
146
147    #[inline]
148    fn read_offset_u16(&self, offset: isize) -> u16 {
149        unsafe {
150            read_u16(
151                self.instruction_pointer
152                    // Offset for max_index that is one byte
153                    .offset(offset),
154            )
155        }
156    }
157}
158
159impl EofCodeInfo for ExtBytecode {
160    fn code_info(&self, idx: usize) -> Option<&CodeInfo> {
161        self.base.eof().and_then(|eof| eof.body.code_info.get(idx))
162    }
163
164    fn code_section_pc(&self, idx: usize) -> Option<usize> {
165        self.base
166            .eof()
167            .and_then(|eof| eof.body.eof_code_section_start(idx))
168    }
169}
170
171impl EofData for ExtBytecode {
172    fn data(&self) -> &[u8] {
173        self.base.eof().expect("eof").data()
174    }
175
176    fn data_slice(&self, offset: usize, len: usize) -> &[u8] {
177        self.base.eof().expect("eof").data_slice(offset, len)
178    }
179
180    fn data_size(&self) -> usize {
181        self.base.eof().expect("eof").header.data_size as usize
182    }
183}
184
185impl EofContainer for ExtBytecode {
186    fn eof_container(&self, index: usize) -> Option<&Bytes> {
187        self.base
188            .eof()
189            .and_then(|eof| eof.body.container_section.get(index))
190    }
191}
192
193impl LegacyBytecode for ExtBytecode {
194    fn bytecode_len(&self) -> usize {
195        // Inform the optimizer that the bytecode cannot be EOF to remove a bounds check.
196        assume!(!self.base.is_eof());
197        self.base.len()
198    }
199
200    fn bytecode_slice(&self) -> &[u8] {
201        // Inform the optimizer that the bytecode cannot be EOF to remove a bounds check.
202        assume!(!self.base.is_eof());
203        self.base.original_byte_slice()
204    }
205}
206
207#[cfg(test)]
208mod tests {
209    use super::*;
210    use primitives::Bytes;
211
212    #[test]
213    fn test_with_hash_constructor() {
214        let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00][..]));
215        let hash = bytecode.hash_slow();
216        let ext_bytecode = ExtBytecode::new_with_hash(bytecode.clone(), hash);
217        assert_eq!(ext_bytecode.bytecode_hash, Some(hash));
218    }
219}