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]
75 pub fn calculate_hash(&mut self) -> B256 {
76 let hash = self.base.hash_slow();
77 self.bytecode_hash = Some(hash);
78 hash
79 }
80
81 #[inline]
83 pub fn hash(&mut self) -> Option<B256> {
84 self.bytecode_hash
85 }
86
87 #[inline]
89 pub fn get_or_calculate_hash(&mut self) -> B256 {
90 *self.bytecode_hash.get_or_insert_with(
91 #[cold]
92 || self.base.hash_slow(),
93 )
94 }
95}
96
97impl LoopControl for ExtBytecode {
98 #[inline]
99 fn is_not_end(&self) -> bool {
100 self.continue_execution
101 }
102
103 #[inline]
104 fn reset_action(&mut self) {
105 self.continue_execution = true;
106 }
107
108 #[inline]
109 fn set_action(&mut self, action: InterpreterAction) {
110 debug_assert_eq!(
111 !self.continue_execution,
112 self.action.is_some(),
113 "has_set_action out of sync"
114 );
115 debug_assert!(
116 self.continue_execution,
117 "action already set;\nold: {:#?}\nnew: {:#?}",
118 self.action, action,
119 );
120 self.continue_execution = false;
121 self.action = Some(action);
122 }
123
124 #[inline]
125 fn action(&mut self) -> &mut Option<InterpreterAction> {
126 &mut self.action
127 }
128}
129
130impl Jumps for ExtBytecode {
131 #[inline]
132 fn relative_jump(&mut self, offset: isize) {
133 self.instruction_pointer = unsafe { self.instruction_pointer.offset(offset) };
134 }
135
136 #[inline]
137 fn absolute_jump(&mut self, offset: usize) {
138 self.instruction_pointer = unsafe { self.base.bytes_ref().as_ptr().add(offset) };
139 }
140
141 #[inline]
142 fn is_valid_legacy_jump(&mut self, offset: usize) -> bool {
143 self.base
144 .legacy_jump_table()
145 .expect("Panic if not legacy")
146 .is_valid(offset)
147 }
148
149 #[inline]
150 fn opcode(&self) -> u8 {
151 unsafe { *self.instruction_pointer }
153 }
154
155 #[inline]
156 fn pc(&self) -> usize {
157 unsafe {
160 self.instruction_pointer
161 .offset_from_unsigned(self.base.bytes_ref().as_ptr())
162 }
163 }
164}
165
166impl Immediates for ExtBytecode {
167 #[inline]
168 fn read_u16(&self) -> u16 {
169 unsafe { read_u16(self.instruction_pointer) }
170 }
171
172 #[inline]
173 fn read_u8(&self) -> u8 {
174 unsafe { *self.instruction_pointer }
175 }
176
177 #[inline]
178 fn read_slice(&self, len: usize) -> &[u8] {
179 unsafe { core::slice::from_raw_parts(self.instruction_pointer, len) }
180 }
181
182 #[inline]
183 fn read_offset_u16(&self, offset: isize) -> u16 {
184 unsafe {
185 read_u16(
186 self.instruction_pointer
187 .offset(offset),
189 )
190 }
191 }
192}
193
194impl LegacyBytecode for ExtBytecode {
195 fn bytecode_len(&self) -> usize {
196 self.base.len()
197 }
198
199 fn bytecode_slice(&self) -> &[u8] {
200 self.base.original_byte_slice()
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207 use primitives::Bytes;
208
209 #[test]
210 fn test_with_hash_constructor() {
211 let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00][..]));
212 let hash = bytecode.hash_slow();
213 let ext_bytecode = ExtBytecode::new_with_hash(bytecode.clone(), hash);
214 assert_eq!(ext_bytecode.bytecode_hash, Some(hash));
215 }
216}