first attempt to fix

This commit is contained in:
vms
2021-04-23 23:56:41 +03:00
parent 34bf8a196a
commit 6bf0eedec7
17 changed files with 373 additions and 321 deletions

View File

@@ -27,3 +27,38 @@ pub enum MemoryAccessError {
memory_size: usize,
},
}
#[derive(Debug, ThisError)]
pub enum MemoryWriteError {
/// The memory doesn't exist.
#[error("memory `{memory_index}` does not exist")]
MemoryIsMissing {
/// The memory index.
memory_index: usize,
},
/// The local or import function doesn't exist.
#[error("the allocate function with index `{function_index}` doesn't exist in Wasm module")]
AllocateFuncIsMissing {
/// The local or import function index.
function_index: u32,
},
/// Failed to call a allocate function.
#[error("call to allocated was failed")]
AllocateCallFailed,
/// Allocate input types doesn't match with needed.
#[error(
"allocate func doesn't receive two i32 values,\
probably a Wasm module's built with unsupported sdk version"
)]
AllocateFuncIncompatibleSignature,
/// Allocate output types doesn't match with needed.
#[error(
"allocate func doesn't return a one value of I32 type,\
probably a Wasm module's built with unsupported sdk version"
)]
AllocateFuncIncompatibleOutput,
}

View File

