Skip to content

Commit 572e15b

Browse files
author
Lorenzo Feroleto
committed
chore(SharedMemory): refactoring
1 parent c7945eb commit 572e15b

File tree

4 files changed

+58
-69
lines changed

4 files changed

+58
-69
lines changed

crates/interpreter/src/instructions/macros.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,10 @@ macro_rules! gas_or_fail {
5252

5353
macro_rules! shared_memory_resize {
5454
($interp:expr, $offset:expr, $len:expr) => {
55-
let len: usize = $len;
56-
let offset: usize = $offset;
5755
if let Some(new_size) =
58-
crate::interpreter::shared_memory::next_multiple_of_32(offset.saturating_add(len))
56+
crate::interpreter::shared_memory::next_multiple_of_32($offset.saturating_add($len))
5957
{
60-
if new_size as u64 > $interp.shared_memory.limit {
58+
if new_size > $interp.shared_memory.limit {
6159
$interp.instruction_result = InstructionResult::MemoryLimitOOG;
6260
return;
6361
}

crates/interpreter/src/interpreter.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,7 @@ impl<'a> Interpreter<'a> {
147147
/// Returns a copy of the interpreter's return value, if any.
148148
#[inline]
149149
pub fn return_value(&mut self) -> Bytes {
150-
let return_data = self.return_value_slice().to_vec().into();
151-
self.shared_memory.free_context_memory();
152-
return_data
150+
self.return_value_slice().to_vec().into()
153151
}
154152

155153
/// Returns a reference to the interpreter's return value, if any.

crates/interpreter/src/interpreter/shared_memory.rs

+50-61
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use revm_primitives::U256;
22

33
use crate::alloc::vec;
4-
use crate::alloc::vec::Vec;
4+
use crate::alloc::{boxed::Box, slice, vec::Vec};
55
use core::{
66
cmp::min,
77
fmt,
@@ -14,119 +14,111 @@ use core::{
1414
/// the `new` static method to ensure memory safety.
1515
pub struct SharedMemory {
1616
/// Shared buffer
17-
data: Vec<u8>,
17+
data: Box<[u8]>,
1818
/// Memory checkpoints for each depth
1919
checkpoints: Vec<usize>,
2020
/// Raw pointer used for the portion of memory used
2121
/// by the current context
22-
current_slice: *mut [u8],
22+
current_ptr: *mut u8,
2323
/// How much memory has been used in the current context
2424
current_len: usize,
2525
/// Amount of memory left for assignment
26-
pub limit: u64,
26+
pub limit: usize,
2727
}
2828

2929
impl fmt::Debug for SharedMemory {
3030
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3131
f.debug_struct("SharedMemory")
3232
.field(
3333
"current_slice",
34-
&crate::primitives::hex::encode(self.get_current_slice()),
34+
&crate::primitives::hex::encode(self.current_slice()),
3535
)
3636
.finish()
3737
}
3838
}
3939

4040
impl SharedMemory {
41+
/// Calculates memory allocation upper bound using
42+
/// https://2π.com/22/eth-max-mem
43+
#[inline]
44+
pub fn calculate_upper_bound(gas_limit: u64) -> u64 {
45+
4096 * sqrt(2 * gas_limit)
46+
}
47+
4148
/// Allocate memory to be shared between calls.
4249
/// Memory size is estimated using https://2π.com/22/eth-max-mem
4350
/// which depends on transaction [gas_limit].
4451
/// Maximum allocation size is 2^32 - 1 bytes;
4552
pub fn new(gas_limit: u64) -> Self {
46-
let size = min(
47-
SharedMemory::calculate_upper_bound(gas_limit) as usize,
48-
2usize.pow(32) - 1,
49-
);
50-
51-
let mut data = vec![0; size];
52-
let current_slice: *mut [u8] = &mut data[..];
53-
SharedMemory {
54-
data,
55-
checkpoints: Vec::with_capacity(1024),
56-
current_slice,
57-
current_len: 0,
58-
limit: size as u64,
59-
}
53+
Self::new_with_memory_limit(gas_limit, (u32::MAX - 1) as u64)
6054
}
6155

6256
/// Allocate memory to be shared between calls.
6357
/// Memory size is estimated using https://2π.com/22/eth-max-mem
6458
/// which depends on transaction [gas_limit].
6559
/// Uses [memory_limit] as maximum allocation size
6660
pub fn new_with_memory_limit(gas_limit: u64, memory_limit: u64) -> Self {
67-
let size = min(
68-
SharedMemory::calculate_upper_bound(gas_limit) as usize,
61+
let limit = min(
62+
Self::calculate_upper_bound(gas_limit) as usize,
6963
memory_limit as usize,
7064
);
7165

72-
let mut data = vec![0; size];
73-
let current_slice: *mut [u8] = &mut data[..];
74-
SharedMemory {
66+
let mut data = vec![0; limit].into_boxed_slice();
67+
let current_slice = data.as_mut_ptr();
68+
Self {
7569
data,
76-
checkpoints: Vec::with_capacity(1024),
77-
current_slice,
70+
checkpoints: Vec::with_capacity(32),
71+
current_ptr: current_slice,
7872
current_len: 0,
79-
limit: size as u64,
73+
limit,
8074
}
8175
}
8276

8377
/// Prepares the shared memory for a new context
8478
pub fn new_context_memory(&mut self) {
85-
let base_offset = self.checkpoints.last().unwrap_or(&0);
79+
let base_offset = self.last_checkpoint();
8680
let new_checkpoint = base_offset + self.current_len;
8781

8882
self.checkpoints.push(new_checkpoint);
8983

90-
self.current_slice = &mut self.data[new_checkpoint..];
84+
self.current_ptr = self.data[new_checkpoint..].as_mut_ptr();
9185
self.current_len = 0;
9286
}
9387

9488
/// Prepares the shared memory for returning to the previous context
9589
pub fn free_context_memory(&mut self) {
9690
if let Some(old_checkpoint) = self.checkpoints.pop() {
97-
let last = *self.checkpoints.last().unwrap_or(&0);
98-
self.current_slice = &mut self.data[last..];
99-
self.current_len = old_checkpoint - last;
91+
let last_checkpoint = self.last_checkpoint();
92+
self.current_ptr = self.data[last_checkpoint..].as_mut_ptr();
93+
self.current_len = old_checkpoint - last_checkpoint;
10094
self.update_limit();
10195
}
10296
}
10397

10498
/// Get the length of the current memory range.
99+
#[inline(always)]
105100
pub fn len(&self) -> usize {
106101
self.current_len
107102
}
108103

109-
/// Return true if current effective memory range is zero.
104+
#[inline(always)]
110105
pub fn is_empty(&self) -> bool {
111106
self.current_len == 0
112107
}
113108

114-
/// Return the memory of the current context
115-
pub fn data(&self) -> &[u8] {
116-
self.get_current_slice()
117-
}
118-
119109
/// Resize the memory. assume that we already checked if:
120-
/// - we have enought gas to resize this vector
110+
/// - we have enough gas to resize this vector
121111
/// - we made new_size as multiply of 32
122112
/// - [new_size] is greater than `self.len()`
113+
#[inline(always)]
123114
pub fn resize(&mut self, new_size: usize) {
124115
// extend with zeros
125116
let range = self.current_len..new_size;
126117

127-
self.get_current_slice_mut()[range]
128-
.iter_mut()
129-
.for_each(|byte| *byte = 0);
118+
for byte in self.current_slice_mut()[range].iter_mut() {
119+
*byte = 0;
120+
}
121+
130122
self.current_len = new_size;
131123
self.update_limit();
132124
}
@@ -137,7 +129,7 @@ impl SharedMemory {
137129
#[inline(always)]
138130
#[cfg_attr(debug_assertions, track_caller)]
139131
pub fn slice(&self, offset: usize, size: usize) -> &[u8] {
140-
match self.get_current_slice().get(offset..offset + size) {
132+
match self.current_slice().get(offset..offset + size) {
141133
Some(slice) => slice,
142134
None => debug_unreachable!("slice OOB: {offset}..{size}; len: {}", self.len()),
143135
}
@@ -150,7 +142,7 @@ impl SharedMemory {
150142
#[cfg_attr(debug_assertions, track_caller)]
151143
pub fn slice_mut(&mut self, offset: usize, size: usize) -> &mut [u8] {
152144
let len = self.current_len;
153-
match self.get_current_slice_mut().get_mut(offset..offset + size) {
145+
match self.current_slice_mut().get_mut(offset..offset + size) {
154146
Some(slice) => slice,
155147
None => debug_unreachable!("slice OOB: {offset}..{size}; len: {}", len),
156148
}
@@ -162,7 +154,7 @@ impl SharedMemory {
162154
#[inline(always)]
163155
#[cfg_attr(debug_assertions, track_caller)]
164156
pub fn set_byte(&mut self, index: usize, byte: u8) {
165-
match self.get_current_slice_mut().get_mut(index) {
157+
match self.current_slice_mut().get_mut(index) {
166158
Some(b) => *b = byte,
167159
None => debug_unreachable!("set_byte OOB: {index}; len: {}", self.len()),
168160
}
@@ -219,36 +211,33 @@ impl SharedMemory {
219211
#[inline(always)]
220212
#[cfg_attr(debug_assertions, track_caller)]
221213
pub fn copy(&mut self, dst: usize, src: usize, len: usize) {
222-
self.get_current_slice_mut()
223-
.copy_within(src..src + len, dst);
214+
self.current_slice_mut().copy_within(src..src + len, dst);
224215
}
225216

226-
/// Get a refernce to the memory of the current context
217+
/// Get a reference to the memory of the current context
227218
#[inline(always)]
228-
fn get_current_slice(&self) -> &[u8] {
219+
fn current_slice(&self) -> &[u8] {
229220
// Safety: if it is a valid pointer to a slice of `self.data`
230-
unsafe { &*self.current_slice }
221+
unsafe { slice::from_raw_parts(self.current_ptr, self.limit) }
231222
}
232223

233-
/// Get a mutable refernce to the memory of the current context
224+
/// Get a mutable reference to the memory of the current context
234225
#[inline(always)]
235-
fn get_current_slice_mut(&mut self) -> &mut [u8] {
226+
fn current_slice_mut(&mut self) -> &mut [u8] {
236227
// Safety: it is a valid pointer to a slice of `self.data`
237-
unsafe { &mut *self.current_slice }
228+
unsafe { slice::from_raw_parts_mut(self.current_ptr, self.limit) }
238229
}
239230

240-
/// Calculates memory allocation upper bound using
241-
/// https://2π.com/22/eth-max-mem
231+
/// Update the amount of memory left for usage
242232
#[inline(always)]
243-
fn calculate_upper_bound(gas_limit: u64) -> u64 {
244-
4096 * sqrt(2 * gas_limit)
233+
fn update_limit(&mut self) {
234+
self.limit = self.data.len() - self.last_checkpoint() - self.current_len;
245235
}
246236

247-
/// Update the amount of memory left for usage
237+
/// Get the last memory checkpoint
248238
#[inline(always)]
249-
fn update_limit(&mut self) {
250-
self.limit =
251-
(self.data.len() - *self.checkpoints.last().unwrap_or(&0) - self.current_len) as u64;
239+
fn last_checkpoint(&self) -> usize {
240+
*self.checkpoints.last().unwrap_or(&0)
252241
}
253242
}
254243

crates/revm/src/evm_impl.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,11 @@ impl<'a, GSPEC: Spec, DB: Database, const INSPECT: bool> EVMImpl<'a, GSPEC, DB,
604604
interpreter.run::<Self, GSPEC>(self)
605605
};
606606

607-
(exit_reason, interpreter.return_value(), *interpreter.gas())
607+
let (return_value, gas) = (interpreter.return_value(), *interpreter.gas());
608+
609+
interpreter.shared_memory.free_context_memory();
610+
611+
(exit_reason, return_value, gas)
608612
}
609613

610614
/// Call precompile contract

0 commit comments

Comments
 (0)