diff --git a/crates/interpreter/src/interpreter.rs b/crates/interpreter/src/interpreter.rs index 0e30170af9..59d9ae1ba8 100644 --- a/crates/interpreter/src/interpreter.rs +++ b/crates/interpreter/src/interpreter.rs @@ -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 } @@ -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() } diff --git a/crates/interpreter/src/interpreter/shared_memory.rs b/crates/interpreter/src/interpreter/shared_memory.rs index 8f9deafc2a..af4ed2c236 100644 --- a/crates/interpreter/src/interpreter/shared_memory.rs +++ b/crates/interpreter/src/interpreter/shared_memory.rs @@ -42,7 +42,7 @@ 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. @@ -50,7 +50,7 @@ impl SharedMemory { /// 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. @@ -81,7 +81,7 @@ 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; } @@ -89,7 +89,7 @@ impl SharedMemory { 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(); } @@ -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 @@ -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(); @@ -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()), } } @@ -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), } } @@ -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 @@ -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. diff --git a/crates/revm/benches/bench.rs b/crates/revm/benches/bench.rs index 736e6f4a1c..e7e057b6db 100644 --- a/crates/revm/benches/bench.rs +++ b/crates/revm/benches/bench.rs @@ -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| { @@ -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,