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 let jt = self.base.legacy_jump_table();
144 unsafe { jt.unwrap_unchecked() }.is_valid(offset)
146 }
147
148 #[inline]
149 fn opcode(&self) -> u8 {
150 unsafe { *self.instruction_pointer }
152 }
153
154 #[inline]
155 fn pc(&self) -> usize {
156 unsafe {
159 self.instruction_pointer
160 .offset_from_unsigned(self.base.bytes_ref().as_ptr())
161 }
162 }
163}
164
165impl Immediates for ExtBytecode {
166 #[inline]
167 fn read_u16(&self) -> u16 {
168 unsafe { read_u16(self.instruction_pointer) }
169 }
170
171 #[inline]
172 fn read_u8(&self) -> u8 {
173 unsafe { *self.instruction_pointer }
174 }
175
176 #[inline]
177 fn read_slice(&self, len: usize) -> &[u8] {
178 unsafe { core::slice::from_raw_parts(self.instruction_pointer, len) }
179 }
180
181 #[inline]
182 fn read_offset_u16(&self, offset: isize) -> u16 {
183 unsafe {
184 read_u16(
185 self.instruction_pointer
186 .offset(offset),
188 )
189 }
190 }
191}
192
193impl LegacyBytecode for ExtBytecode {
194 fn bytecode_len(&self) -> usize {
195 self.base.len()
196 }
197
198 fn bytecode_slice(&self) -> &[u8] {
199 self.base.original_byte_slice()
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use primitives::Bytes;
207
208 #[test]
209 fn test_with_hash_constructor() {
210 let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00][..]));
211 let hash = bytecode.hash_slow();
212 let ext_bytecode = ExtBytecode::new_with_hash(bytecode.clone(), hash);
213 assert_eq!(ext_bytecode.bytecode_hash, Some(hash));
214 }
215}