Skip to content

Commit

Permalink
chore(SharedMemory): refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
Lorenzo Feroleto committed Sep 27, 2023
1 parent c7945eb commit 0e349b5
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 38 deletions.
4 changes: 1 addition & 3 deletions crates/interpreter/src/instructions/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,8 @@ macro_rules! gas_or_fail {

macro_rules! shared_memory_resize {
($interp:expr, $offset:expr, $len:expr) => {
let len: usize = $len;
let offset: usize = $offset;
if let Some(new_size) =
crate::interpreter::shared_memory::next_multiple_of_32(offset.saturating_add(len))
crate::interpreter::shared_memory::next_multiple_of_32($offset.saturating_add($len))
{
if new_size as u64 > $interp.shared_memory.limit {
$interp.instruction_result = InstructionResult::MemoryLimitOOG;
Expand Down
72 changes: 37 additions & 35 deletions crates/interpreter/src/interpreter/shared_memory.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use revm_primitives::U256;
use revm_primitives::{CALL_STACK_LIMIT, U256};

use crate::alloc::vec;
use crate::alloc::vec::Vec;
use crate::alloc::{boxed::Box, vec::Vec};
use core::{
cmp::min,
fmt,
Expand All @@ -14,7 +14,7 @@ use core::{
/// the `new` static method to ensure memory safety.
pub struct SharedMemory {
/// Shared buffer
data: Vec<u8>,
data: Box<[u8]>,
/// Memory checkpoints for each depth
checkpoints: Vec<usize>,
/// Raw pointer used for the portion of memory used
Expand All @@ -31,26 +31,33 @@ impl fmt::Debug for SharedMemory {
f.debug_struct("SharedMemory")
.field(
"current_slice",
&crate::primitives::hex::encode(self.get_current_slice()),
&crate::primitives::hex::encode(self.current_slice()),
)
.finish()
}
}

impl SharedMemory {
/// Calculates memory allocation upper bound using
/// https://2π.com/22/eth-max-mem
#[inline]
pub fn calculate_upper_bound(gas_limit: u64) -> u64 {
4096 * sqrt(2 * 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 {
let size = min(
SharedMemory::calculate_upper_bound(gas_limit) as usize,
Self::calculate_upper_bound(gas_limit) as usize,
2usize.pow(32) - 1,
);

let mut data = vec![0; size];
let mut data = vec![0; size].into_boxed_slice();
let current_slice: *mut [u8] = &mut data[..];
SharedMemory {
Self {
data,
checkpoints: Vec::with_capacity(1024),
current_slice,
Expand All @@ -65,15 +72,15 @@ impl SharedMemory {
/// Uses [memory_limit] as maximum allocation size
pub fn new_with_memory_limit(gas_limit: u64, memory_limit: u64) -> Self {
let size = min(
SharedMemory::calculate_upper_bound(gas_limit) as usize,
Self::calculate_upper_bound(gas_limit) as usize,
memory_limit as usize,
);

let mut data = vec![0; size];
let mut data = vec![0; size].into_boxed_slice();
let current_slice: *mut [u8] = &mut data[..];
SharedMemory {
Self {
data,
checkpoints: Vec::with_capacity(1024),
checkpoints: Vec::with_capacity(CALL_STACK_LIMIT as usize),
current_slice,
current_len: 0,
limit: size as u64,
Expand All @@ -94,37 +101,34 @@ impl SharedMemory {
/// 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 = *self.checkpoints.last().unwrap_or(&0);
self.current_slice = &mut self.data[last..];
self.current_len = old_checkpoint - last;
let last_checkpoint = self.last_checkpoint();
self.current_slice = &mut self.data[last_checkpoint..];
self.current_len = old_checkpoint - last_checkpoint;
self.update_limit();
}
}

/// Get the length of the current memory range.
#[inline(always)]
pub fn len(&self) -> usize {
self.current_len
}

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

/// Return the memory of the current context
pub fn data(&self) -> &[u8] {
self.get_current_slice()
}

/// Resize the memory. assume that we already checked if:
/// - we have enought gas to resize this vector
/// - we made new_size as multiply of 32
/// - [new_size] is greater than `self.len()`
#[inline(always)]
pub fn resize(&mut self, new_size: usize) {
// extend with zeros
let range = self.current_len..new_size;

self.get_current_slice_mut()[range]
self.current_slice_mut()[range]
.iter_mut()
.for_each(|byte| *byte = 0);
self.current_len = new_size;
Expand All @@ -137,7 +141,7 @@ impl SharedMemory {
#[inline(always)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn slice(&self, offset: usize, size: usize) -> &[u8] {
match self.get_current_slice().get(offset..offset + size) {
match self.current_slice().get(offset..offset + size) {
Some(slice) => slice,
None => debug_unreachable!("slice OOB: {offset}..{size}; len: {}", self.len()),
}
Expand All @@ -150,7 +154,7 @@ impl SharedMemory {
#[cfg_attr(debug_assertions, track_caller)]
pub fn slice_mut(&mut self, offset: usize, size: usize) -> &mut [u8] {
let len = self.current_len;
match self.get_current_slice_mut().get_mut(offset..offset + size) {
match self.current_slice_mut().get_mut(offset..offset + size) {
Some(slice) => slice,
None => debug_unreachable!("slice OOB: {offset}..{size}; len: {}", len),
}
Expand All @@ -162,7 +166,7 @@ impl SharedMemory {
#[inline(always)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn set_byte(&mut self, index: usize, byte: u8) {
match self.get_current_slice_mut().get_mut(index) {
match self.current_slice_mut().get_mut(index) {
Some(b) => *b = byte,
None => debug_unreachable!("set_byte OOB: {index}; len: {}", self.len()),
}
Expand Down Expand Up @@ -219,37 +223,35 @@ impl SharedMemory {
#[inline(always)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn copy(&mut self, dst: usize, src: usize, len: usize) {
self.get_current_slice_mut()
.copy_within(src..src + len, dst);
self.current_slice_mut().copy_within(src..src + len, dst);
}

/// Get a refernce to the memory of the current context
#[inline(always)]
fn get_current_slice(&self) -> &[u8] {
fn current_slice(&self) -> &[u8] {
// Safety: if it is a valid pointer to a slice of `self.data`
unsafe { &*self.current_slice }
}

/// Get a mutable refernce to the memory of the current context
#[inline(always)]
fn get_current_slice_mut(&mut self) -> &mut [u8] {
fn current_slice_mut(&mut self) -> &mut [u8] {
// Safety: it is a valid pointer to a slice of `self.data`
unsafe { &mut *self.current_slice }
}

/// Calculates memory allocation upper bound using
/// https://2π.com/22/eth-max-mem
#[inline(always)]
fn calculate_upper_bound(gas_limit: u64) -> u64 {
4096 * sqrt(2 * gas_limit)
}

/// Update the amount of memory left for usage
#[inline(always)]
fn update_limit(&mut self) {
self.limit =
(self.data.len() - *self.checkpoints.last().unwrap_or(&0) - self.current_len) as u64;
}

/// Get the last memory checkpoint
#[inline(always)]
fn last_checkpoint(&self) -> usize {
*self.checkpoints.last().unwrap_or(&0)
}
}

/// Rounds up `x` to the closest multiple of 32. If `x % 32 == 0` then `x` is returned.
Expand Down

0 comments on commit 0e349b5

Please sign in to comment.