Skip to content

Commit

Permalink
chore(SharedMemory): internal refactoring part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
Lorenzo Feroleto committed Sep 30, 2023
1 parent 07ece23 commit 23a1191
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 25 deletions.
5 changes: 3 additions & 2 deletions crates/interpreter/src/interpreter.rs
Expand Up @@ -88,7 +88,8 @@ impl<'a> Interpreter<'a> {
&self.gas
}

/// Reference of interpreter stack.
/// Returns a reference to the interpreter's stack.
#[inline]
pub fn stack(&self) -> &Stack {
&self.stack
}
Expand Down Expand Up @@ -146,7 +147,7 @@ impl<'a> Interpreter<'a> {

/// Returns a copy of the interpreter's return value, if any.
#[inline]
pub fn return_value(&mut self) -> Bytes {
pub fn return_value(&self) -> Bytes {
self.return_value_slice().to_vec().into()
}

Expand Down
36 changes: 24 additions & 12 deletions crates/interpreter/src/interpreter/shared_memory.rs
Expand Up @@ -42,15 +42,15 @@ impl SharedMemory {
/// https://2π.com/22/eth-max-mem
#[inline]
pub fn calculate_upper_bound(gas_limit: u64) -> u64 {
4096 * sqrt(2u64.checked_mul(gas_limit).unwrap_or(u64::MAX))
4096 * sqrt(2u64.saturating_mul(gas_limit))
}

/// Allocate memory to be shared between calls.
/// Memory size is estimated using https://2π.com/22/eth-max-mem
/// which depends on transaction [gas_limit].
/// Maximum allocation size is 2^32 - 1 bytes;
pub fn new(gas_limit: u64) -> Self {
Self::new_with_memory_limit(gas_limit, (u32::MAX - 1) as u64)
Self::new_with_memory_limit(gas_limit, u32::MAX as u64)
}

/// Allocate memory to be shared between calls.
Expand Down Expand Up @@ -81,15 +81,15 @@ impl SharedMemory {

self.checkpoints.push(new_checkpoint);

self.current_ptr = self.data[new_checkpoint..].as_mut_ptr();
self.set_ptr(new_checkpoint);
self.current_len = 0;
}

/// Prepares the shared memory for returning to the previous context
pub fn free_context_memory(&mut self) {
if let Some(old_checkpoint) = self.checkpoints.pop() {
let last_checkpoint = self.last_checkpoint();
self.current_ptr = self.data[last_checkpoint..].as_mut_ptr();
self.set_ptr(last_checkpoint);
self.current_len = old_checkpoint - last_checkpoint;
self.update_limit();
}
Expand All @@ -101,6 +101,7 @@ impl SharedMemory {
self.current_len
}

/// Returns true if the current memory range is empty.
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.current_len == 0
Expand All @@ -115,9 +116,7 @@ impl SharedMemory {
// extend with zeros
let range = self.current_len..new_size;

for byte in self.current_slice_mut()[range].iter_mut() {
*byte = 0;
}
self.current_slice_mut()[range].fill(0);

self.current_len = new_size;
self.update_limit();
Expand All @@ -129,9 +128,10 @@ impl SharedMemory {
#[inline(always)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn slice(&self, offset: usize, size: usize) -> &[u8] {
match self.current_slice().get(offset..offset + size) {
let end = offset + size;
match self.current_slice().get(offset..end) {
Some(slice) => slice,
None => debug_unreachable!("slice OOB: {offset}..{size}; len: {}", self.len()),
None => debug_unreachable!("slice OOB: {offset}..{end}; len: {}", self.len()),
}
}

Expand All @@ -141,10 +141,11 @@ impl SharedMemory {
#[inline(always)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn slice_mut(&mut self, offset: usize, size: usize) -> &mut [u8] {
let end = offset + size;
let len = self.current_len;
match self.current_slice_mut().get_mut(offset..offset + size) {
Some(slice) => slice,
None => debug_unreachable!("slice OOB: {offset}..{size}; len: {}", len),
None => debug_unreachable!("slice OOB: {offset}..{end}; len: {}", len),
}
}

Expand Down Expand Up @@ -218,14 +219,16 @@ impl SharedMemory {
#[inline(always)]
fn current_slice(&self) -> &[u8] {
// Safety: if it is a valid pointer to a slice of `self.data`
unsafe { slice::from_raw_parts(self.current_ptr, self.limit) }
unsafe { slice::from_raw_parts(self.current_ptr, self.data.len() - self.last_checkpoint()) }
}

/// Get a mutable reference to the memory of the current context
#[inline(always)]
fn current_slice_mut(&mut self) -> &mut [u8] {
// Safety: it is a valid pointer to a slice of `self.data`
unsafe { slice::from_raw_parts_mut(self.current_ptr, self.limit) }
unsafe {
slice::from_raw_parts_mut(self.current_ptr, self.data.len() - self.last_checkpoint())
}
}

/// Update the amount of memory left for usage
Expand All @@ -239,6 +242,15 @@ impl SharedMemory {
fn last_checkpoint(&self) -> usize {
*self.checkpoints.last().unwrap_or(&0)
}

/// Set memory pointer to checkpoint
#[inline(always)]
fn set_ptr(&mut self, checkpoint: usize) {
if self.data.len() > 0 {
assume!(checkpoint < self.data.len());
self.current_ptr = unsafe { self.data.as_mut_ptr().add(checkpoint) };
}
}
}

/// Rounds up `x` to the closest multiple of 32. If `x % 32 == 0` then `x` is returned.
Expand Down
13 changes: 2 additions & 11 deletions crates/revm/benches/bench.rs
Expand Up @@ -102,18 +102,11 @@ fn bench_transact(g: &mut BenchmarkGroup<'_, WallTime>, evm: &mut Evm) {
BytecodeState::Analysed { .. } => "analysed",
};
let id = format!("transact/{state}");
g.bench_function(id, |b| {
b.iter(|| {
// reset gas limit to the right amount before tx
evm.env.tx.gas_limit = 22_000;
evm.transact().unwrap()
})
});
g.bench_function(id, |b| b.iter(|| evm.transact().unwrap()));
}

fn bench_eval(g: &mut BenchmarkGroup<'_, WallTime>, evm: &mut Evm) {
let gas_limit = 22_000;
evm.env.tx.gas_limit = gas_limit;
evm.env.tx.gas_limit = 22_000;
let mut shared_memory = SharedMemory::new(evm.env.tx.gas_limit);

g.bench_function("eval", |b| {
Expand All @@ -124,8 +117,6 @@ fn bench_eval(g: &mut BenchmarkGroup<'_, WallTime>, evm: &mut Evm) {
};
let mut host = DummyHost::new(evm.env.clone());
b.iter(|| {
// reset gas limit to the right amount before tx
evm.env.tx.gas_limit = gas_limit;
let mut interpreter = Interpreter::new(
Box::new(contract.clone()),
u64::MAX,
Expand Down

0 comments on commit 23a1191

Please sign in to comment.