Files
parity-wasm/src/interpreter/memory.rs

152 lines
4.5 KiB
Rust
Raw Normal View History

2017-04-21 14:35:12 +03:00
use std::u32;
use std::sync::Arc;
use parking_lot::RwLock;
use elements::MemoryType;
2017-08-01 16:15:08 +03:00
use interpreter::{Error, UserError};
2017-06-08 10:49:32 +03:00
use interpreter::module::check_limits;
2017-04-21 14:35:12 +03:00
/// Linear memory page size.
2017-05-08 11:35:56 +03:00
pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536;
2017-06-09 12:13:35 +03:00
/// Maximal number of pages.
const LINEAR_MEMORY_MAX_PAGES: u32 = 65536;
2017-04-21 14:35:12 +03:00
/// Linear memory instance.
2017-08-01 16:15:08 +03:00
pub struct MemoryInstance<E: UserError> {
2017-04-21 14:35:12 +03:00
/// Linear memory buffer.
buffer: RwLock<Vec<u8>>,
/// Maximum buffer size.
maximum_size: u32,
2017-08-01 14:44:33 +03:00
/// Dummy to avoid compilation error.
_dummy: ::std::marker::PhantomData<E>,
2017-04-21 14:35:12 +03:00
}
2017-06-14 17:56:45 +03:00
struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref<Target=Vec<u8>> {
2017-06-14 18:00:59 +03:00
buffer: &'a B,
2017-06-14 17:56:45 +03:00
offset: usize,
size: usize,
}
impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref<Target=Vec<u8>> {
fn range(&self) -> ::std::ops::Range<usize> {
self.offset..self.offset+self.size
}
2017-06-14 18:00:59 +03:00
fn slice(&self) -> &[u8] {
2017-06-14 18:09:33 +03:00
&self.buffer[self.range()]
2017-06-14 18:00:59 +03:00
}
2017-06-14 17:56:45 +03:00
}
2017-08-01 16:15:08 +03:00
impl<E> MemoryInstance<E> where E: UserError {
2017-04-21 14:35:12 +03:00
/// Create new linear memory instance.
2017-08-01 14:44:33 +03:00
pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error<E>> {
2017-06-08 10:49:32 +03:00
check_limits(memory_type.limits())?;
let maximum_size = match memory_type.limits().maximum() {
Some(maximum_pages) if maximum_pages > LINEAR_MEMORY_MAX_PAGES =>
return Err(Error::Memory(format!("maximum memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES))),
Some(maximum_pages) => maximum_pages.saturating_mul(LINEAR_MEMORY_PAGE_SIZE),
None => u32::MAX,
};
let initial_size = calculate_memory_size(0, memory_type.limits().initial(), maximum_size)
.ok_or(Error::Memory(format!("initial memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES)))?;
2017-06-09 12:13:35 +03:00
2017-04-21 14:35:12 +03:00
let memory = MemoryInstance {
2017-06-27 15:21:10 +03:00
buffer: RwLock::new(vec![0; initial_size as usize]),
maximum_size: maximum_size,
2017-08-01 14:44:33 +03:00
_dummy: Default::default(),
2017-04-21 14:35:12 +03:00
};
2017-04-21 14:35:12 +03:00
Ok(Arc::new(memory))
}
/// Return linear memory size (in pages).
pub fn size(&self) -> u32 {
self.buffer.read().len() as u32 / LINEAR_MEMORY_PAGE_SIZE
}
/// Get data at given offset.
2017-08-01 14:44:33 +03:00
pub fn get(&self, offset: u32, size: usize) -> Result<Vec<u8>, Error<E>> {
2017-04-21 14:35:12 +03:00
let buffer = self.buffer.read();
2017-06-14 17:56:45 +03:00
let region = self.checked_region(&buffer, offset as usize, size)?;
2017-04-21 14:35:12 +03:00
2017-06-14 18:00:59 +03:00
Ok(region.slice().to_vec())
2017-04-21 14:35:12 +03:00
}
/// Set data at given offset.
2017-08-01 14:44:33 +03:00
pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error<E>> {
2017-04-21 14:35:12 +03:00
let mut buffer = self.buffer.write();
2017-06-14 17:56:45 +03:00
let range = self.checked_region(&buffer, offset as usize, value.len())?.range();
2017-04-21 14:35:12 +03:00
2017-06-14 17:56:45 +03:00
buffer[range].copy_from_slice(value);
2017-04-21 14:35:12 +03:00
Ok(())
}
/// Increases the size of the linear memory by given number of pages.
/// Returns -1 if allocation fails or previous memory size, if succeeds.
2017-08-01 14:44:33 +03:00
pub fn grow(&self, pages: u32) -> Result<u32, Error<E>> {
2017-04-21 14:35:12 +03:00
let mut buffer = self.buffer.write();
let old_size = buffer.len() as u32;
match calculate_memory_size(old_size, pages, self.maximum_size) {
2017-04-21 14:35:12 +03:00
None => Ok(u32::MAX),
Some(new_size) => {
2017-06-21 14:13:03 +03:00
buffer.resize(new_size as usize, 0);
2017-04-21 14:35:12 +03:00
Ok(old_size / LINEAR_MEMORY_PAGE_SIZE)
},
}
}
2017-06-14 17:56:45 +03:00
2017-08-01 14:44:33 +03:00
fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result<CheckedRegion<'a, B>, Error<E>>
2017-06-14 17:56:45 +03:00
where B: ::std::ops::Deref<Target=Vec<u8>>
{
let end = offset.checked_add(size)
.ok_or(Error::Memory(format!("trying to access memory block of size {} from offset {}", size, offset)))?;
if end > buffer.len() {
return Err(Error::Memory(format!("trying to access region [{}..{}] in memory [0..{}]", offset, end, buffer.len())));
}
Ok(CheckedRegion {
2017-06-14 18:00:59 +03:00
buffer: buffer,
2017-06-14 17:56:45 +03:00
offset: offset,
size: size,
})
}
2017-06-14 18:00:59 +03:00
/// Copy memory region
2017-08-01 14:44:33 +03:00
pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error<E>> {
2017-06-14 17:56:45 +03:00
let buffer = self.buffer.write();
let read_region = self.checked_region(&buffer, src_offset, len)?;
let write_region = self.checked_region(&buffer, dst_offset, len)?;
unsafe { ::std::ptr::copy(
buffer[read_region.range()].as_ptr(),
buffer[write_region.range()].as_ptr() as *mut _,
len,
)}
Ok(())
}
2017-06-14 19:26:38 +03:00
/// Zero memory region
2017-08-01 14:44:33 +03:00
pub fn zero(&self, offset: usize, len: usize) -> Result<(), Error<E>> {
2017-06-14 19:26:38 +03:00
let mut buffer = self.buffer.write();
let range = self.checked_region(&buffer, offset, len)?.range();
for val in &mut buffer[range] { *val = 0 }
Ok(())
}
2017-04-21 14:35:12 +03:00
}
fn calculate_memory_size(old_size: u32, additional_pages: u32, maximum_size: u32) -> Option<u32> {
additional_pages
.checked_mul(LINEAR_MEMORY_PAGE_SIZE)
.and_then(|size| size.checked_add(old_size))
.and_then(|size| if size > maximum_size {
None
} else {
Some(size)
})
}