revm_interpreter/interpreter/
ext_bytecode.rs1use super::{EofCodeInfo, EofContainer, EofData, Immediates, Jumps, LegacyBytecode};
2use crate::{interpreter_types::LoopControl, InterpreterAction};
3use bytecode::{eof::CodeInfo, utils::read_u16, Bytecode};
4use core::{ops::Deref, ptr};
5use primitives::{Bytes, B256};
6
7#[cfg(feature = "serde")]
8mod serde;
9
10#[derive(Debug)]
11pub struct ExtBytecode {
12 base: Bytecode,
13 bytecode_hash: Option<B256>,
14 pub action: Option<InterpreterAction>,
17 previous_pointer: Option<*const u8>,
18 instruction_pointer: *const u8,
19}
20
21impl Deref for ExtBytecode {
22 type Target = Bytecode;
23
24 fn deref(&self) -> &Self::Target {
25 &self.base
26 }
27}
28
29impl ExtBytecode {
30 pub fn new(base: Bytecode) -> Self {
32 let instruction_pointer = base.bytecode_ptr();
33 Self {
34 base,
35 instruction_pointer,
36 bytecode_hash: None,
37 action: None,
38 previous_pointer: None,
39 }
40 }
41
42 pub fn new_with_hash(base: Bytecode, hash: B256) -> Self {
44 let instruction_pointer = base.bytecode_ptr();
45 Self {
46 base,
47 instruction_pointer,
48 bytecode_hash: Some(hash),
49 action: None,
50 previous_pointer: None,
51 }
52 }
53
54 pub fn regenerate_hash(&mut self) -> B256 {
56 let hash = self.base.hash_slow();
57 self.bytecode_hash = Some(hash);
58 hash
59 }
60
61 pub fn hash(&mut self) -> Option<B256> {
63 self.bytecode_hash
64 }
65}
66
67impl LoopControl for ExtBytecode {
68 #[inline]
69 fn is_end(&self) -> bool {
70 self.instruction_pointer.is_null()
71 }
72
73 #[inline]
74 fn revert_to_previous_pointer(&mut self) {
75 if let Some(previous_pointer) = self.previous_pointer {
76 self.instruction_pointer = previous_pointer;
77 }
78 }
79
80 #[inline]
81 fn set_action(&mut self, action: InterpreterAction) {
82 self.action = Some(action);
83 self.previous_pointer = Some(core::mem::replace(
84 &mut self.instruction_pointer,
85 ptr::null(),
86 ));
87 }
88
89 #[inline]
90 fn action(&mut self) -> &mut Option<InterpreterAction> {
91 &mut self.action
92 }
93}
94
95impl Jumps for ExtBytecode {
96 #[inline]
97 fn relative_jump(&mut self, offset: isize) {
98 self.instruction_pointer = unsafe { self.instruction_pointer.offset(offset) };
99 }
100
101 #[inline]
102 fn absolute_jump(&mut self, offset: usize) {
103 self.instruction_pointer = unsafe { self.base.bytes_ref().as_ptr().add(offset) };
104 }
105
106 #[inline]
107 fn is_valid_legacy_jump(&mut self, offset: usize) -> bool {
108 self.base
109 .legacy_jump_table()
110 .expect("Panic if not legacy")
111 .is_valid(offset)
112 }
113
114 #[inline]
115 fn opcode(&self) -> u8 {
116 unsafe { *self.instruction_pointer }
118 }
119
120 #[inline]
121 fn pc(&self) -> usize {
122 unsafe {
125 self.instruction_pointer
126 .offset_from(self.base.bytes_ref().as_ptr()) as usize
127 }
128 }
129}
130
131impl Immediates for ExtBytecode {
132 #[inline]
133 fn read_u16(&self) -> u16 {
134 unsafe { read_u16(self.instruction_pointer) }
135 }
136
137 #[inline]
138 fn read_u8(&self) -> u8 {
139 unsafe { *self.instruction_pointer }
140 }
141
142 #[inline]
143 fn read_slice(&self, len: usize) -> &[u8] {
144 unsafe { core::slice::from_raw_parts(self.instruction_pointer, len) }
145 }
146
147 #[inline]
148 fn read_offset_u16(&self, offset: isize) -> u16 {
149 unsafe {
150 read_u16(
151 self.instruction_pointer
152 .offset(offset),
154 )
155 }
156 }
157}
158
159impl EofCodeInfo for ExtBytecode {
160 fn code_info(&self, idx: usize) -> Option<&CodeInfo> {
161 self.base.eof().and_then(|eof| eof.body.code_info.get(idx))
162 }
163
164 fn code_section_pc(&self, idx: usize) -> Option<usize> {
165 self.base
166 .eof()
167 .and_then(|eof| eof.body.eof_code_section_start(idx))
168 }
169}
170
171impl EofData for ExtBytecode {
172 fn data(&self) -> &[u8] {
173 self.base.eof().expect("eof").data()
174 }
175
176 fn data_slice(&self, offset: usize, len: usize) -> &[u8] {
177 self.base.eof().expect("eof").data_slice(offset, len)
178 }
179
180 fn data_size(&self) -> usize {
181 self.base.eof().expect("eof").header.data_size as usize
182 }
183}
184
185impl EofContainer for ExtBytecode {
186 fn eof_container(&self, index: usize) -> Option<&Bytes> {
187 self.base
188 .eof()
189 .and_then(|eof| eof.body.container_section.get(index))
190 }
191}
192
193impl LegacyBytecode for ExtBytecode {
194 fn bytecode_len(&self) -> usize {
195 assume!(!self.base.is_eof());
197 self.base.len()
198 }
199
200 fn bytecode_slice(&self) -> &[u8] {
201 assume!(!self.base.is_eof());
203 self.base.original_byte_slice()
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210 use primitives::Bytes;
211
212 #[test]
213 fn test_with_hash_constructor() {
214 let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00][..]));
215 let hash = bytecode.hash_slow();
216 let ext_bytecode = ExtBytecode::new_with_hash(bytecode.clone(), hash);
217 assert_eq!(ext_bytecode.bytecode_hash, Some(hash));
218 }
219}