diff --git a/src/memory.rs b/src/memory.rs index 038ab58..f87dd50 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -58,6 +58,7 @@ pub struct MemoryInstance { initial: Pages, current_size: Cell, maximum: Option, + lowest_used: Cell, } impl fmt::Debug for MemoryInstance { @@ -127,6 +128,7 @@ impl MemoryInstance { initial: initial, current_size: Cell::new(initial_size.0), maximum: maximum, + lowest_used: Cell::new(u32::max_value()), } } @@ -148,6 +150,16 @@ impl MemoryInstance { self.maximum } + /// Returns lowest offset ever written or `u32::max_value()` if none. + pub fn lowest_used(&self) -> u32 { + self.lowest_used.get() + } + + /// Resets tracked lowest offset. + pub fn reset_lowest_used(&self, addr: u32) { + self.lowest_used.set(addr) + } + /// Returns current linear memory size. /// /// Maximum memory size cannot exceed `65536` pages or 4GiB. @@ -171,6 +183,12 @@ impl MemoryInstance { Bytes(self.current_size.get()).round_up_to() } + /// Returns current used memory size in bytes. + /// This is the highest memory address that had been written to. + pub fn used_size(&self) -> Bytes { + Bytes(self.buffer.borrow().len()) + } + /// Get value from memory at given offset. pub fn get_value(&self, offset: u32) -> Result { let mut buffer = self.buffer.borrow_mut(); @@ -213,6 +231,9 @@ impl MemoryInstance { .checked_region(&mut buffer, offset as usize, value.len())? .range(); + if offset < self.lowest_used.get() { + self.lowest_used.set(offset); + } buffer[range].copy_from_slice(value); Ok(()) @@ -224,6 +245,9 @@ impl MemoryInstance { let range = self .checked_region(&mut buffer, offset as usize, ::core::mem::size_of::())? .range(); + if offset < self.lowest_used.get() { + self.lowest_used.set(offset); + } value.into_little_endian(&mut buffer[range]); Ok(()) } @@ -368,6 +392,10 @@ impl MemoryInstance { let (read_region, write_region) = self.checked_region_pair(&mut buffer, src_offset, len, dst_offset, len)?; + if dst_offset < self.lowest_used.get() as usize { + self.lowest_used.set(dst_offset as u32); + } + unsafe { ::core::ptr::copy( buffer[read_region.range()].as_ptr(), @@ -407,6 +435,10 @@ impl MemoryInstance { ))); } + if dst_offset < self.lowest_used.get() as usize { + self.lowest_used.set(dst_offset as u32); + } + unsafe { ::core::ptr::copy_nonoverlapping( buffer[read_region.range()].as_ptr(), @@ -446,6 +478,10 @@ impl MemoryInstance { .checked_region(&mut dst_buffer, dst_offset, len)? .range(); + if dst_offset < dst.lowest_used.get() as usize { + dst.lowest_used.set(dst_offset as u32); + } + dst_buffer[dst_range].copy_from_slice(&src_buffer[src_range]); Ok(()) @@ -462,6 +498,11 @@ impl MemoryInstance { let mut buffer = self.buffer.borrow_mut(); let range = self.checked_region(&mut buffer, offset, len)?.range(); + + if offset < self.lowest_used.get() as usize { + self.lowest_used.set(offset as u32); + } + for val in &mut buffer[range] { *val = new_val }