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