mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-15 07:51:46 +00:00
Implement copy_nonoverlapping and clear.
This commit is contained in:
@ -1,5 +1,7 @@
|
|||||||
use std::u32;
|
use std::u32;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::ops::Range;
|
||||||
|
use std::cmp;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use elements::{MemoryType, ResizableLimits};
|
use elements::{MemoryType, ResizableLimits};
|
||||||
use interpreter::{Error, UserError};
|
use interpreter::{Error, UserError};
|
||||||
@ -29,13 +31,20 @@ struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref<Target=Vec<u8>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref<Target=Vec<u8>> {
|
impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref<Target=Vec<u8>> {
|
||||||
fn range(&self) -> ::std::ops::Range<usize> {
|
fn range(&self) -> Range<usize> {
|
||||||
self.offset..self.offset+self.size
|
self.offset..self.offset+self.size
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slice(&self) -> &[u8] {
|
fn slice(&self) -> &[u8] {
|
||||||
&self.buffer[self.range()]
|
&self.buffer[self.range()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn intersects(&self, other: &Self) -> bool {
|
||||||
|
let low = cmp::max(self.offset, other.offset);
|
||||||
|
let high = cmp::min(self.offset + self.size, other.offset + other.size);
|
||||||
|
|
||||||
|
low < high
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> MemoryInstance<E> where E: UserError {
|
impl<E> MemoryInstance<E> where E: UserError {
|
||||||
@ -131,7 +140,7 @@ impl<E> MemoryInstance<E> where E: UserError {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy memory region
|
/// Copy memory region. Semantically equivalent to `memmove`.
|
||||||
pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error<E>> {
|
pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error<E>> {
|
||||||
let buffer = self.buffer.write();
|
let buffer = self.buffer.write();
|
||||||
|
|
||||||
@ -147,14 +156,40 @@ impl<E> MemoryInstance<E> where E: UserError {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Zero memory region
|
/// Copy memory region, non-overlapping version. Semantically equivalent to `memcpy`,
|
||||||
pub fn zero(&self, offset: usize, len: usize) -> Result<(), Error<E>> {
|
/// but returns Error if source overlaping with destination.
|
||||||
|
pub fn copy_nonoverlapping(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error<E>> {
|
||||||
|
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)?;
|
||||||
|
|
||||||
|
if read_region.intersects(&write_region) {
|
||||||
|
return Err(Error::Memory(format!("non-overlapping copy is used for overlapping regions")))
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { ::std::ptr::copy_nonoverlapping(
|
||||||
|
buffer[read_region.range()].as_ptr(),
|
||||||
|
buffer[write_region.range()].as_ptr() as *mut _,
|
||||||
|
len,
|
||||||
|
)}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear memory region with a specified value. Semantically equivalent to `memset`.
|
||||||
|
pub fn clear(&self, offset: usize, new_val: u8, len: usize) -> Result<(), Error<E>> {
|
||||||
let mut buffer = self.buffer.write();
|
let mut buffer = self.buffer.write();
|
||||||
|
|
||||||
let range = self.checked_region(&buffer, offset, len)?.range();
|
let range = self.checked_region(&buffer, offset, len)?.range();
|
||||||
for val in &mut buffer[range] { *val = 0 }
|
for val in &mut buffer[range] { *val = new_val }
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Zero memory region
|
||||||
|
pub fn zero(&self, offset: usize, len: usize) -> Result<(), Error<E>> {
|
||||||
|
self.clear(offset, 0, len)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_memory_size(old_size: u32, additional_pages: u32, maximum_size: u32) -> Option<u32> {
|
fn calculate_memory_size(old_size: u32, additional_pages: u32, maximum_size: u32) -> Option<u32> {
|
||||||
@ -172,8 +207,68 @@ fn calculate_memory_size(old_size: u32, additional_pages: u32, maximum_size: u32
|
|||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::MemoryInstance;
|
use super::MemoryInstance;
|
||||||
|
use interpreter::{Error, DummyUserError};
|
||||||
use elements::MemoryType;
|
use elements::MemoryType;
|
||||||
use interpreter::DummyUserError;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
fn create_memory(initial_content: &[u8]) -> Arc<MemoryInstance<DummyUserError>> {
|
||||||
|
let mem = MemoryInstance::new(&MemoryType::new(1, Some(1)))
|
||||||
|
.expect("MemoryInstance created successfuly");
|
||||||
|
mem.set(0, initial_content).expect("Successful initialize the memory");
|
||||||
|
mem
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn copy_overlaps_1() {
|
||||||
|
let mem = create_memory(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||||
|
mem.copy(0, 4, 6).expect("Successfully copy the elements");
|
||||||
|
let result = mem.get(0, 10).expect("Successfully retrieve the result");
|
||||||
|
assert_eq!(result, &[0, 1, 2, 3, 0, 1, 2, 3, 4, 5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn copy_overlaps_2() {
|
||||||
|
let mem = create_memory(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||||
|
mem.copy(4, 0, 6).expect("Successfully copy the elements");
|
||||||
|
let result = mem.get(0, 10).expect("Successfully retrieve the result");
|
||||||
|
assert_eq!(result, &[4, 5, 6, 7, 8, 9, 6, 7, 8, 9]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn copy_nonoverlapping() {
|
||||||
|
let mem = create_memory(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||||
|
mem.copy_nonoverlapping(0, 10, 10).expect("Successfully copy the elements");
|
||||||
|
let result = mem.get(10, 10).expect("Successfully retrieve the result");
|
||||||
|
assert_eq!(result, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn copy_nonoverlapping_overlaps_1() {
|
||||||
|
let mem = create_memory(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||||
|
let result = mem.copy_nonoverlapping(0, 4, 6);
|
||||||
|
match result {
|
||||||
|
Err(Error::Memory(_)) => {},
|
||||||
|
_ => panic!("Expected Error::Memory(_) result, but got {:?}", result),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn copy_nonoverlapping_overlaps_2() {
|
||||||
|
let mem = create_memory(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||||
|
let result = mem.copy_nonoverlapping(4, 0, 6);
|
||||||
|
match result {
|
||||||
|
Err(Error::Memory(_)) => {},
|
||||||
|
_ => panic!("Expected Error::Memory(_), but got {:?}", result),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn clear() {
|
||||||
|
let mem = create_memory(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||||
|
mem.clear(0, 0x4A, 10).expect("To successfully clear the memory");
|
||||||
|
let result = mem.get(0, 10).expect("To successfully retrieve the result");
|
||||||
|
assert_eq!(result, &[0x4A; 10]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_into() {
|
fn get_into() {
|
||||||
@ -185,4 +280,4 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(data, [17, 129]);
|
assert_eq!(data, [17, 129]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user