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