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, ptr};
5use primitives::B256;
6
7#[cfg(feature = "serde")]
8mod serde;
9
10#[derive(Debug)]
12pub struct ExtBytecode {
13 bytecode_hash: Option<B256>,
14 pub action: Option<InterpreterAction>,
17 base: Bytecode,
19 previous_pointer: Option<*const u8>,
21 instruction_pointer: *const u8,
23}
24
25impl Deref for ExtBytecode {
26 type Target = Bytecode;
27
28 fn deref(&self) -> &Self::Target {
29 &self.base
30 }
31}
32
33impl Default for ExtBytecode {
34 #[inline]
35 fn default() -> Self {
36 Self::new(Bytecode::default())
37 }
38}
39
40impl ExtBytecode {
41 #[inline]
43 pub fn new(base: Bytecode) -> Self {
44 let instruction_pointer = base.bytecode_ptr();
45 Self {
46 base,
47 instruction_pointer,
48 bytecode_hash: None,
49 action: None,
50 previous_pointer: None,
51 }
52 }
53
54 pub fn new_with_hash(base: Bytecode, hash: B256) -> Self {
56 let instruction_pointer = base.bytecode_ptr();
57 Self {
58 base,
59 instruction_pointer,
60 bytecode_hash: Some(hash),
61 action: None,
62 previous_pointer: None,
63 }
64 }
65
66 pub fn regenerate_hash(&mut self) -> B256 {
68 let hash = self.base.hash_slow();
69 self.bytecode_hash = Some(hash);
70 hash
71 }
72
73 pub fn hash(&mut self) -> Option<B256> {
75 self.bytecode_hash
76 }
77}
78
79impl LoopControl for ExtBytecode {
80 #[inline]
81 fn is_end(&self) -> bool {
82 self.instruction_pointer.is_null()
83 }
84
85 #[inline]
86 fn revert_to_previous_pointer(&mut self) {
87 if let Some(previous_pointer) = self.previous_pointer {
88 self.instruction_pointer = previous_pointer;
89 }
90 }
91
92 #[inline]
93 fn set_action(&mut self, action: InterpreterAction) {
94 self.action = Some(action);
95 self.previous_pointer = Some(core::mem::replace(
96 &mut self.instruction_pointer,
97 ptr::null(),
98 ));
99 }
100
101 #[inline]
102 fn action(&mut self) -> &mut Option<InterpreterAction> {
103 &mut self.action
104 }
105}
106
107impl Jumps for ExtBytecode {
108 #[inline]
109 fn relative_jump(&mut self, offset: isize) {
110 self.instruction_pointer = unsafe { self.instruction_pointer.offset(offset) };
111 }
112
113 #[inline]
114 fn absolute_jump(&mut self, offset: usize) {
115 self.instruction_pointer = unsafe { self.base.bytes_ref().as_ptr().add(offset) };
116 }
117
118 #[inline]
119 fn is_valid_legacy_jump(&mut self, offset: usize) -> bool {
120 self.base
121 .legacy_jump_table()
122 .expect("Panic if not legacy")
123 .is_valid(offset)
124 }
125
126 #[inline]
127 fn opcode(&self) -> u8 {
128 unsafe { *self.instruction_pointer }
130 }
131
132 #[inline]
133 fn pc(&self) -> usize {
134 unsafe {
137 self.instruction_pointer
138 .offset_from(self.base.bytes_ref().as_ptr()) as usize
139 }
140 }
141}
142
143impl Immediates for ExtBytecode {
144 #[inline]
145 fn read_u16(&self) -> u16 {
146 unsafe { read_u16(self.instruction_pointer) }
147 }
148
149 #[inline]
150 fn read_u8(&self) -> u8 {
151 unsafe { *self.instruction_pointer }
152 }
153
154 #[inline]
155 fn read_slice(&self, len: usize) -> &[u8] {
156 unsafe { core::slice::from_raw_parts(self.instruction_pointer, len) }
157 }
158
159 #[inline]
160 fn read_offset_u16(&self, offset: isize) -> u16 {
161 unsafe {
162 read_u16(
163 self.instruction_pointer
164 .offset(offset),
166 )
167 }
168 }
169}
170
171impl LegacyBytecode for ExtBytecode {
172 fn bytecode_len(&self) -> usize {
173 self.base.len()
174 }
175
176 fn bytecode_slice(&self) -> &[u8] {
177 self.base.original_byte_slice()
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184 use primitives::Bytes;
185
186 #[test]
187 fn test_with_hash_constructor() {
188 let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00][..]));
189 let hash = bytecode.hash_slow();
190 let ext_bytecode = ExtBytecode::new_with_hash(bytecode.clone(), hash);
191 assert_eq!(ext_bytecode.bytecode_hash, Some(hash));
192 }
193}