revm_interpreter/interpreter/
shared_memory.rs
1use core::{cmp::min, fmt, ops::Range};
2use revm_primitives::{B256, U256};
3use std::vec::Vec;
4
5#[derive(Clone, PartialEq, Eq, Hash)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct SharedMemory {
12 buffer: Vec<u8>,
14 checkpoints: Vec<usize>,
17 last_checkpoint: usize,
19 #[cfg(feature = "memory_limit")]
21 memory_limit: u64,
22}
23
24pub const EMPTY_SHARED_MEMORY: SharedMemory = SharedMemory {
28 buffer: Vec::new(),
29 checkpoints: Vec::new(),
30 last_checkpoint: 0,
31 #[cfg(feature = "memory_limit")]
32 memory_limit: u64::MAX,
33};
34
35impl fmt::Debug for SharedMemory {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 f.debug_struct("SharedMemory")
38 .field("current_len", &self.len())
39 .field(
40 "context_memory",
41 &crate::primitives::hex::encode(self.context_memory()),
42 )
43 .finish_non_exhaustive()
44 }
45}
46
47impl Default for SharedMemory {
48 #[inline]
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54impl SharedMemory {
55 #[inline]
59 pub fn new() -> Self {
60 Self::with_capacity(4 * 1024) }
62
63 #[inline]
65 pub fn with_capacity(capacity: usize) -> Self {
66 Self {
67 buffer: Vec::with_capacity(capacity),
68 checkpoints: Vec::with_capacity(32),
69 last_checkpoint: 0,
70 #[cfg(feature = "memory_limit")]
71 memory_limit: u64::MAX,
72 }
73 }
74
75 #[cfg(feature = "memory_limit")]
80 #[inline]
81 pub fn new_with_memory_limit(memory_limit: u64) -> Self {
82 Self {
83 memory_limit,
84 ..Self::new()
85 }
86 }
87
88 #[cfg(feature = "memory_limit")]
91 #[inline]
92 pub fn limit_reached(&self, new_size: usize) -> bool {
93 self.last_checkpoint.saturating_add(new_size) as u64 > self.memory_limit
94 }
95
96 #[inline]
98 pub fn new_context(&mut self) {
99 let new_checkpoint = self.buffer.len();
100 self.checkpoints.push(new_checkpoint);
101 self.last_checkpoint = new_checkpoint;
102 }
103
104 #[inline]
106 pub fn free_context(&mut self) {
107 if let Some(old_checkpoint) = self.checkpoints.pop() {
108 self.last_checkpoint = self.checkpoints.last().cloned().unwrap_or_default();
109 unsafe { self.buffer.set_len(old_checkpoint) };
111 }
112 }
113
114 #[inline]
116 pub fn len(&self) -> usize {
117 self.buffer.len() - self.last_checkpoint
118 }
119
120 #[inline]
122 pub fn is_empty(&self) -> bool {
123 self.len() == 0
124 }
125
126 #[inline]
128 pub fn current_expansion_cost(&self) -> u64 {
129 crate::gas::memory_gas_for_len(self.len())
130 }
131
132 #[inline]
134 pub fn resize(&mut self, new_size: usize) {
135 self.buffer.resize(self.last_checkpoint + new_size, 0);
136 }
137
138 #[inline]
144 #[cfg_attr(debug_assertions, track_caller)]
145 pub fn slice(&self, offset: usize, size: usize) -> &[u8] {
146 self.slice_range(offset..offset + size)
147 }
148
149 #[inline]
155 #[cfg_attr(debug_assertions, track_caller)]
156 pub fn slice_range(&self, range @ Range { start, end }: Range<usize>) -> &[u8] {
157 match self.context_memory().get(range) {
158 Some(slice) => slice,
159 None => debug_unreachable!("slice OOB: {start}..{end}; len: {}", self.len()),
160 }
161 }
162
163 #[inline]
169 #[cfg_attr(debug_assertions, track_caller)]
170 pub fn slice_mut(&mut self, offset: usize, size: usize) -> &mut [u8] {
171 let end = offset + size;
172 match self.context_memory_mut().get_mut(offset..end) {
173 Some(slice) => slice,
174 None => debug_unreachable!("slice OOB: {offset}..{end}"),
175 }
176 }
177
178 #[inline]
184 pub fn get_byte(&self, offset: usize) -> u8 {
185 self.slice(offset, 1)[0]
186 }
187
188 #[inline]
194 pub fn get_word(&self, offset: usize) -> B256 {
195 self.slice(offset, 32).try_into().unwrap()
196 }
197
198 #[inline]
204 pub fn get_u256(&self, offset: usize) -> U256 {
205 self.get_word(offset).into()
206 }
207
208 #[inline]
214 #[cfg_attr(debug_assertions, track_caller)]
215 pub fn set_byte(&mut self, offset: usize, byte: u8) {
216 self.set(offset, &[byte]);
217 }
218
219 #[inline]
225 #[cfg_attr(debug_assertions, track_caller)]
226 pub fn set_word(&mut self, offset: usize, value: &B256) {
227 self.set(offset, &value[..]);
228 }
229
230 #[inline]
236 #[cfg_attr(debug_assertions, track_caller)]
237 pub fn set_u256(&mut self, offset: usize, value: U256) {
238 self.set(offset, &value.to_be_bytes::<32>());
239 }
240
241 #[inline]
247 #[cfg_attr(debug_assertions, track_caller)]
248 pub fn set(&mut self, offset: usize, value: &[u8]) {
249 if !value.is_empty() {
250 self.slice_mut(offset, value.len()).copy_from_slice(value);
251 }
252 }
253
254 #[inline]
261 #[cfg_attr(debug_assertions, track_caller)]
262 pub fn set_data(&mut self, memory_offset: usize, data_offset: usize, len: usize, data: &[u8]) {
263 if data_offset >= data.len() {
264 self.slice_mut(memory_offset, len).fill(0);
266 return;
267 }
268 let data_end = min(data_offset + len, data.len());
269 let data_len = data_end - data_offset;
270 debug_assert!(data_offset < data.len() && data_end <= data.len());
271 let data = unsafe { data.get_unchecked(data_offset..data_end) };
272 self.slice_mut(memory_offset, data_len)
273 .copy_from_slice(data);
274
275 self.slice_mut(memory_offset + data_len, len - data_len)
278 .fill(0);
279 }
280
281 #[inline]
287 #[cfg_attr(debug_assertions, track_caller)]
288 pub fn copy(&mut self, dst: usize, src: usize, len: usize) {
289 self.context_memory_mut().copy_within(src..src + len, dst);
290 }
291
292 #[inline]
294 pub fn context_memory(&self) -> &[u8] {
295 unsafe {
297 self.buffer
298 .get_unchecked(self.last_checkpoint..self.buffer.len())
299 }
300 }
301
302 #[inline]
304 pub fn context_memory_mut(&mut self) -> &mut [u8] {
305 let buf_len = self.buffer.len();
306 unsafe { self.buffer.get_unchecked_mut(self.last_checkpoint..buf_len) }
308 }
309}
310
311#[inline]
314pub const fn num_words(len: u64) -> u64 {
315 len.saturating_add(31) / 32
316}
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321
322 #[test]
323 fn test_num_words() {
324 assert_eq!(num_words(0), 0);
325 assert_eq!(num_words(1), 1);
326 assert_eq!(num_words(31), 1);
327 assert_eq!(num_words(32), 1);
328 assert_eq!(num_words(33), 2);
329 assert_eq!(num_words(63), 2);
330 assert_eq!(num_words(64), 2);
331 assert_eq!(num_words(65), 3);
332 assert_eq!(num_words(u64::MAX), u64::MAX / 32);
333 }
334
335 #[test]
336 fn new_free_context() {
337 let mut shared_memory = SharedMemory::new();
338 shared_memory.new_context();
339
340 assert_eq!(shared_memory.buffer.len(), 0);
341 assert_eq!(shared_memory.checkpoints.len(), 1);
342 assert_eq!(shared_memory.last_checkpoint, 0);
343
344 unsafe { shared_memory.buffer.set_len(32) };
345 assert_eq!(shared_memory.len(), 32);
346 shared_memory.new_context();
347
348 assert_eq!(shared_memory.buffer.len(), 32);
349 assert_eq!(shared_memory.checkpoints.len(), 2);
350 assert_eq!(shared_memory.last_checkpoint, 32);
351 assert_eq!(shared_memory.len(), 0);
352
353 unsafe { shared_memory.buffer.set_len(96) };
354 assert_eq!(shared_memory.len(), 64);
355 shared_memory.new_context();
356
357 assert_eq!(shared_memory.buffer.len(), 96);
358 assert_eq!(shared_memory.checkpoints.len(), 3);
359 assert_eq!(shared_memory.last_checkpoint, 96);
360 assert_eq!(shared_memory.len(), 0);
361
362 shared_memory.free_context();
364 assert_eq!(shared_memory.buffer.len(), 96);
365 assert_eq!(shared_memory.checkpoints.len(), 2);
366 assert_eq!(shared_memory.last_checkpoint, 32);
367 assert_eq!(shared_memory.len(), 64);
368
369 shared_memory.free_context();
370 assert_eq!(shared_memory.buffer.len(), 32);
371 assert_eq!(shared_memory.checkpoints.len(), 1);
372 assert_eq!(shared_memory.last_checkpoint, 0);
373 assert_eq!(shared_memory.len(), 32);
374
375 shared_memory.free_context();
376 assert_eq!(shared_memory.buffer.len(), 0);
377 assert_eq!(shared_memory.checkpoints.len(), 0);
378 assert_eq!(shared_memory.last_checkpoint, 0);
379 assert_eq!(shared_memory.len(), 0);
380 }
381
382 #[test]
383 fn resize() {
384 let mut shared_memory = SharedMemory::new();
385 shared_memory.new_context();
386
387 shared_memory.resize(32);
388 assert_eq!(shared_memory.buffer.len(), 32);
389 assert_eq!(shared_memory.len(), 32);
390 assert_eq!(shared_memory.buffer.get(0..32), Some(&[0_u8; 32] as &[u8]));
391
392 shared_memory.new_context();
393 shared_memory.resize(96);
394 assert_eq!(shared_memory.buffer.len(), 128);
395 assert_eq!(shared_memory.len(), 96);
396 assert_eq!(
397 shared_memory.buffer.get(32..128),
398 Some(&[0_u8; 96] as &[u8])
399 );
400
401 shared_memory.free_context();
402 shared_memory.resize(64);
403 assert_eq!(shared_memory.buffer.len(), 64);
404 assert_eq!(shared_memory.len(), 64);
405 assert_eq!(shared_memory.buffer.get(0..64), Some(&[0_u8; 64] as &[u8]));
406 }
407}