@@ -23,7 +23,8 @@ pub use fluence_it_types::IRecordType;
pub use fluence_it_types::IType;
pub use fluence_it_types::IValue;
pub type MResult<T> = std::result::Result<T, error::MemoryAccessError>;
pub type ReadResult<T> = std::result::Result<T, error::MemoryAccessError>;
pub type WriteResult<T> = std::result::Result<T, error::MemoryWriteError>;
/// Size of a value in a serialized view.
pub fn ser_type_size(ty: &IType) -> usize {
@@ -42,7 +43,7 @@ pub fn ser_type_size(ty: &IType) -> usize {
}
/// Size of a value in a serialized view.
pub fn ser_value_size(value: &IValue) -> usize {
pub fn ser_value_size(value: &IValue) -> u32 {
match value {
IValue::Boolean(_) | IValue::S8(_) | IValue::U8(_) => 1,
IValue::S16(_) | IValue::U16(_) => 2,

View File

@@ -101,7 +101,7 @@ macro_rules! read_array_ty {
&self,
offset: usize,
elements_count: usize,
) -> crate::MResult<Vec<crate::IValue>> {
) -> crate::ReadResult<Vec<crate::IValue>> {
let reader =
self.sequential_reader(offset, std::mem::size_of::<$ty>() * elements_count)?;
let mut result = Vec::with_capacity(elements_count);

View File

@@ -18,7 +18,7 @@ use crate::error::MemoryAccessError;
use crate::read_array_ty;
use crate::read_ty;
use crate::IValue;
use crate::MResult;
use crate::ReadResult;
use std::cell::Cell;
@@ -46,13 +46,13 @@ impl<'m> MemoryReader<'m> {
&self,
offset: usize,
size: usize,
) -> MResult<SequentialReader<'_, '_>> {
) -> ReadResult<SequentialReader<'_, '_>> {
self.check_access(offset, size)?;
Ok(SequentialReader::new(&self, offset))
}
pub fn read_raw_u8_array(&self, offset: usize, elements_count: usize) -> MResult<Vec<u8>> {
pub fn read_raw_u8_array(&self, offset: usize, elements_count: usize) -> ReadResult<Vec<u8>> {
let reader = self.sequential_reader(offset, elements_count)?;
let mut result = Vec::with_capacity(elements_count);
@@ -64,7 +64,7 @@ impl<'m> MemoryReader<'m> {
Ok(result)
}
pub fn read_bool_array(&self, offset: usize, elements_count: usize) -> MResult<Vec<IValue>> {
pub fn read_bool_array(&self, offset: usize, elements_count: usize) -> ReadResult<Vec<IValue>> {
let reader = self.sequential_reader(offset, elements_count)?;
let mut result = Vec::with_capacity(elements_count);
@@ -76,7 +76,7 @@ impl<'m> MemoryReader<'m> {
Ok(result)
}
pub fn check_access(&self, offset: usize, size: usize) -> MResult<()> {
pub fn check_access(&self, offset: usize, size: usize) -> ReadResult<()> {
let right = offset + size;
// the first condition is a check for overflow

View File

@@ -14,106 +14,78 @@
* limitations under the License.
*/
use crate::error::MemoryAccessError;
use crate::MResult;
use crate::WriteResult;
use std::cell::Cell;
pub struct MemoryWriter<'m> {
memory: &'m [Cell<u8>],
pub type MemSlice<'m> = &'m [Cell<u8>];
const MEMORY_INDEX: usize = 0;
pub trait Heapable {
fn allocate(&self, size: u32, type_tag: u32) -> WriteResult<usize>;
fn memory_slice(&self, memory_index: usize) -> WriteResult<MemSlice<'_>>;
}
/// Writes values of basic types sequentially to the provided writer.
/// It don't check memory limits for the optimization purposes,
/// so it could be created only by the MemoryReader::sequential_reader method.
pub struct SequentialWriter<'w, 'm> {
writer: &'w MemoryWriter<'m>,
pub struct MemoryWriter<'i, T: Heapable> {
heap_manager: &'i T,
pub(self) memory: Cell<MemSlice<'i>>,
}
pub struct SequentialWriter {
start_offset: usize,
offset: Cell<usize>,
}
impl<'m> MemoryWriter<'m> {
pub fn new(memory: &'m [Cell<u8>]) -> Self {
Self { memory }
impl<'i, T: Heapable> MemoryWriter<'i, T> {
pub fn new(heap_manager: &'i T) -> WriteResult<Self> {
let mem_slice = heap_manager.memory_slice(MEMORY_INDEX)?;
let memory = Cell::new(mem_slice);
let writer = Self {
heap_manager,
memory,
};
Ok(writer)
}
pub fn write_array<const N: usize>(&self, offset: usize, values: [u8; N]) -> MResult<()> {
self.check_access(offset, values.len())?;
pub fn write_bytes(&self, bytes: &[u8]) -> WriteResult<usize> {
let byte_type_tag = crate::type_tag_form_itype(&crate::IType::U8);
let seq_writer = self.sequential_writer(bytes.len() as _, byte_type_tag)?;
seq_writer.write_bytes(self, bytes);
self.memory[offset..offset + N]
.iter()
.zip(values.iter())
.for_each(|(cell, &byte)| cell.set(byte));
Ok(())
Ok(seq_writer.start_offset())
}
// specialization of write_array for u8
pub fn write_u8(&self, offset: usize, value: u8) -> MResult<()> {
self.check_access(offset, 1)?;
self.memory[offset].set(value);
pub fn sequential_writer(&self, size: u32, type_tag: u32) -> WriteResult<SequentialWriter> {
let offset = self.heap_manager.allocate(size, type_tag)?;
let new_mem_slice = self.heap_manager.memory_slice(MEMORY_INDEX)?;
self.memory.set(new_mem_slice);
Ok(())
}
// specialization of write_array for u32
pub fn write_u32(&self, offset: usize, value: u32) -> MResult<()> {
self.check_access(offset, 4)?;
let value = value.to_le_bytes();
self.memory[offset].set(value[0]);
self.memory[offset + 1].set(value[1]);
self.memory[offset + 2].set(value[2]);
self.memory[offset + 3].set(value[3]);
Ok(())
}
pub fn write_bytes(&self, offset: usize, bytes: &[u8]) -> MResult<()> {
let writer = self.sequential_writer(offset, bytes.len())?;
writer.write_bytes(bytes);
Ok(())
}
pub fn sequential_writer(
&self,
offset: usize,
size: usize,
) -> MResult<SequentialWriter<'_, '_>> {
self.check_access(offset, size)?;
Ok(SequentialWriter::new(&self, offset))
}
pub fn check_access(&self, offset: usize, size: usize) -> MResult<()> {
let right = offset + size;
// the first condition is a check for overflow
if right < offset || right >= self.memory.len() {
return Err(MemoryAccessError::InvalidAccess {
offset,
size,
memory_size: self.memory.len(),
});
}
Ok(())
Ok(SequentialWriter::new(offset))
}
}
impl<'w, 'm> SequentialWriter<'w, 'm> {
pub(super) fn new(writer: &'w MemoryWriter<'m>, offset: usize) -> Self {
let offset = Cell::new(offset);
Self { writer, offset }
impl SequentialWriter {
pub(self) fn new(offset: usize) -> Self {
Self {
offset: Cell::new(offset),
start_offset: offset,
}
}
pub fn write_array<const N: usize>(&self, values: [u8; N]) {
pub fn start_offset(&self) -> usize {
self.start_offset
}
pub fn write_array<T: Heapable, const N: usize>(
&self,
writer: &MemoryWriter<T>,
values: [u8; N],
) {
let offset = self.offset.get();
log::trace!("write array: offset {} {:?}", offset, values);
self.writer.memory[offset..offset + N]
writer.memory.get()[offset..offset + N]
.iter()
.zip(values.iter())
.for_each(|(cell, &byte)| cell.set(byte));
@@ -122,33 +94,35 @@ impl<'w, 'm> SequentialWriter<'w, 'm> {
}
// specialization of write_array for u8
pub fn write_u8(&self, value: u8) {
pub fn write_u8<T: Heapable>(&self, writer: &MemoryWriter<T>, value: u8) {
let offset = self.offset.get();
log::trace!("write_u8: write {} to {}", value, offset);
self.writer.memory[offset].set(value);
writer.memory.get()[offset].set(value);
self.offset.set(offset + 1);
}
// specialization of write_array for u32
pub fn write_u32(&self, value: u32) {
pub fn write_u32<T: Heapable>(&self, writer: &MemoryWriter<T>, value: u32) {
let offset = self.offset.get();
let value = value.to_le_bytes();
self.writer.memory[offset].set(value[0]);
self.writer.memory[offset + 1].set(value[1]);
self.writer.memory[offset + 2].set(value[2]);
self.writer.memory[offset + 3].set(value[3]);
let memory = writer.memory.get();
memory[offset].set(value[0]);
memory[offset + 1].set(value[1]);
memory[offset + 2].set(value[2]);
memory[offset + 3].set(value[3]);
self.offset.set(offset + 4);
}
#[allow(dead_code)]
pub fn write_bytes(&self, bytes: &[u8]) {
pub fn write_bytes<T: Heapable>(&self, writer: &MemoryWriter<T>, bytes: &[u8]) {
let offset = self.offset.get();
self.writer.memory[offset..offset + bytes.len()]
let memory = writer.memory.get();
memory[offset..offset + bytes.len()]
.iter()
.zip(bytes)
.for_each(|(cell, &byte)| cell.set(byte));