mirror of
https://github.com/fluencelabs/interface-types
synced 2024-12-11 02:30:17 +00:00
Rework memory access interface to support non-wasmer environments (#14)
This commit is contained in:
parent
94023f668f
commit
0c5145aa37
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -39,14 +39,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "it-lilo"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"fluence-it-types",
|
||||
"it-memory-traits",
|
||||
"log",
|
||||
"paste",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "it-memory-traits"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "it-to-bytes"
|
||||
version = "0.1.0"
|
||||
@ -272,10 +280,11 @@ checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "wasmer-interface-types-fl"
|
||||
version = "0.20.1"
|
||||
version = "0.21.0"
|
||||
dependencies = [
|
||||
"fluence-it-types",
|
||||
"it-lilo",
|
||||
"it-memory-traits",
|
||||
"it-to-bytes",
|
||||
"itertools",
|
||||
"log",
|
||||
|
@ -3,6 +3,7 @@ members = [
|
||||
"crates/it-lilo",
|
||||
"crates/to-bytes",
|
||||
"crates/it-types",
|
||||
"crates/it-memory-traits",
|
||||
"wasmer-it",
|
||||
]
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "it-lilo"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
authors = ["Fluence Labs"]
|
||||
description = "Defines some helper utils for lifting/lowering IT"
|
||||
edition = "2018"
|
||||
@ -12,6 +12,7 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
fluence-it-types = { path = "../it-types/", version = "0.3.0" }
|
||||
it-memory-traits = { path = "../it-memory-traits", version = "0.1.0" }
|
||||
|
||||
paste = "1.0.5"
|
||||
thiserror = "1.0.24"
|
||||
|
@ -15,18 +15,15 @@
|
||||
*/
|
||||
|
||||
use crate::traits::RecordResolvableError;
|
||||
|
||||
use it_memory_traits::MemoryAccessError;
|
||||
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum LiError {
|
||||
#[error(
|
||||
"Out-of-bound Wasm memory access: offset {offset}, size {size}, while memory_size {memory_size}"
|
||||
)]
|
||||
InvalidAccess {
|
||||
offset: usize,
|
||||
size: usize,
|
||||
memory_size: usize,
|
||||
},
|
||||
#[error("{0}")]
|
||||
MemoryAccessError(#[from] MemoryAccessError),
|
||||
|
||||
#[error("{0}")]
|
||||
RecordResolvableError(#[from] RecordResolvableError),
|
||||
|
@ -22,8 +22,10 @@ use crate::utils::ser_type_size;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
|
||||
pub fn array_lift_memory<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
use it_memory_traits::{SequentialMemoryView, SequentialReader};
|
||||
|
||||
pub fn array_lift_memory<R: RecordResolvable, MV: for<'a> SequentialMemoryView<'a>>(
|
||||
lifter: &ILifter<'_, R, MV>,
|
||||
value_type: &IType,
|
||||
offset: usize,
|
||||
elements_count: usize,
|
||||
@ -59,8 +61,8 @@ pub fn array_lift_memory<R: RecordResolvable>(
|
||||
Ok(IValue::Array(ivalues))
|
||||
}
|
||||
|
||||
fn read_string_array<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
fn read_string_array<R: RecordResolvable, MV: for<'a> SequentialMemoryView<'a>>(
|
||||
lifter: &ILifter<'_, R, MV>,
|
||||
offset: usize,
|
||||
elements_count: usize,
|
||||
) -> LiResult<Vec<IValue>> {
|
||||
@ -81,8 +83,8 @@ fn read_string_array<R: RecordResolvable>(
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn read_array_array<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
fn read_array_array<R: RecordResolvable, MV: for<'a> SequentialMemoryView<'a>>(
|
||||
lifter: &ILifter<'_, R, MV>,
|
||||
ty: &IType,
|
||||
offset: usize,
|
||||
elements_count: usize,
|
||||
@ -103,8 +105,8 @@ fn read_array_array<R: RecordResolvable>(
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn read_record_array<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
fn read_record_array<R: RecordResolvable, MV: for<'a> SequentialMemoryView<'a>>(
|
||||
lifter: &ILifter<'_, R, MV>,
|
||||
record_type_id: u64,
|
||||
offset: usize,
|
||||
elements_count: usize,
|
||||
|
@ -18,7 +18,6 @@ use super::ILifter;
|
||||
use super::LiError;
|
||||
use super::LiResult;
|
||||
use super::MemoryReader;
|
||||
use super::SequentialReader;
|
||||
use crate::traits::RecordResolvable;
|
||||
use crate::utils::record_size;
|
||||
use crate::IRecordType;
|
||||
@ -26,8 +25,10 @@ use crate::IType;
|
||||
use crate::IValue;
|
||||
use crate::NEVec;
|
||||
|
||||
pub fn record_lift_memory<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
use it_memory_traits::{SequentialMemoryView, SequentialReader};
|
||||
|
||||
pub fn record_lift_memory<R: RecordResolvable, MV: for<'a> SequentialMemoryView<'a>>(
|
||||
lifter: &ILifter<'_, R, MV>,
|
||||
record_type: &IRecordType,
|
||||
offset: usize,
|
||||
) -> LiResult<IValue> {
|
||||
@ -67,9 +68,9 @@ pub fn record_lift_memory<R: RecordResolvable>(
|
||||
Ok(IValue::Record(record))
|
||||
}
|
||||
|
||||
fn read_string(
|
||||
reader: &MemoryReader<'_>,
|
||||
seq_reader: &SequentialReader<'_, '_>,
|
||||
fn read_string<MV: for<'a> SequentialMemoryView<'a>>(
|
||||
reader: &MemoryReader<MV>,
|
||||
seq_reader: &<MV as SequentialMemoryView<'_>>::SR,
|
||||
) -> LiResult<String> {
|
||||
let offset = seq_reader.read_u32();
|
||||
let size = seq_reader.read_u32();
|
||||
@ -80,9 +81,9 @@ fn read_string(
|
||||
Ok(string)
|
||||
}
|
||||
|
||||
fn read_byte_array(
|
||||
reader: &MemoryReader<'_>,
|
||||
seq_reader: &SequentialReader<'_, '_>,
|
||||
fn read_byte_array<MV: for<'a> SequentialMemoryView<'a>>(
|
||||
reader: &MemoryReader<MV>,
|
||||
seq_reader: &<MV as SequentialMemoryView<'_>>::SR,
|
||||
) -> LiResult<IValue> {
|
||||
let offset = seq_reader.read_u32();
|
||||
let size = seq_reader.read_u32();
|
||||
@ -92,9 +93,9 @@ fn read_byte_array(
|
||||
Ok(IValue::ByteArray(array))
|
||||
}
|
||||
|
||||
fn read_array<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
seq_reader: &SequentialReader<'_, '_>,
|
||||
fn read_array<R: RecordResolvable, MV: for<'a> SequentialMemoryView<'a>>(
|
||||
lifter: &ILifter<'_, R, MV>,
|
||||
seq_reader: &<MV as SequentialMemoryView<'_>>::SR,
|
||||
value_type: &IType,
|
||||
) -> LiResult<IValue> {
|
||||
let offset = seq_reader.read_u32();
|
||||
@ -103,9 +104,9 @@ fn read_array<R: RecordResolvable>(
|
||||
super::array_lift_memory(lifter, value_type, offset as _, size as _)
|
||||
}
|
||||
|
||||
fn read_record<R: RecordResolvable>(
|
||||
lifter: &ILifter<'_, '_, R>,
|
||||
seq_reader: &SequentialReader<'_, '_>,
|
||||
fn read_record<R: RecordResolvable, MV: for<'a> SequentialMemoryView<'a>>(
|
||||
lifter: &ILifter<'_, R, MV>,
|
||||
seq_reader: &<MV as SequentialMemoryView<'_>>::SR,
|
||||
record_type_id: u64,
|
||||
) -> LiResult<IValue> {
|
||||
let offset = seq_reader.read_u32();
|
||||
|
@ -17,7 +17,7 @@
|
||||
#[macro_export]
|
||||
macro_rules! value_der {
|
||||
($self:expr, $offset:expr, @seq_start $($ids:tt),* @seq_end) => {
|
||||
[$($self.reader.memory[$offset + $ids].get()),+]
|
||||
[$($self.memory.get($offset + $ids)),+]
|
||||
};
|
||||
|
||||
($self:expr, $offset:expr, 1) => {
|
||||
@ -44,7 +44,7 @@ macro_rules! value_der {
|
||||
#[macro_export]
|
||||
macro_rules! read_ty {
|
||||
($func_name:ident, $ty:ty, 1) => {
|
||||
pub fn $func_name(&self) -> $ty {
|
||||
fn $func_name(&self) -> $ty {
|
||||
let offset = self.offset.get();
|
||||
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 1));
|
||||
|
||||
@ -54,7 +54,7 @@ macro_rules! read_ty {
|
||||
};
|
||||
|
||||
($func_name:ident, $ty:ty, 2) => {
|
||||
pub fn $func_name(&self) -> $ty {
|
||||
fn $func_name(&self) -> $ty {
|
||||
let offset = self.offset.get();
|
||||
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 2));
|
||||
|
||||
@ -64,7 +64,7 @@ macro_rules! read_ty {
|
||||
};
|
||||
|
||||
($func_name:ident, $ty:ty, 4) => {
|
||||
pub fn $func_name(&self) -> $ty {
|
||||
fn $func_name(&self) -> $ty {
|
||||
let offset = self.offset.get();
|
||||
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 4));
|
||||
|
||||
@ -74,7 +74,7 @@ macro_rules! read_ty {
|
||||
};
|
||||
|
||||
($func_name:ident, $ty:ty, 8) => {
|
||||
pub fn $func_name(&self) -> $ty {
|
||||
fn $func_name(&self) -> $ty {
|
||||
let offset = self.offset.get();
|
||||
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 8));
|
||||
|
||||
@ -84,7 +84,7 @@ macro_rules! read_ty {
|
||||
};
|
||||
|
||||
($func_name:ident, $ty:ty, 16) => {
|
||||
pub fn $func_name(&self) -> $ty {
|
||||
fn $func_name(&self) -> $ty {
|
||||
let offset = self.offset.get();
|
||||
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 16));
|
||||
|
||||
@ -94,6 +94,29 @@ macro_rules! read_ty {
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! read_ty_decl {
|
||||
($func_name:ident, $ty:ty, 1) => {
|
||||
fn $func_name(&self) -> $ty;
|
||||
};
|
||||
|
||||
($func_name:ident, $ty:ty, 2) => {
|
||||
fn $func_name(&self) -> $ty;
|
||||
};
|
||||
|
||||
($func_name:ident, $ty:ty, 4) => {
|
||||
fn $func_name(&self) -> $ty;
|
||||
};
|
||||
|
||||
($func_name:ident, $ty:ty, 8) => {
|
||||
fn $func_name(&self) -> $ty;
|
||||
};
|
||||
|
||||
($func_name:ident, $ty:ty, 16) => {
|
||||
fn $func_name(&self) -> $ty;
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! read_array_ty {
|
||||
($func_name:ident, $ty:ident, $ity:ident) => {
|
||||
|
@ -14,29 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use super::LiError;
|
||||
use super::LiResult;
|
||||
use crate::read_array_ty;
|
||||
use crate::read_ty;
|
||||
use crate::IValue;
|
||||
|
||||
use std::cell::Cell;
|
||||
use it_memory_traits::{SequentialMemoryView, SequentialReader};
|
||||
|
||||
pub struct MemoryReader<'m> {
|
||||
pub(self) memory: &'m [Cell<u8>],
|
||||
pub struct MemoryReader<MV> {
|
||||
pub(self) view: MV,
|
||||
}
|
||||
|
||||
/// Reads values of basic types sequentially from the provided reader.
|
||||
/// It doesn't check memory limits for the optimization purposes,
|
||||
/// so it could be created only by the MemoryReader::sequential_reader method.
|
||||
pub struct SequentialReader<'r, 'm> {
|
||||
reader: &'r MemoryReader<'m>,
|
||||
offset: Cell<usize>,
|
||||
}
|
||||
|
||||
impl<'m> MemoryReader<'m> {
|
||||
pub fn new(memory: &'m [Cell<u8>]) -> Self {
|
||||
Self { memory }
|
||||
impl<MV: for<'a> SequentialMemoryView<'a>> MemoryReader<MV> {
|
||||
pub fn new(view: MV) -> Self {
|
||||
Self { view }
|
||||
}
|
||||
|
||||
/// Returns reader that allows read sequentially. It's important that memory limit is checked
|
||||
@ -46,10 +36,9 @@ impl<'m> MemoryReader<'m> {
|
||||
&self,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
) -> LiResult<SequentialReader<'_, '_>> {
|
||||
self.check_access(offset, size)?;
|
||||
|
||||
Ok(SequentialReader::new(&self, offset))
|
||||
) -> LiResult<<MV as SequentialMemoryView<'_>>::SR> {
|
||||
let seq_reader = self.view.sequential_reader(offset, size)?;
|
||||
Ok(seq_reader)
|
||||
}
|
||||
|
||||
pub fn read_raw_u8_array(&self, offset: usize, elements_count: usize) -> LiResult<Vec<u8>> {
|
||||
@ -76,21 +65,6 @@ impl<'m> MemoryReader<'m> {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn check_access(&self, offset: usize, size: usize) -> LiResult<()> {
|
||||
let right = offset + size;
|
||||
|
||||
// the first condition is a check for overflow
|
||||
if right < offset || right >= self.memory.len() {
|
||||
return Err(LiError::InvalidAccess {
|
||||
offset,
|
||||
size,
|
||||
memory_size: self.memory.len(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
read_array_ty!(read_u8_array, u8, U8);
|
||||
read_array_ty!(read_s8_array, i8, S8);
|
||||
read_array_ty!(read_u16_array, u16, U16);
|
||||
@ -104,29 +78,3 @@ impl<'m> MemoryReader<'m> {
|
||||
read_array_ty!(read_i64_array, i64, I64);
|
||||
read_array_ty!(read_f64_array, f64, F64);
|
||||
}
|
||||
|
||||
impl<'r, 'm> SequentialReader<'r, 'm> {
|
||||
pub(self) fn new(reader: &'r MemoryReader<'m>, offset: usize) -> Self {
|
||||
let offset = Cell::new(offset);
|
||||
Self { reader, offset }
|
||||
}
|
||||
|
||||
pub fn read_bool(&self) -> bool {
|
||||
let offset = self.offset.get();
|
||||
let result = self.reader.memory[offset].get() != 0;
|
||||
|
||||
self.offset.set(offset + 1);
|
||||
result
|
||||
}
|
||||
|
||||
read_ty!(read_u8, u8, 1);
|
||||
read_ty!(read_i8, i8, 1);
|
||||
read_ty!(read_u16, u16, 2);
|
||||
read_ty!(read_i16, i16, 2);
|
||||
read_ty!(read_u32, u32, 4);
|
||||
read_ty!(read_i32, i32, 4);
|
||||
read_ty!(read_f32, f32, 4);
|
||||
read_ty!(read_u64, u64, 8);
|
||||
read_ty!(read_i64, i64, 8);
|
||||
read_ty!(read_f64, f64, 8);
|
||||
}
|
||||
|
@ -24,22 +24,21 @@ pub use error::LiError;
|
||||
pub use lift_array::array_lift_memory;
|
||||
pub use lift_record::record_lift_memory;
|
||||
pub use memory_reader::MemoryReader;
|
||||
pub use memory_reader::SequentialReader;
|
||||
|
||||
use super::traits::RecordResolvable;
|
||||
|
||||
use std::cell::Cell;
|
||||
pub use it_memory_traits::SequentialMemoryView;
|
||||
|
||||
pub type LiResult<T> = std::result::Result<T, error::LiError>;
|
||||
|
||||
pub struct ILifter<'m, 'r, R: RecordResolvable> {
|
||||
pub reader: MemoryReader<'m>,
|
||||
pub struct ILifter<'r, R: RecordResolvable, MV> {
|
||||
pub reader: MemoryReader<MV>,
|
||||
pub resolver: &'r R,
|
||||
}
|
||||
|
||||
impl<'m, 'r, R: RecordResolvable> ILifter<'m, 'r, R> {
|
||||
pub fn new(memory: &'m [Cell<u8>], resolver: &'r R) -> Self {
|
||||
let reader = MemoryReader::new(memory);
|
||||
impl<'r, R: RecordResolvable, MV: for<'a> SequentialMemoryView<'a>> ILifter<'r, R, MV> {
|
||||
pub fn new(view: MV, resolver: &'r R) -> Self {
|
||||
let reader = MemoryReader::new(view);
|
||||
Self { reader, resolver }
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
use crate::traits::AllocatableError;
|
||||
use crate::traits::RecordResolvableError;
|
||||
use it_memory_traits::MemoryAccessError;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
@ -25,4 +26,7 @@ pub enum LoError {
|
||||
|
||||
#[error("{0}")]
|
||||
RecordResolvableError(#[from] RecordResolvableError),
|
||||
|
||||
#[error("{0}")]
|
||||
MemoryAccessError(#[from] MemoryAccessError),
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ use crate::utils::ser_value_size;
|
||||
use crate::utils::type_tag_form_ivalue;
|
||||
use crate::IValue;
|
||||
|
||||
use it_memory_traits::{SequentialMemoryView, SequentialWriter};
|
||||
|
||||
pub struct LoweredArray {
|
||||
pub offset: usize,
|
||||
pub size: usize,
|
||||
@ -36,8 +38,8 @@ impl LoweredArray {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn array_lower_memory<A: Allocatable>(
|
||||
lowerer: &ILowerer<'_, A>,
|
||||
pub fn array_lower_memory<A: Allocatable, MV: for<'a> SequentialMemoryView<'a>>(
|
||||
lowerer: &ILowerer<'_, A, MV>,
|
||||
array_values: Vec<IValue>,
|
||||
) -> LoResult<LoweredArray> {
|
||||
if array_values.is_empty() {
|
||||
@ -52,40 +54,40 @@ pub fn array_lower_memory<A: Allocatable>(
|
||||
// here it's known that all interface values have the same type
|
||||
for value in array_values {
|
||||
match value {
|
||||
IValue::Boolean(value) => seq_writer.write_u8(&lowerer.writer, value as _),
|
||||
IValue::S8(value) => seq_writer.write_u8(&lowerer.writer, value as _),
|
||||
IValue::S16(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::S32(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::S64(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::U8(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::U16(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::U32(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::U64(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::I32(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::I64(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::F32(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::F64(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()),
|
||||
IValue::Boolean(value) => seq_writer.write_u8(value as _),
|
||||
IValue::S8(value) => seq_writer.write_u8(value as _),
|
||||
IValue::S16(value) => seq_writer.write_bytes(&value.to_le_bytes()),
|
||||
IValue::S32(value) => seq_writer.write_bytes(&value.to_le_bytes()),
|
||||
IValue::S64(value) => seq_writer.write_bytes(&value.to_le_bytes()),
|
||||
IValue::U8(value) => seq_writer.write_bytes(&value.to_le_bytes()),
|
||||
IValue::U16(value) => seq_writer.write_bytes(&value.to_le_bytes()),
|
||||
IValue::U32(value) => seq_writer.write_bytes(&value.to_le_bytes()),
|
||||
IValue::U64(value) => seq_writer.write_bytes(&value.to_le_bytes()),
|
||||
IValue::I32(value) => seq_writer.write_bytes(&value.to_le_bytes()),
|
||||
IValue::I64(value) => seq_writer.write_bytes(&value.to_le_bytes()),
|
||||
IValue::F32(value) => seq_writer.write_bytes(&value.to_le_bytes()),
|
||||
IValue::F64(value) => seq_writer.write_bytes(&value.to_le_bytes()),
|
||||
IValue::String(value) => {
|
||||
let offset = lowerer.writer.write_bytes(value.as_bytes())? as u32;
|
||||
let offset = lowerer.writer.write_bytes(&value.as_bytes())? as u32;
|
||||
|
||||
seq_writer.write_array(&lowerer.writer, offset.to_le_bytes());
|
||||
seq_writer.write_array(&lowerer.writer, (value.len() as u32).to_le_bytes());
|
||||
seq_writer.write_bytes(&offset.to_le_bytes());
|
||||
seq_writer.write_bytes(&(value.len() as u32).to_le_bytes());
|
||||
}
|
||||
IValue::ByteArray(values) => {
|
||||
let offset = lowerer.writer.write_bytes(&values)? as u32;
|
||||
|
||||
seq_writer.write_array(&lowerer.writer, offset.to_le_bytes());
|
||||
seq_writer.write_array(&lowerer.writer, (values.len() as u32).to_le_bytes());
|
||||
seq_writer.write_bytes(&offset.to_le_bytes());
|
||||
seq_writer.write_bytes(&(values.len() as u32).to_le_bytes());
|
||||
}
|
||||
IValue::Array(values) => {
|
||||
let LoweredArray { offset, size } = array_lower_memory(lowerer, values)?;
|
||||
|
||||
seq_writer.write_array(&lowerer.writer, (offset as u32).to_le_bytes());
|
||||
seq_writer.write_array(&lowerer.writer, (size as u32).to_le_bytes());
|
||||
seq_writer.write_bytes(&(offset as u32).to_le_bytes());
|
||||
seq_writer.write_bytes(&(size as u32).to_le_bytes());
|
||||
}
|
||||
IValue::Record(values) => {
|
||||
let offset = super::record_lower_memory(lowerer, values)? as u32;
|
||||
seq_writer.write_array(&lowerer.writer, offset.to_le_bytes());
|
||||
seq_writer.write_bytes(&offset.to_le_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,10 @@ use crate::traits::Allocatable;
|
||||
use crate::IValue;
|
||||
use crate::NEVec;
|
||||
|
||||
pub fn record_lower_memory<A: Allocatable>(
|
||||
lowerer: &ILowerer<'_, A>,
|
||||
use it_memory_traits::SequentialMemoryView;
|
||||
|
||||
pub fn record_lower_memory<A: Allocatable, MV: for<'a> SequentialMemoryView<'a>>(
|
||||
lowerer: &ILowerer<'_, A, MV>,
|
||||
values: NEVec<IValue>,
|
||||
) -> LoResult<i32> {
|
||||
let average_field_size = 4;
|
||||
|
@ -16,113 +16,36 @@
|
||||
|
||||
use super::LoResult;
|
||||
use crate::traits::Allocatable;
|
||||
use crate::traits::MemSlice;
|
||||
use crate::traits::DEFAULT_MEMORY_INDEX;
|
||||
use crate::utils::type_tag_form_itype;
|
||||
|
||||
use std::cell::Cell;
|
||||
use it_memory_traits::{SequentialMemoryView, SequentialWriter};
|
||||
|
||||
pub struct MemoryWriter<'i, R: Allocatable> {
|
||||
pub struct MemoryWriter<'i, R: Allocatable, MV> {
|
||||
heap_manager: &'i R,
|
||||
pub(self) memory: Cell<MemSlice<'i>>,
|
||||
view: MV,
|
||||
}
|
||||
|
||||
pub struct SequentialWriter {
|
||||
start_offset: usize,
|
||||
offset: Cell<usize>,
|
||||
}
|
||||
|
||||
impl<'i, A: Allocatable> MemoryWriter<'i, A> {
|
||||
pub fn new(heap_manager: &'i A) -> LoResult<Self> {
|
||||
let mem_slice = heap_manager.memory_slice(DEFAULT_MEMORY_INDEX)?;
|
||||
let memory = Cell::new(mem_slice);
|
||||
|
||||
let writer = Self {
|
||||
heap_manager,
|
||||
memory,
|
||||
};
|
||||
impl<'i, A: Allocatable, MV: for<'a> SequentialMemoryView<'a>> MemoryWriter<'i, A, MV> {
|
||||
pub fn new(view: MV, heap_manager: &'i A) -> LoResult<Self> {
|
||||
let writer = Self { heap_manager, view };
|
||||
Ok(writer)
|
||||
}
|
||||
|
||||
pub fn write_bytes(&self, bytes: &[u8]) -> LoResult<usize> {
|
||||
let byte_type_tag = 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);
|
||||
seq_writer.write_bytes(bytes);
|
||||
|
||||
Ok(seq_writer.start_offset())
|
||||
}
|
||||
|
||||
pub fn sequential_writer(&self, size: u32, type_tag: u32) -> LoResult<SequentialWriter> {
|
||||
let offset = self.heap_manager.allocate(size, type_tag)?;
|
||||
|
||||
let new_mem_slice = self.heap_manager.memory_slice(DEFAULT_MEMORY_INDEX)?;
|
||||
self.memory.set(new_mem_slice);
|
||||
|
||||
Ok(SequentialWriter::new(offset))
|
||||
}
|
||||
}
|
||||
|
||||
impl SequentialWriter {
|
||||
pub(self) fn new(offset: usize) -> Self {
|
||||
Self {
|
||||
offset: Cell::new(offset),
|
||||
start_offset: offset,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_offset(&self) -> usize {
|
||||
self.start_offset
|
||||
}
|
||||
|
||||
pub fn write_array<A: Allocatable, const N: usize>(
|
||||
pub fn sequential_writer(
|
||||
&self,
|
||||
writer: &MemoryWriter<'_, A>,
|
||||
values: [u8; N],
|
||||
) {
|
||||
let offset = self.offset.get();
|
||||
|
||||
writer.memory.get()[offset..offset + N]
|
||||
.iter()
|
||||
.zip(values.iter())
|
||||
.for_each(|(cell, &byte)| cell.set(byte));
|
||||
|
||||
self.offset.set(offset + N);
|
||||
}
|
||||
|
||||
// specialization of write_array for u8
|
||||
pub fn write_u8<A: Allocatable>(&self, writer: &MemoryWriter<'_, A>, value: u8) {
|
||||
let offset = self.offset.get();
|
||||
|
||||
writer.memory.get()[offset].set(value);
|
||||
|
||||
self.offset.set(offset + 1);
|
||||
}
|
||||
|
||||
// specialization of write_array for u32
|
||||
pub fn write_u32<A: Allocatable>(&self, writer: &MemoryWriter<'_, A>, value: u32) {
|
||||
let offset = self.offset.get();
|
||||
|
||||
let value = value.to_le_bytes();
|
||||
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<A: Allocatable>(&self, writer: &MemoryWriter<'_, A>, bytes: &[u8]) {
|
||||
let offset = self.offset.get();
|
||||
|
||||
let memory = writer.memory.get();
|
||||
memory[offset..offset + bytes.len()]
|
||||
.iter()
|
||||
.zip(bytes)
|
||||
.for_each(|(cell, &byte)| cell.set(byte));
|
||||
|
||||
self.offset.set(offset + bytes.len());
|
||||
size: u32,
|
||||
type_tag: u32,
|
||||
) -> LoResult<<MV as SequentialMemoryView<'_>>::SW> {
|
||||
let offset = self.heap_manager.allocate(size, type_tag)?;
|
||||
let seq_writer = self.view.sequential_writer(offset, size as usize)?;
|
||||
Ok(seq_writer)
|
||||
}
|
||||
}
|
||||
|
@ -27,15 +27,17 @@ pub use lower_array::array_lower_memory;
|
||||
pub use lower_array::LoweredArray;
|
||||
pub use lower_record::record_lower_memory;
|
||||
|
||||
pub use it_memory_traits::SequentialMemoryView;
|
||||
|
||||
pub type LoResult<T> = std::result::Result<T, error::LoError>;
|
||||
|
||||
pub struct ILowerer<'m, A: Allocatable> {
|
||||
pub writer: MemoryWriter<'m, A>,
|
||||
pub struct ILowerer<'m, A: Allocatable, MV> {
|
||||
pub writer: MemoryWriter<'m, A, MV>,
|
||||
}
|
||||
|
||||
impl<'m, A: Allocatable> ILowerer<'m, A> {
|
||||
pub fn new(allocatable: &'m A) -> LoResult<Self> {
|
||||
let writer = MemoryWriter::new(allocatable)?;
|
||||
impl<'m, A: Allocatable, MV: for<'a> SequentialMemoryView<'a>> ILowerer<'m, A, MV> {
|
||||
pub fn new(view: MV, allocatable: &'m A) -> LoResult<Self> {
|
||||
let writer = MemoryWriter::new(view, allocatable)?;
|
||||
let lowerer = Self { writer };
|
||||
|
||||
Ok(lowerer)
|
||||
|
@ -14,17 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use std::cell::Cell;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
pub const DEFAULT_MEMORY_INDEX: usize = 0;
|
||||
|
||||
pub type MemSlice<'m> = &'m [Cell<u8>];
|
||||
|
||||
pub trait Allocatable {
|
||||
fn allocate(&self, size: u32, type_tag: u32) -> Result<usize, AllocatableError>;
|
||||
|
||||
fn memory_slice(&self, memory_index: usize) -> Result<MemSlice<'_>, AllocatableError>;
|
||||
}
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
|
@ -26,4 +26,7 @@ pub enum RecordResolvableError {
|
||||
/// Record for such type is wasn't found.
|
||||
#[error("Record with type id '{0}' not found")]
|
||||
RecordNotFound(u64),
|
||||
|
||||
#[error("Memory with index '{memory_index}' not found")]
|
||||
MemoryIsMissing { memory_index: usize },
|
||||
}
|
||||
|
14
crates/it-memory-traits/Cargo.toml
Normal file
14
crates/it-memory-traits/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "it-memory-traits"
|
||||
version = "0.1.0"
|
||||
authors = ["Fluence Labs"]
|
||||
description = "Defines traits that IT uses for accessing memory"
|
||||
edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[lib]
|
||||
name = "it_memory_traits"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.24"
|
27
crates/it-memory-traits/src/errors.rs
Normal file
27
crates/it-memory-traits/src/errors.rs
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2022 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum MemoryAccessError {
|
||||
#[error("Out-of-bound Wasm memory access: offset {offset}, size {size}, while memory_size {memory_size}")]
|
||||
OutOfBounds {
|
||||
offset: usize,
|
||||
size: usize,
|
||||
memory_size: usize,
|
||||
},
|
||||
}
|
86
crates/it-memory-traits/src/lib.rs
Normal file
86
crates/it-memory-traits/src/lib.rs
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2022 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
mod errors;
|
||||
|
||||
pub use errors::MemoryAccessError;
|
||||
|
||||
macro_rules! read_ty {
|
||||
($func_name:ident, $ty:ty, $size:literal) => {
|
||||
fn $func_name(&self) -> $ty {
|
||||
<$ty>::from_le_bytes(self.read_bytes::<$size>())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub trait SequentialReader {
|
||||
fn read_byte(&self) -> u8;
|
||||
|
||||
fn read_bytes<const COUNT: usize>(&self) -> [u8; COUNT];
|
||||
|
||||
fn read_bool(&self) -> bool {
|
||||
self.read_byte() != 0
|
||||
}
|
||||
|
||||
read_ty!(read_u8, u8, 1);
|
||||
read_ty!(read_i8, i8, 1);
|
||||
read_ty!(read_u16, u16, 2);
|
||||
read_ty!(read_i16, i16, 2);
|
||||
read_ty!(read_u32, u32, 4);
|
||||
read_ty!(read_i32, i32, 4);
|
||||
read_ty!(read_f32, f32, 4);
|
||||
read_ty!(read_u64, u64, 8);
|
||||
read_ty!(read_i64, i64, 8);
|
||||
read_ty!(read_f64, f64, 8);
|
||||
}
|
||||
|
||||
pub trait SequentialWriter {
|
||||
fn start_offset(&self) -> usize;
|
||||
|
||||
// specialization of write_array for u8
|
||||
fn write_u8(&self, value: u8);
|
||||
|
||||
// specialization of write_array for u32
|
||||
fn write_u32(&self, value: u32);
|
||||
|
||||
fn write_bytes(&self, bytes: &[u8]);
|
||||
}
|
||||
|
||||
// the lifetime is needed because some implementations
|
||||
// need to bind SR and SW lifetimes to lifetime of &self in methods
|
||||
pub trait SequentialMemoryView<'s> {
|
||||
type SR: SequentialReader + 's;
|
||||
type SW: SequentialWriter + 's;
|
||||
|
||||
fn sequential_writer(
|
||||
&'s self,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
) -> Result<Self::SW, MemoryAccessError>;
|
||||
|
||||
fn sequential_reader(
|
||||
&'s self,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
) -> Result<Self::SR, MemoryAccessError>;
|
||||
}
|
||||
|
||||
pub trait Memory<View>
|
||||
where
|
||||
View: for<'a> SequentialMemoryView<'a>,
|
||||
{
|
||||
fn view(&self) -> View;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasmer-interface-types-fl"
|
||||
version = "0.20.2"
|
||||
version = "0.21.0"
|
||||
description = "WebAssembly Interface Types library for Wasmer"
|
||||
license = "MIT"
|
||||
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
|
||||
@ -10,7 +10,8 @@ edition = "2018"
|
||||
[dependencies]
|
||||
fluence-it-types = { path = "../crates/it-types", version = "0.3.1", features = ["impls"] }
|
||||
it-to-bytes = { path = "../crates/to-bytes", version = "0.1.0" }
|
||||
it-lilo = { path = "../crates/it-lilo", version = "0.1.0" }
|
||||
it-lilo = { path = "../crates/it-lilo", version = "0.2.0" }
|
||||
it-memory-traits = { path = "../crates/it-memory-traits", version = "0.1.0" }
|
||||
|
||||
nom = "5.1"
|
||||
wast = "8.0"
|
||||
|
@ -17,6 +17,7 @@ use it_lilo::lowerer::LoError;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
pub use fluence_it_types::WasmValueNativeCastError;
|
||||
use it_memory_traits::MemoryAccessError;
|
||||
|
||||
/// A type alias for instruction's results.
|
||||
pub type InstructionResult<T> = Result<T, InstructionError>;
|
||||
@ -54,6 +55,25 @@ impl InstructionError {
|
||||
let error_kind = InstructionErrorKind::LoError(lo);
|
||||
Self::from_error_kind(instruction, error_kind)
|
||||
}
|
||||
|
||||
pub(crate) fn from_memory_access(
|
||||
instruction: Instruction,
|
||||
memory_access: MemoryAccessError,
|
||||
) -> Self {
|
||||
match memory_access {
|
||||
MemoryAccessError::OutOfBounds {
|
||||
offset,
|
||||
size,
|
||||
memory_size,
|
||||
} => Self::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryOutOfBoundsAccess {
|
||||
index: offset + size,
|
||||
length: memory_size,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for InstructionError {}
|
||||
|
@ -10,20 +10,21 @@ use crate::{
|
||||
use it_lilo::lifter::ILifter;
|
||||
use it_lilo::lowerer::ILowerer;
|
||||
use it_lilo::lowerer::LoweredArray;
|
||||
use it_lilo::traits::DEFAULT_MEMORY_INDEX;
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub(crate) fn array_lift_memory<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
pub(crate) fn array_lift_memory<Instance, Export, LocalImport, Memory, SequentialMemoryView>(
|
||||
instruction: Instruction,
|
||||
value_type: IType,
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<SequentialMemoryView>,
|
||||
SequentialMemoryView: for<'a> crate::interpreter::wasm::structures::SequentialMemoryView<'a>,
|
||||
Instance:
|
||||
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
@ -55,7 +56,7 @@ where
|
||||
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
|
||||
let memory_index = 0;
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory_view = instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
@ -65,10 +66,9 @@ where
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
let memory = memory_view.deref();
|
||||
|
||||
let li_helper = lilo::LiHelper::new(&**instance);
|
||||
let lifter = ILifter::new(memory, &li_helper);
|
||||
let lifter = ILifter::new(memory_view, &li_helper);
|
||||
let array =
|
||||
it_lilo::lifter::array_lift_memory(&lifter, &value_type, offset as _, size as _)
|
||||
.map_err(|e| InstructionError::from_li(instruction.clone(), e))?;
|
||||
@ -81,17 +81,17 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn array_lower_memory<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
pub(crate) fn array_lower_memory<Instance, Export, LocalImport, Memory, SequentialMemoryView>(
|
||||
instruction: Instruction,
|
||||
value_type: IType,
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<SequentialMemoryView>,
|
||||
SequentialMemoryView: for<'a> crate::interpreter::wasm::structures::SequentialMemoryView<'a>,
|
||||
Instance:
|
||||
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
@ -115,9 +115,19 @@ where
|
||||
InstructionError::from_error_kind(instruction.clone(), e)
|
||||
})?;
|
||||
}
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory_view = instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
|
||||
let lo_helper = lilo::LoHelper::new(&**instance);
|
||||
let lowerer = ILowerer::new(&lo_helper)
|
||||
let lowerer = ILowerer::new(memory_view, &lo_helper)
|
||||
.map_err(|e| InstructionError::from_lo(instruction.clone(), e))?;
|
||||
|
||||
let LoweredArray { offset, size } =
|
||||
@ -136,7 +146,18 @@ where
|
||||
}
|
||||
IValue::ByteArray(bytearray) => {
|
||||
let lo_helper = lilo::LoHelper::new(&**instance);
|
||||
let lowerer = ILowerer::new(&lo_helper)
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory_view = instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
|
||||
let lowerer = ILowerer::new(memory_view, &lo_helper)
|
||||
.map_err(|e| InstructionError::from_lo(instruction.clone(), e))?;
|
||||
|
||||
let offset = lowerer
|
||||
|
@ -7,7 +7,10 @@ use crate::{
|
||||
interpreter::Instruction,
|
||||
};
|
||||
|
||||
use std::{cell::Cell, convert::TryInto};
|
||||
use it_memory_traits::{SequentialReader, SequentialWriter};
|
||||
use it_lilo::traits::DEFAULT_MEMORY_INDEX;
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
executable_instruction!(
|
||||
byte_array_lift_memory(instruction: Instruction) -> _ {
|
||||
@ -19,7 +22,7 @@ executable_instruction!(
|
||||
)
|
||||
})?;
|
||||
|
||||
let memory_index = 0;
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory = runtime
|
||||
.wasm_instance
|
||||
.memory(memory_index)
|
||||
@ -47,20 +50,14 @@ executable_instruction!(
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
if memory_view.len() < pointer + length {
|
||||
return instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryOutOfBoundsAccess {
|
||||
index: pointer + length,
|
||||
length: memory_view.len(),
|
||||
}
|
||||
);
|
||||
}
|
||||
let reader = memory_view
|
||||
.sequential_reader(pointer, length)
|
||||
.map_err(|e| InstructionError::from_memory_access(instruction.clone(), e))?;
|
||||
|
||||
let data: Vec<u8> = (&memory_view[pointer..pointer + length])
|
||||
.iter()
|
||||
.map(Cell::get)
|
||||
.collect();
|
||||
let mut data = Vec::<u8>::with_capacity(length);
|
||||
for index in 0..length {
|
||||
data[index] = reader.read_u8();
|
||||
}
|
||||
|
||||
log::debug!("byte_array.lift_memory: pushing {:?} on the stack", data);
|
||||
runtime.stack.push(IValue::ByteArray(data));
|
||||
@ -93,7 +90,7 @@ executable_instruction!(
|
||||
})?;
|
||||
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let memory_index = 0;
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory_view = instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
@ -104,9 +101,11 @@ executable_instruction!(
|
||||
})?
|
||||
.view();
|
||||
|
||||
for (nth, byte) in array.iter().enumerate() {
|
||||
memory_view[array_pointer as usize + nth].set(*byte);
|
||||
}
|
||||
let writer = memory_view
|
||||
.sequential_writer(array_pointer, array.len())
|
||||
.map_err(|e| InstructionError::from_memory_access(instruction.clone(), e))?;
|
||||
|
||||
writer.write_bytes(&array);
|
||||
|
||||
log::debug!("string.lower_memory: pushing {}, {} on the stack", array_pointer, length);
|
||||
runtime.stack.push(IValue::I32(array_pointer as i32));
|
||||
|
@ -6,29 +6,29 @@ use it_lilo::traits::RecordResolvableError;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct LiHelper<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
pub struct LiHelper<'i, Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'i,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
Memory: wasm::structures::Memory<SequentialMemoryView> + 'i,
|
||||
SequentialMemoryView: (for<'a> wasm::structures::SequentialMemoryView<'a>) + 'i,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
pub(crate) instance: &'i Instance,
|
||||
_export: PhantomData<Export>,
|
||||
_local_import: PhantomData<LocalImport>,
|
||||
_memory: PhantomData<Memory>,
|
||||
_memory_view: PhantomData<MemoryView>,
|
||||
_memory_view: PhantomData<SequentialMemoryView>,
|
||||
}
|
||||
|
||||
impl<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
LiHelper<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
impl<'i, Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
LiHelper<'i, Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'i,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
Memory: wasm::structures::Memory<SequentialMemoryView> + 'i,
|
||||
SequentialMemoryView: (for<'a> wasm::structures::SequentialMemoryView<'a>),
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
pub(crate) fn new(instance: &'i Instance) -> Self {
|
||||
Self {
|
||||
@ -41,14 +41,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'i, Instance, Export, LocalImport, Memory, MemoryView> RecordResolvable
|
||||
for LiHelper<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
impl<'i, Instance, Export, LocalImport, Memory, SequentialMemoryView> RecordResolvable
|
||||
for LiHelper<'i, Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'i,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
Memory: wasm::structures::Memory<SequentialMemoryView> + 'i,
|
||||
SequentialMemoryView: (for<'a> wasm::structures::SequentialMemoryView<'a>),
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
fn resolve_record(&self, record_type_id: u64) -> Result<&IRecordType, RecordResolvableError> {
|
||||
let record = self
|
||||
|
@ -4,33 +4,32 @@ use crate::IValue;
|
||||
|
||||
use it_lilo::traits::Allocatable;
|
||||
use it_lilo::traits::AllocatableError;
|
||||
use it_lilo::traits::MemSlice;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
pub struct LoHelper<'i, Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'i,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
Memory: wasm::structures::Memory<SequentialMemoryView> + 'i,
|
||||
SequentialMemoryView: (for<'a> wasm::structures::SequentialMemoryView<'a>),
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
pub(crate) instance: &'i Instance,
|
||||
_export: PhantomData<Export>,
|
||||
_local_import: PhantomData<LocalImport>,
|
||||
_memory: PhantomData<Memory>,
|
||||
_memory_view: PhantomData<MemoryView>,
|
||||
_memory_view: PhantomData<SequentialMemoryView>,
|
||||
}
|
||||
|
||||
impl<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
impl<'i, Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
LoHelper<'i, Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'i,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
Memory: wasm::structures::Memory<SequentialMemoryView> + 'i,
|
||||
SequentialMemoryView: (for<'a> wasm::structures::SequentialMemoryView<'a>),
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
pub(crate) fn new(instance: &'i Instance) -> Self {
|
||||
Self {
|
||||
@ -43,14 +42,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'i, Instance, Export, LocalImport, Memory, MemoryView> Allocatable
|
||||
for LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
impl<'i, Instance, Export, LocalImport, Memory, SequentialMemoryView> Allocatable
|
||||
for LoHelper<'i, Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export + 'i,
|
||||
LocalImport: wasm::structures::LocalImport + 'i,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'i,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
Memory: wasm::structures::Memory<SequentialMemoryView> + 'i,
|
||||
SequentialMemoryView: (for<'a> wasm::structures::SequentialMemoryView<'a>),
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
fn allocate(&self, size: u32, type_tag: u32) -> Result<usize, AllocatableError> {
|
||||
use AllocatableError::*;
|
||||
@ -88,10 +87,4 @@ where
|
||||
_ => Err(AllocateFuncIncompatibleOutput),
|
||||
}
|
||||
}
|
||||
|
||||
fn memory_slice(&self, memory_index: usize) -> Result<MemSlice<'_>, AllocatableError> {
|
||||
self.instance
|
||||
.memory_slice(memory_index)
|
||||
.ok_or(AllocatableError::MemoryIsMissing { memory_index })
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ pub(crate) fn check_function_signature<
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
SequentialMemoryView,
|
||||
>(
|
||||
instance: &'instance Instance,
|
||||
local_import: &LocalImport,
|
||||
@ -241,9 +241,9 @@ pub(crate) fn check_function_signature<
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'instance,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
Memory: wasm::structures::Memory<SequentialMemoryView> + 'instance,
|
||||
SequentialMemoryView: (for<'a> wasm::structures::SequentialMemoryView<'a>),
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
let func_inputs = local_import.arguments();
|
||||
|
||||
@ -261,7 +261,7 @@ pub(crate) fn is_value_compatible_to_type<
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
SequentialMemoryView,
|
||||
>(
|
||||
instance: &'instance Instance,
|
||||
interface_type: &IType,
|
||||
@ -270,9 +270,9 @@ pub(crate) fn is_value_compatible_to_type<
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'instance,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
Memory: wasm::structures::Memory<SequentialMemoryView> + 'instance,
|
||||
SequentialMemoryView: (for<'a> wasm::structures::SequentialMemoryView<'a>),
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
match (&interface_type, interface_value) {
|
||||
(IType::Boolean, IValue::Boolean(_)) => Ok(()),
|
||||
@ -332,7 +332,7 @@ pub(crate) fn is_record_fields_compatible_to_type<
|
||||
Export,
|
||||
LocalImport,
|
||||
Memory,
|
||||
MemoryView,
|
||||
SequentialMemoryView,
|
||||
>(
|
||||
instance: &'instance Instance,
|
||||
record_type_id: u64,
|
||||
@ -341,9 +341,9 @@ pub(crate) fn is_record_fields_compatible_to_type<
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'instance,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
Memory: wasm::structures::Memory<SequentialMemoryView> + 'instance,
|
||||
SequentialMemoryView: (for<'a> wasm::structures::SequentialMemoryView<'a>),
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
let record_type = instance
|
||||
.wit_record_by_id(record_type_id)
|
||||
@ -428,11 +428,11 @@ pub(crate) mod tests {
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub(crate) struct MemoryView(Rc<Vec<Cell<u8>>>);
|
||||
pub(crate) struct SequentialMemoryView(Rc<Vec<Cell<u8>>>);
|
||||
|
||||
impl wasm::structures::MemoryView for MemoryView {}
|
||||
impl wasm::structures::SequentialMemoryView for SequentialMemoryView {}
|
||||
|
||||
impl Deref for MemoryView {
|
||||
impl Deref for SequentialMemoryView {
|
||||
type Target = [Cell<u8>];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
@ -442,19 +442,19 @@ pub(crate) mod tests {
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Memory {
|
||||
pub(crate) view: MemoryView,
|
||||
pub(crate) view: SequentialMemoryView,
|
||||
}
|
||||
|
||||
impl Memory {
|
||||
pub(crate) fn new(data: Vec<Cell<u8>>) -> Self {
|
||||
Self {
|
||||
view: MemoryView(Rc::new(data)),
|
||||
view: SequentialMemoryView(Rc::new(data)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl wasm::structures::Memory<MemoryView> for Memory {
|
||||
fn view(&self) -> MemoryView {
|
||||
impl wasm::structures::Memory<SequentialMemoryView> for Memory {
|
||||
fn view(&self) -> SequentialMemoryView {
|
||||
self.view.clone()
|
||||
}
|
||||
}
|
||||
@ -554,7 +554,7 @@ pub(crate) mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
impl wasm::structures::Instance<Export, LocalImport, Memory, MemoryView> for Instance {
|
||||
impl wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView> for Instance {
|
||||
fn export(&self, export_name: &str) -> Option<&Export> {
|
||||
self.exports.get(export_name)
|
||||
}
|
||||
|
@ -7,20 +7,21 @@ use crate::{errors::InstructionError, errors::InstructionErrorKind, interpreter:
|
||||
|
||||
use it_lilo::lifter::ILifter;
|
||||
use it_lilo::lowerer::ILowerer;
|
||||
use it_lilo::traits::DEFAULT_MEMORY_INDEX;
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub(crate) fn record_lift_memory<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
pub(crate) fn record_lift_memory<Instance, Export, LocalImport, Memory, SequentialMemoryView>(
|
||||
record_type_id: u64,
|
||||
instruction: Instruction,
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<SequentialMemoryView>,
|
||||
SequentialMemoryView: for<'a> crate::interpreter::wasm::structures::SequentialMemoryView<'a>,
|
||||
Instance:
|
||||
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
@ -53,7 +54,7 @@ where
|
||||
record_type_id
|
||||
);
|
||||
|
||||
let memory_index = 0;
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory_view = instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
@ -63,10 +64,9 @@ where
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
let memory = memory_view.deref();
|
||||
|
||||
let li_helper = lilo::LiHelper::new(&**instance);
|
||||
let lifter = ILifter::new(memory, &li_helper);
|
||||
let lifter = ILifter::new(memory_view, &li_helper);
|
||||
let record = it_lilo::lifter::record_lift_memory(&lifter, record_type, offset)
|
||||
.map_err(|e| InstructionError::from_li(instruction.clone(), e))?;
|
||||
|
||||
@ -78,17 +78,17 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn record_lower_memory<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
pub(crate) fn record_lower_memory<Instance, Export, LocalImport, Memory, SequentialMemoryView>(
|
||||
record_type_id: u64,
|
||||
instruction: Instruction,
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<SequentialMemoryView>,
|
||||
SequentialMemoryView: for<'a> crate::interpreter::wasm::structures::SequentialMemoryView<'a>,
|
||||
Instance:
|
||||
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
@ -107,8 +107,19 @@ where
|
||||
|
||||
log::debug!("record.lower_memory: obtained {:?} values on the stack for record type = {}", record_fields, record_type_id);
|
||||
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory_view = instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::from_error_kind(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
|
||||
let lo_helper = lilo::LoHelper::new(&**instance);
|
||||
let memory_writer = ILowerer::new(&lo_helper)
|
||||
let memory_writer = ILowerer::new(memory_view, &lo_helper)
|
||||
.map_err(|e| InstructionError::from_lo(instruction.clone(), e))?;
|
||||
let offset =
|
||||
it_lilo::lowerer::record_lower_memory(&memory_writer, record_fields)
|
||||
|
@ -7,7 +7,10 @@ use crate::{
|
||||
interpreter::Instruction,
|
||||
};
|
||||
|
||||
use std::{cell::Cell, convert::TryInto};
|
||||
use it_memory_traits::{SequentialReader, SequentialWriter};
|
||||
use it_lilo::traits::DEFAULT_MEMORY_INDEX;
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
executable_instruction!(
|
||||
string_lift_memory(instruction: Instruction) -> _ {
|
||||
@ -19,7 +22,7 @@ executable_instruction!(
|
||||
)
|
||||
})?;
|
||||
|
||||
let memory_index = 0;
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory = runtime
|
||||
.wasm_instance
|
||||
.memory(memory_index)
|
||||
@ -46,20 +49,14 @@ executable_instruction!(
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
if memory_view.len() < pointer + length {
|
||||
return instr_error!(
|
||||
instruction.clone(),
|
||||
InstructionErrorKind::MemoryOutOfBoundsAccess {
|
||||
index: pointer + length,
|
||||
length: memory_view.len(),
|
||||
}
|
||||
);
|
||||
}
|
||||
let reader = memory_view
|
||||
.sequential_reader(pointer, length)
|
||||
.map_err(|e| InstructionError::from_memory_access(instruction.clone(), e))?;
|
||||
|
||||
let data: Vec<u8> = (&memory_view[pointer..pointer + length])
|
||||
.iter()
|
||||
.map(Cell::get)
|
||||
.collect();
|
||||
let mut data = Vec::<u8>::with_capacity(length);
|
||||
for index in 0..length {
|
||||
data[index] = reader.read_u8();
|
||||
}
|
||||
|
||||
let string = String::from_utf8(data)
|
||||
.map_err(|error| InstructionError::from_error_kind(instruction.clone(), InstructionErrorKind::String(error)))?;
|
||||
@ -96,7 +93,7 @@ executable_instruction!(
|
||||
})?;
|
||||
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let memory_index = 0;
|
||||
let memory_index = DEFAULT_MEMORY_INDEX;
|
||||
let memory_view = instance
|
||||
.memory(memory_index)
|
||||
.ok_or_else(|| {
|
||||
@ -107,9 +104,11 @@ executable_instruction!(
|
||||
})?
|
||||
.view();
|
||||
|
||||
for (nth, byte) in string_bytes.iter().enumerate() {
|
||||
memory_view[string_pointer as usize + nth].set(*byte);
|
||||
}
|
||||
let seq_writer = memory_view
|
||||
.sequential_writer(string_pointer, string_length as usize)
|
||||
.map_err(|e| InstructionError::from_memory_access(instruction.clone(), e))?;
|
||||
|
||||
seq_writer.write_bytes(&string_bytes);
|
||||
|
||||
log::debug!("string.lower_memory: pushing {}, {} on the stack", string_pointer, string_length);
|
||||
runtime.stack.push(IValue::I32(string_pointer as i32));
|
||||
|
@ -13,13 +13,13 @@ use std::{convert::TryFrom, marker::PhantomData};
|
||||
|
||||
/// Represents the `Runtime`, which is used by an adapter to execute
|
||||
/// its instructions.
|
||||
pub(crate) struct Runtime<'invocation, 'instance, Instance, Export, LocalImport, Memory, MemoryView>
|
||||
pub(crate) struct Runtime<'invocation, 'instance, Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'instance,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView> + 'instance,
|
||||
Memory: wasm::structures::Memory<SequentialMemoryView> + 'instance,
|
||||
SequentialMemoryView: (for<'a> wasm::structures::SequentialMemoryView<'a>),
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView> + 'instance,
|
||||
{
|
||||
/// The invocation inputs are all the arguments received by an
|
||||
/// adapter.
|
||||
@ -33,13 +33,13 @@ where
|
||||
wasm_instance: &'instance mut Instance,
|
||||
|
||||
/// Phantom data.
|
||||
_phantom: PhantomData<(Export, LocalImport, Memory, MemoryView)>,
|
||||
_phantom: PhantomData<(Export, LocalImport, Memory, SequentialMemoryView)>,
|
||||
}
|
||||
|
||||
/// Type alias for an executable instruction. It's an implementation
|
||||
/// details, but an instruction is a boxed closure instance.
|
||||
pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView> = Box<
|
||||
dyn Fn(&mut Runtime<Instance, Export, LocalImport, Memory, MemoryView>) -> InstructionResult<()>
|
||||
pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, SequentialMemoryView> = Box<
|
||||
dyn Fn(&mut Runtime<Instance, Export, LocalImport, Memory, SequentialMemoryView>) -> InstructionResult<()>
|
||||
+ Send,
|
||||
>;
|
||||
|
||||
@ -61,7 +61,7 @@ pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, Mem
|
||||
/// use std::{cell::Cell, collections::HashMap, convert::TryInto};
|
||||
/// use wasmer_interface_types::{
|
||||
/// interpreter::{
|
||||
/// instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView},
|
||||
/// instructions::tests::{Export, Instance, LocalImport, Memory, SequentialMemoryView},
|
||||
/// // ^^^^^^^^^^^^ This is private and for testing purposes only.
|
||||
/// // It is basically a fake WebAssembly runtime.
|
||||
/// stack::Stackable,
|
||||
@ -73,7 +73,7 @@ pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, Mem
|
||||
///
|
||||
/// // 1. Creates an interpreter from a set of instructions. They will
|
||||
/// // be transformed into executable instructions.
|
||||
/// let interpreter: Interpreter<Instance, Export, LocalImport, Memory, MemoryView> = (&vec![
|
||||
/// let interpreter: Interpreter<Instance, Export, LocalImport, Memory, SequentialMemoryView> = (&vec![
|
||||
/// Instruction::ArgumentGet { index: 1 },
|
||||
/// Instruction::ArgumentGet { index: 0 },
|
||||
/// Instruction::CallCore { function_index: 42 },
|
||||
@ -121,31 +121,31 @@ pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, Mem
|
||||
/// // 5. Read the stack to get the result.
|
||||
/// assert_eq!(stack.as_slice(), &[IValue::I32(7)]);
|
||||
/// ```
|
||||
pub struct Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
pub struct Interpreter<Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export,
|
||||
LocalImport: wasm::structures::LocalImport,
|
||||
Memory: wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
Memory: wasm::structures::Memory<SequentialMemoryView>,
|
||||
SequentialMemoryView: (for<'a> wasm::structures::SequentialMemoryView<'a>),
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
executable_instructions:
|
||||
Vec<ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>>,
|
||||
Vec<ExecutableInstruction<Instance, Export, LocalImport, Memory, SequentialMemoryView>>,
|
||||
}
|
||||
|
||||
impl<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
impl<Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
Interpreter<Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export,
|
||||
LocalImport: wasm::structures::LocalImport,
|
||||
Memory: wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
Memory: wasm::structures::Memory<SequentialMemoryView>,
|
||||
SequentialMemoryView: (for<'a> wasm::structures::SequentialMemoryView<'a>),
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
fn iter(
|
||||
&self,
|
||||
) -> impl Iterator<
|
||||
Item = &ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>,
|
||||
Item = &ExecutableInstruction<Instance, Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
> + '_ {
|
||||
self.executable_instructions.iter()
|
||||
}
|
||||
@ -176,14 +176,14 @@ where
|
||||
}
|
||||
|
||||
/// Transforms a `Vec<Instruction>` into an `Interpreter`.
|
||||
impl<Instance, Export, LocalImport, Memory, MemoryView> TryFrom<Vec<Instruction>>
|
||||
for Interpreter<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
impl<Instance, Export, LocalImport, Memory, SequentialMemoryView> TryFrom<Vec<Instruction>>
|
||||
for Interpreter<Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: wasm::structures::Export,
|
||||
LocalImport: wasm::structures::LocalImport,
|
||||
Memory: wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: wasm::structures::MemoryView,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
Memory: wasm::structures::Memory<SequentialMemoryView>,
|
||||
SequentialMemoryView: (for<'a> wasm::structures::SequentialMemoryView<'a>),
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
type Error = ();
|
||||
|
||||
|
@ -5,7 +5,8 @@ use crate::IRecordType;
|
||||
use crate::IType;
|
||||
use crate::IValue;
|
||||
use std::rc::Rc;
|
||||
use std::{cell::Cell, ops::Deref};
|
||||
|
||||
pub use it_memory_traits::{Memory, SequentialMemoryView, SequentialReader, SequentialWriter, MemoryAccessError};
|
||||
|
||||
pub trait TypedIndex: Copy + Clone {
|
||||
fn new(index: usize) -> Self;
|
||||
@ -61,26 +62,17 @@ pub trait LocalImport {
|
||||
fn call(&self, arguments: &[IValue]) -> Result<Vec<IValue>, ()>;
|
||||
}
|
||||
|
||||
pub trait MemoryView: Deref<Target = [Cell<u8>]> {}
|
||||
|
||||
pub trait Memory<View>
|
||||
where
|
||||
View: MemoryView,
|
||||
{
|
||||
fn view(&self) -> View;
|
||||
}
|
||||
|
||||
pub trait Instance<E, LI, M, MV>
|
||||
where
|
||||
E: Export,
|
||||
LI: LocalImport,
|
||||
M: Memory<MV>,
|
||||
MV: MemoryView,
|
||||
MV: for<'a> SequentialMemoryView<'a>,
|
||||
{
|
||||
fn export(&self, export_name: &str) -> Option<&E>;
|
||||
fn local_or_import<I: TypedIndex + LocalImportIndex>(&self, index: I) -> Option<&LI>;
|
||||
fn memory(&self, index: usize) -> Option<&M>;
|
||||
fn memory_slice(&self, index: usize) -> Option<&[Cell<u8>]>;
|
||||
fn memory_view(&self, index: usize) -> Option<MV>;
|
||||
fn wit_record_by_id(&self, index: u64) -> Option<&Rc<IRecordType>>;
|
||||
}
|
||||
|
||||
@ -138,13 +130,49 @@ impl LocalImport for () {
|
||||
|
||||
pub(crate) struct EmptyMemoryView;
|
||||
|
||||
impl MemoryView for EmptyMemoryView {}
|
||||
pub(crate) struct EmptySequentialReader;
|
||||
pub(crate) struct EmptySequentialWriter;
|
||||
|
||||
impl Deref for EmptyMemoryView {
|
||||
type Target = [Cell<u8>];
|
||||
impl SequentialReader for EmptySequentialReader {
|
||||
fn read_byte(&self) -> u8 {
|
||||
0u8
|
||||
}
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&[]
|
||||
fn read_bytes<const COUNT: usize>(&self) -> [u8; COUNT] {
|
||||
[0u8; COUNT]
|
||||
}
|
||||
}
|
||||
|
||||
impl SequentialWriter for EmptySequentialWriter {
|
||||
fn start_offset(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn write_u8(&self, _value: u8) {}
|
||||
|
||||
fn write_u32(&self, _value: u32) {}
|
||||
|
||||
fn write_bytes(&self, _bytes: &[u8]) {}
|
||||
}
|
||||
|
||||
impl<'a> SequentialMemoryView<'a> for EmptyMemoryView {
|
||||
type SR = EmptySequentialReader;
|
||||
type SW = EmptySequentialWriter;
|
||||
|
||||
fn sequential_writer(&self, offset: usize, size: usize) -> Result<Self::SW, MemoryAccessError> {
|
||||
Err(MemoryAccessError::OutOfBounds {
|
||||
offset,
|
||||
size,
|
||||
memory_size: 0,
|
||||
})
|
||||
}
|
||||
|
||||
fn sequential_reader(&self, offset: usize, size: usize) -> Result<Self::SR, MemoryAccessError> {
|
||||
Err(MemoryAccessError::OutOfBounds {
|
||||
offset,
|
||||
size,
|
||||
memory_size: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,7 +187,7 @@ where
|
||||
E: Export,
|
||||
LI: LocalImport,
|
||||
M: Memory<MV>,
|
||||
MV: MemoryView,
|
||||
MV: for<'a> SequentialMemoryView<'a>,
|
||||
{
|
||||
fn export(&self, _export_name: &str) -> Option<&E> {
|
||||
None
|
||||
@ -169,7 +197,7 @@ where
|
||||
None
|
||||
}
|
||||
|
||||
fn memory_slice(&self, _: usize) -> Option<&[Cell<u8>]> {
|
||||
fn memory_view(&self, _index: usize) -> Option<MV> {
|
||||
None
|
||||
}
|
||||
|
||||
|
@ -67,15 +67,15 @@ macro_rules! consume {
|
||||
/// Check the existing executable instruction to get more examples.
|
||||
macro_rules! executable_instruction {
|
||||
($name:ident ( $($argument_name:ident: $argument_type:ty),* ) -> _ $implementation:block ) => {
|
||||
pub(crate) fn $name<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
pub(crate) fn $name<Instance, Export, LocalImport, Memory, SequentialMemoryView>(
|
||||
$($argument_name: $argument_type),*
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, SequentialMemoryView>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView,
|
||||
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<SequentialMemoryView>,
|
||||
SequentialMemoryView: for<'a> crate::interpreter::wasm::structures::SequentialMemoryView<'a>,
|
||||
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, SequentialMemoryView>,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::{stack::Stackable};
|
||||
@ -100,7 +100,7 @@ macro_rules! test_executable_instruction {
|
||||
fn $test_name() {
|
||||
use crate::{
|
||||
interpreter::{
|
||||
instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView},
|
||||
instructions::tests::{Export, Instance, LocalImport, Memory, SequentialMemoryView},
|
||||
stack::Stackable,
|
||||
Instruction, Interpreter,
|
||||
},
|
||||
@ -109,7 +109,7 @@ macro_rules! test_executable_instruction {
|
||||
};
|
||||
use std::{cell::Cell, collections::HashMap, convert::TryInto};
|
||||
|
||||
let interpreter: Interpreter<Instance, Export, LocalImport, Memory, MemoryView> =
|
||||
let interpreter: Interpreter<Instance, Export, LocalImport, Memory, SequentialMemoryView> =
|
||||
(&vec![$($instructions),*]).try_into().unwrap();
|
||||
|
||||
let invocation_inputs = vec![$($invocation_inputs),*];
|
||||
@ -142,7 +142,7 @@ macro_rules! test_executable_instruction {
|
||||
fn $test_name() {
|
||||
use crate::{
|
||||
interpreter::{
|
||||
instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView},
|
||||
instructions::tests::{Export, Instance, LocalImport, Memory, SequentialMemoryView},
|
||||
stack::Stackable,
|
||||
Instruction, Interpreter,
|
||||
},
|
||||
@ -151,7 +151,7 @@ macro_rules! test_executable_instruction {
|
||||
};
|
||||
use std::{cell::Cell, collections::HashMap, convert::TryInto};
|
||||
|
||||
let interpreter: Interpreter<Instance, Export, LocalImport, Memory, MemoryView> =
|
||||
let interpreter: Interpreter<Instance, Export, LocalImport, Memory, SequentialMemoryView> =
|
||||
(&vec![$($instructions),*]).try_into().unwrap();
|
||||
|
||||
let invocation_inputs = vec![$($invocation_inputs),*];
|
||||
|
Loading…
Reference in New Issue
Block a user