revm_interpreter/interpreter/
ext_bytecode.rs1use super::{Immediates, Jumps, LegacyBytecode};
2use crate::{interpreter_types::LoopControl, InterpreterAction};
3use bytecode::{utils::read_u16, Bytecode};
4use core::ops::Deref;
5use primitives::B256;
6
7#[cfg(feature = "serde")]
8mod serde;
9
10#[derive(Debug)]
12pub struct ExtBytecode {
13 instruction_pointer: *const u8,
15 continue_execution: bool,
17 bytecode_hash: Option<B256>,
21 pub action: Option<InterpreterAction>,
24 base: Bytecode,
26}
27
28impl Deref for ExtBytecode {
29 type Target = Bytecode;
30
31 fn deref(&self) -> &Self::Target {
32 &self.base
33 }
34}
35
36impl Default for ExtBytecode {
37 #[inline]
38 fn default() -> Self {
39 Self::new(Bytecode::default())
40 }
41}
42
43impl ExtBytecode {
44 #[inline]
48 pub fn new(base: Bytecode) -> Self {
49 Self::new_with_optional_hash(base, None)
50 }
51
52 #[inline]
54 pub fn new_with_hash(base: Bytecode, hash: B256) -> Self {
55 Self::new_with_optional_hash(base, Some(hash))
56 }
57
58 #[inline]
60 pub fn new_with_optional_hash(base: Bytecode, hash: Option<B256>) -> Self {
61 let instruction_pointer = base.bytecode_ptr();
62 Self {
63 base,
64 instruction_pointer,
65 bytecode_hash: hash,
66 action: None,
67 continue_execution: true,
68 }
69 }
70
71 #[inline]
73 #[deprecated(note = "use `get_or_calculate_hash` or `calculate_hash` instead")]
74 #[doc(hidden)]
75 pub fn regenerate_hash(&mut self) -> B256 {
76 self.calculate_hash()
77 }
78
79 #[inline]
83 pub fn calculate_hash(&mut self) -> B256 {
84 let hash = self.base.hash_slow();
85 self.bytecode_hash = Some(hash);
86 hash
87 }
88
89 #[inline]
91 pub fn hash(&mut self) -> Option<B256> {
92 self.bytecode_hash
93 }
94
95 #[inline]
97 pub fn get_or_calculate_hash(&mut self) -> B256 {
98 *self.bytecode_hash.get_or_insert_with(
99 #[cold]
100 || self.base.hash_slow(),
101 )
102 }
103}
104
105impl LoopControl for ExtBytecode {
106 #[inline]
107 fn is_not_end(&self) -> bool {
108 self.continue_execution
109 }
110
111 #[inline]
112 fn reset_action(&mut self) {
113 self.continue_execution = true;
114 }
115
116 #[inline]
117 fn set_action(&mut self, action: InterpreterAction) {
118 debug_assert_eq!(
119 !self.continue_execution,
120 self.action.is_some(),
121 "has_set_action out of sync"
122 );
123 debug_assert!(
124 self.continue_execution,
125 "action already set;\nold: {:#?}\nnew: {:#?}",
126 self.action, action,
127 );
128 self.continue_execution = false;
129 self.action = Some(action);
130 }
131
132 #[inline]
133 fn action(&mut self) -> &mut Option<InterpreterAction> {
134 &mut self.action
135 }
136}
137
138impl Jumps for ExtBytecode {
139 #[inline]
140 fn relative_jump(&mut self, offset: isize) {
141 self.instruction_pointer = unsafe { self.instruction_pointer.offset(offset) };
142 }
143
144 #[inline]
145 fn absolute_jump(&mut self, offset: usize) {
146 self.instruction_pointer = unsafe { self.base.bytes_ref().as_ptr().add(offset) };
147 }
148
149 #[inline]
150 fn is_valid_legacy_jump(&mut self, offset: usize) -> bool {
151 self.base
152 .legacy_jump_table()
153 .expect("Panic if not legacy")
154 .is_valid(offset)
155 }
156
157 #[inline]
158 fn opcode(&self) -> u8 {
159 unsafe { *self.instruction_pointer }
161 }
162
163 #[inline]
164 fn pc(&self) -> usize {
165 unsafe {
168 self.instruction_pointer
169 .offset_from(self.base.bytes_ref().as_ptr()) as usize
170 }
171 }
172}
173
174impl Immediates for ExtBytecode {
175 #[inline]
176 fn read_u16(&self) -> u16 {
177 unsafe { read_u16(self.instruction_pointer) }
178 }
179
180 #[inline]
181 fn read_u8(&self) -> u8 {
182 unsafe { *self.instruction_pointer }
183 }
184
185 #[inline]
186 fn read_slice(&self, len: usize) -> &[u8] {
187 unsafe { core::slice::from_raw_parts(self.instruction_pointer, len) }
188 }
189
190 #[inline]
191 fn read_offset_u16(&self, offset: isize) -> u16 {
192 unsafe {
193 read_u16(
194 self.instruction_pointer
195 .offset(offset),
197 )
198 }
199 }
200}
201
202impl LegacyBytecode for ExtBytecode {
203 fn bytecode_len(&self) -> usize {
204 self.base.len()
205 }
206
207 fn bytecode_slice(&self) -> &[u8] {
208 self.base.original_byte_slice()
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215 use primitives::Bytes;
216
217 #[test]
218 fn test_with_hash_constructor() {
219 let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00][..]));
220 let hash = bytecode.hash_slow();
221 let ext_bytecode = ExtBytecode::new_with_hash(bytecode.clone(), hash);
222 assert_eq!(ext_bytecode.bytecode_hash, Some(hash));
223 }
224}