From aa8ab1b1e3b4cdd13315f896af1f938947d88e93 Mon Sep 17 00:00:00 2001 From: vms Date: Wed, 21 Apr 2021 00:43:17 +0300 Subject: [PATCH] save point --- Cargo.lock | 1 + crates/it-lilo-utils/src/lib.rs | 78 ++++ crates/it-lilo-utils/src/memory_writer.rs | 8 +- wasmer-it/src/errors.rs | 229 +++++---- .../src/interpreter/instructions/arrays.rs | 69 +-- .../instructions/arrays/lift_array.rs | 145 ++++-- .../instructions/arrays/lower_array.rs | 113 ++--- .../instructions/arrays/memory_writer.rs | 48 -- .../instructions/arrays/read_arrays.rs | 440 ------------------ .../src/interpreter/instructions/call_core.rs | 9 +- wasmer-it/src/interpreter/instructions/dup.rs | 2 +- .../instructions/lilo/li_helper.rs | 36 ++ .../instructions/lilo/lo_helper.rs | 45 ++ .../src/interpreter/instructions/lilo/mod.rs | 13 + .../interpreter/instructions/lilo/utils.rs | 79 ++++ wasmer-it/src/interpreter/instructions/mod.rs | 85 ++-- .../src/interpreter/instructions/numbers.rs | 2 +- .../src/interpreter/instructions/records.rs | 55 ++- .../interpreter/instructions/records/error.rs | 17 - .../instructions/records/lift_record.rs | 55 +-- .../instructions/records/lower_record.rs | 27 +- .../src/interpreter/instructions/strings.rs | 18 +- .../src/interpreter/instructions/swap2.rs | 2 +- .../src/interpreter/instructions/utils.rs | 179 ------- wasmer-it/src/interpreter/mod.rs | 2 - wasmer-it/src/lib.rs | 3 - 26 files changed, 650 insertions(+), 1110 deletions(-) delete mode 100644 wasmer-it/src/interpreter/instructions/arrays/memory_writer.rs delete mode 100644 wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs create mode 100644 wasmer-it/src/interpreter/instructions/lilo/li_helper.rs create mode 100644 wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs create mode 100644 wasmer-it/src/interpreter/instructions/lilo/mod.rs create mode 100644 wasmer-it/src/interpreter/instructions/lilo/utils.rs delete mode 100644 wasmer-it/src/interpreter/instructions/records/error.rs delete mode 100644 wasmer-it/src/interpreter/instructions/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 92da332..f43133d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -272,6 +272,7 @@ dependencies = [ "semver", "serde", "serde_json", + "thiserror", "wast", ] diff --git a/crates/it-lilo-utils/src/lib.rs b/crates/it-lilo-utils/src/lib.rs index d3a518b..8b5934b 100644 --- a/crates/it-lilo-utils/src/lib.rs +++ b/crates/it-lilo-utils/src/lib.rs @@ -2,6 +2,84 @@ pub mod error; pub mod memory_reader; pub mod memory_writer; +pub use fluence_it_types::IRecordType; +pub use fluence_it_types::IType; pub use fluence_it_types::IValue; pub type MResult = std::result::Result; + +/// Size of a value in a serialized view. +pub fn ser_type_size(ty: &IType) -> usize { + const WASM_POINTER_SIZE: usize = 4; + + match ty { + IType::Boolean | IType::S8 | IType::U8 => 1, + IType::S16 | IType::U16 => 2, + IType::S32 | IType::U32 | IType::I32 | IType::F32 => 4, + IType::Record(_) => 4, + // Vec-like types are passed by pointer and size + IType::String | IType::ByteArray | IType::Array(_) => 2 * WASM_POINTER_SIZE, + IType::S64 | IType::U64 | IType::I64 | IType::F64 => 8, + } +} + +/// Size of a value in a serialized view. +pub fn ser_value_size(value: &IValue) -> usize { + match value { + IValue::Boolean(_) | IValue::S8(_) | IValue::U8(_) => 1, + IValue::S16(_) | IValue::U16(_) => 2, + IValue::S32(_) | IValue::U32(_) | IValue::F32(_) | IValue::I32(_) => 4, + IValue::S64(_) | IValue::U64(_) | IValue::F64(_) | IValue::I64(_) => 8, + IValue::String(_) | IValue::ByteArray(_) | IValue::Array(_) => 2 * 4, + IValue::Record(_) => 4, + } +} + +/// Returns the record size in bytes. +pub fn record_size(record_type: &IRecordType) -> usize { + record_type + .fields + .iter() + .map(|f| ser_type_size(&f.ty)) + .sum() +} + +pub fn type_code_form_itype(itype: &IType) -> u32 { + const POINTER_CODE: u32 = 3; // u32 on the sdk + + match itype { + IType::Boolean => 0, // u8 + IType::U8 => 1, // u8 + IType::U16 => 2, // u16 + IType::U32 => 3, // u32 + IType::U64 => 4, // u64 + IType::S8 => 5, // i8 + IType::S16 => 6, // i16 + IType::S32 | IType::I32 => 7, // i32 + IType::S64 | IType::I64 => 8, // i64 + IType::F32 => 9, // f32 + IType::F64 => 10, // f64 + IType::ByteArray | IType::Array(_) | IType::Record(_) | IType::String => POINTER_CODE, + } +} + +pub fn type_code_form_ivalue(itype: &IValue) -> u32 { + const POINTER_CODE: u32 = 3; // u32 on the sdk + + match itype { + IValue::Boolean(_) => 0, // u8 + IValue::U8(_) => 1, // u8 + IValue::U16(_) => 2, // u16 + IValue::U32(_) => 3, // u32 + IValue::U64(_) => 4, // u64 + IValue::S8(_) => 5, // i8 + IValue::S16(_) => 6, // i16 + IValue::S32(_) | IValue::I32(_) => 7, // i32 + IValue::S64(_) | IValue::I64(_) => 8, // i64 + IValue::F32(_) => 9, // f32 + IValue::F64(_) => 10, // f64 + IValue::ByteArray(_) | IValue::Array(_) | IValue::Record(_) | IValue::String(_) => { + POINTER_CODE + } + } +} diff --git a/crates/it-lilo-utils/src/memory_writer.rs b/crates/it-lilo-utils/src/memory_writer.rs index 885a7f6..f75cd65 100644 --- a/crates/it-lilo-utils/src/memory_writer.rs +++ b/crates/it-lilo-utils/src/memory_writer.rs @@ -14,8 +14,8 @@ * limitations under the License. */ -use crate::MResult; use crate::error::MemoryAccessError; +use crate::MResult; use std::cell::Cell; @@ -75,7 +75,11 @@ impl<'m> MemoryWriter<'m> { Ok(()) } - pub fn sequential_writer(&self, offset: usize, size: usize) -> MResult> { + pub fn sequential_writer( + &self, + offset: usize, + size: usize, + ) -> MResult> { self.check_access(offset, size)?; Ok(SequentialWriter::new(&self, offset)) diff --git a/wasmer-it/src/errors.rs b/wasmer-it/src/errors.rs index 91b9f4b..a9a894a 100644 --- a/wasmer-it/src/errors.rs +++ b/wasmer-it/src/errors.rs @@ -12,6 +12,8 @@ use std::{ string::{self, ToString}, }; +use thiserror::Error as ThisError; + pub use fluence_it_types::WasmValueNativeCastError; /// A type alias for instruction's results. @@ -31,12 +33,20 @@ pub struct InstructionError { } impl InstructionError { - pub(crate) fn new(instruction: Instruction, error_kind: InstructionErrorKind) -> Self { + pub(crate) fn from_error_kind( + instruction: Instruction, + error_kind: InstructionErrorKind, + ) -> Self { Self { instruction, error_kind, } } + + pub(crate) fn from_lilo(instruction: Instruction, lilo: LiLoError) -> Self { + let error_kind = InstructionErrorKind::LiLoError(lilo); + Self::from_error_kind(instruction, error_kind) + } } impl Error for InstructionError {} @@ -45,7 +55,7 @@ impl Error for InstructionError {} #[macro_export] macro_rules! instr_error { ($instruction:expr, $error_kind:expr) => { - Err(crate::errors::InstructionError::new( + Err(crate::errors::InstructionError::from_error_kind( $instruction, $error_kind, )) @@ -64,18 +74,21 @@ impl Display for InstructionError { } /// The kind of instruction errors. -#[derive(Debug)] +#[derive(ThisError, Debug)] pub enum InstructionErrorKind { /// The instruction needs to read an invocation input at index `index`, but it's missing. + #[error("cannot access invocation inputs #{index} because it doesn't exist")] InvocationInputIsMissing { /// The invocation input index. index: u32, }, /// Failed to cast from a WIT value to a native value. - ToNative(WasmValueNativeCastError), + #[error("failed to cast the WIT value `{0}` to its native type")] + ToNative(#[from] WasmValueNativeCastError), /// Failed to cast from `from` to `to`. + #[error("failed to cast `{from:?}` to `{to:?}`")] LoweringLifting { /// The initial type. from: IType, @@ -86,6 +99,7 @@ pub enum InstructionErrorKind { /// Read a value from the stack, but it doesn't have the expected /// type. + #[error("read a value `{expected_type:?}` from the stack, that can't be converted to `{received_value:?}`")] InvalidValueOnTheStack { /// The expected type. expected_type: IType, @@ -96,12 +110,16 @@ pub enum InstructionErrorKind { /// Need to read some values from the stack, but it doesn't /// contain enough data. + #[error( + "needed to read `{needed}` value(s) from the stack, but it doesn't contain enough data" + )] StackIsTooSmall { /// The number of values that were needed. needed: usize, }, /// The local or import function doesn't exist. + #[error("the local or import function `{function_index}` doesn't exist")] LocalOrImportIsMissing { /// The local or import function index. function_index: u32, @@ -109,6 +127,12 @@ pub enum InstructionErrorKind { /// Values given to a local or import function doesn't match the /// function signature. + #[error( + "the local or import function `{function_index}` has the signature\ + `{:?} -> {:?}`\ + but it received values of kind `{:?} -> {:?}`", + .expected.0, .expected.1, .received.0, .received.1, + )] LocalOrImportSignatureMismatch { /// The local or import function index. function_index: u32, @@ -121,18 +145,21 @@ pub enum InstructionErrorKind { }, /// Failed to call a local or import function. + #[error("failed while calling the local or import function `{function_name}`")] LocalOrImportCall { /// The local or import function name that has been called. function_name: String, }, /// The memory doesn't exist. + #[error("memory `{memory_index}` does not exist")] MemoryIsMissing { /// The memory index. memory_index: usize, }, /// Tried to read out of bounds of the memory. + #[error("read out of the memory bounds (index {index} > memory length {length})")] MemoryOutOfBoundsAccess { /// The access index. index: usize, @@ -142,33 +169,43 @@ pub enum InstructionErrorKind { }, /// The string contains invalid UTF-8 encoding. + #[error("{0}")] String(string::FromUtf8Error), /// Out of range integral type conversion attempted. + #[error("attempted to convert `{subject}`, but it appears to be a negative value")] NegativeValue { /// The variable name that triggered the error. subject: &'static str, }, /// The type doesn't exist. + #[error("the type `{type_index}` doesn't exist")] TypeIsMissing { /// The type index. type_index: u32, }, - /// The searched by name type doesn't exist. + /// The searched by id type doesn't exist. + #[error("type with `{record_type_id}` is missing in a Wasm binary")] RecordTypeByNameIsMissing { /// The record type name. record_type_id: u64, }, /// Corrupted array's been popped from the stack. + #[error("{0}")] CorruptedArray(String), /// Corrupted record's been popped from the stack. + #[error("{0}")] CorruptedRecord(String), /// Read a type that has an unexpected type. + #[error( + "read a type of kind `{received_kind:?}`,\ + but the kind `{expected_kind:?}` was expected" + )] InvalidTypeKind { /// The expected kind. expected_kind: TypeKind, @@ -178,127 +215,12 @@ pub enum InstructionErrorKind { }, /// Errors related to Serialization/deserialization of record. + #[error("serde error: {0}")] SerdeError(String), - /// Errors related to lifting incorrect UTF8 string from a Wasm module. - CorruptedUTF8String(std::string::FromUtf8Error), -} - -impl Error for InstructionErrorKind {} - -impl Display for InstructionErrorKind { - fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { - match self { - Self::InvocationInputIsMissing { index } => write!( - formatter, - "cannot access invocation inputs #{} because it doesn't exist", - index - ), - - Self::ToNative(WasmValueNativeCastError { from, .. }) => write!( - formatter, - "failed to cast the WIT value `{:?}` to its native type", - from, - ), - - Self::LoweringLifting { from, to } => { - write!(formatter, "failed to cast `{:?}` to `{:?}`", from, to) - } - - Self::InvalidValueOnTheStack { - expected_type, - received_value, - } => write!( - formatter, - "read a value `{:?}` from the stack, that can't be converted to `{:?}`", - received_value, expected_type, - ), - - Self::StackIsTooSmall { needed } => write!( - formatter, - "needed to read `{}` value(s) from the stack, but it doesn't contain enough data", - needed - ), - - Self::LocalOrImportIsMissing { function_index } => write!( - formatter, - "the local or import function `{}` doesn't exist", - function_index - ), - - Self::LocalOrImportSignatureMismatch { function_index, expected, received } => write!( - formatter, - "the local or import function `{}` has the signature `{:?} -> {:?}` but it received values of kind `{:?} -> {:?}`", - function_index, expected.0, expected.1, received.0, received.1, - ), - - Self::LocalOrImportCall { function_name } => write!( - formatter, - "failed while calling the local or import function `{}`", - function_name - ), - - Self::MemoryIsMissing { memory_index } => write!( - formatter, - "memory `{}` does not exist", - memory_index, - ), - - Self::MemoryOutOfBoundsAccess { index, length } => write!( - formatter, - "read out of the memory bounds (index {} > memory length {})", - index, length, - ), - - Self::String(error) => write!(formatter, "{}", error), - - Self::NegativeValue { subject } => write!( - formatter, - "attempted to convert `{}` but it appears to be a negative value", - subject - ), - - Self::TypeIsMissing { type_index } => write!( - formatter, - "the type `{}` doesn't exist", - type_index - ), - - Self::InvalidTypeKind { expected_kind, received_kind } => write!( - formatter, - "read a type of kind `{:?}`, but the kind `{:?}` was expected", - received_kind, expected_kind - ), - - Self::RecordTypeByNameIsMissing { record_type_id: type_name } => write!( - formatter, - "type with `{}` is missing in a Wasm binary", - type_name - ), - - Self::CorruptedArray(err) => write!( - formatter, - "{}", - err - ), - - Self::CorruptedRecord(err) => write!( - formatter, - "{}", - err - ), - - Self::SerdeError(err) => write!( - formatter, - "serde error: {}", err, - ), - - Self::CorruptedUTF8String(err) => write!( - formatter, - "corrupted utf8 string: {}", err - ) - } - } + /// Errors related to lifting/lowering records. + #[error("{0}")] + LiLoError(#[from] LiLoError), } impl From<(TryFromIntError, &'static str)> for InstructionErrorKind { @@ -306,3 +228,62 @@ impl From<(TryFromIntError, &'static str)> for InstructionErrorKind { InstructionErrorKind::NegativeValue { subject } } } + +/// Contains various errors encountered while lifting/lowering records and arrays. +#[derive(Debug, ThisError)] +pub enum LiLoError { + /// This error occurred from out-of-bound memory access. + #[error("{0}")] + MemoryAccessError(#[from] it_lilo_utils::error::MemoryAccessError), + + /// An error related to not found record in module record types. + #[error("Record with type id {0} not found")] + RecordTypeNotFound(u64), + + /// 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, + + /// The searched by id type doesn't exist. + #[error("type with `{record_type_id}` is missing in a Wasm binary")] + RecordTypeByNameIsMissing { + /// The record type name. + record_type_id: u64, + }, + + /// Errors related to lifting incorrect UTF8 string from a Wasm module. + #[error("corrupted UTF8 string {0}")] + CorruptedUTF8String(#[from] std::string::FromUtf8Error), + + /// This error occurred when a record is created from empty values array. + #[error("Record with name '{0}' can't be empty")] + EmptyRecord(String), +} diff --git a/wasmer-it/src/interpreter/instructions/arrays.rs b/wasmer-it/src/interpreter/instructions/arrays.rs index 4f90ef7..513f2a9 100644 --- a/wasmer-it/src/interpreter/instructions/arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays.rs @@ -1,18 +1,11 @@ mod lift_array; mod lower_array; -mod memory_writer; -mod read_arrays; - -pub use lower_array::ser_value_size; pub(crate) use lift_array::array_lift_memory_impl; pub(crate) use lower_array::array_lower_memory_impl; -use super::allocate; -use super::read_from_instance_mem; -use super::record_lift_memory_impl; +use super::lilo; use super::record_lower_memory_impl; -use super::write_to_instance_mem; use crate::instr_error; use crate::interpreter::instructions::to_native; @@ -41,7 +34,7 @@ where Box::new({ move |runtime| -> _ { let inputs = runtime.stack.pop(2).ok_or_else(|| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, ) @@ -50,12 +43,12 @@ where let offset: usize = to_native::(&inputs[0], instruction.clone())? .try_into() .map_err(|e| (e, "offset").into()) - .map_err(|k| InstructionError::new(instruction.clone(), k))?; + .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; let size: usize = to_native::(&inputs[1], instruction.clone())? .try_into() .map_err(|e| (e, "size").into()) - .map_err(|k| InstructionError::new(instruction.clone(), k))?; + .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; log::trace!( "array.lift_memory: lifting memory for value type: {:?}, popped offset {}, size {}", @@ -65,13 +58,23 @@ where ); let instance = &mut runtime.wasm_instance; - let array = array_lift_memory_impl( - *instance, - &value_type, - offset as _, - size as _, - instruction.clone(), - )?; + + let memory_index = 0; + let memory_view = instance + .memory(memory_index) + .ok_or_else(|| { + InstructionError::from_error_kind( + instruction.clone(), + InstructionErrorKind::MemoryIsMissing { memory_index }, + ) + })? + .view(); + let memory = memory_view.deref(); + + let li_helper = lilo::LiHelper::new(&**instance, memory) + .map_err(|e| InstructionError::from_lilo(instruction.clone(), e))?; + let array = array_lift_memory_impl(&li_helper, &value_type, offset as _, size as _) + .map_err(|e| InstructionError::from_lilo(instruction.clone(), e))?; log::trace!("array.lift_memory: pushing {:?} on the stack", array); runtime.stack.push(array); @@ -99,7 +102,7 @@ where move |runtime| -> _ { let instance = &mut runtime.wasm_instance; let stack_value = runtime.stack.pop1().ok_or_else(|| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, ) @@ -110,16 +113,28 @@ where log::trace!("array.lower_memory: obtained {:?} values on the stack for interface type {:?}", values, value_type); for value in values.iter() { - super::is_value_compatible_to_type( - &**instance, - &value_type, - &value, - instruction.clone(), - )?; + super::is_value_compatible_to_type(&**instance, &value_type, &value) + .map_err(|e| { + InstructionError::from_error_kind(instruction.clone(), e) + })?; } - let (offset, size) = - array_lower_memory_impl(*instance, instruction.clone(), values)?; + let memory_index = 0; + let memory_view = instance + .memory(memory_index) + .ok_or_else(|| { + InstructionError::from_error_kind( + instruction.clone(), + InstructionErrorKind::MemoryIsMissing { memory_index }, + ) + })? + .view(); + let memory = memory_view.deref(); + + let lo_helper = lilo::LoHelper::new(&**instance, memory) + .map_err(|e| InstructionError::from_lilo(instruction.clone(), e))?; + let (offset, size) = array_lower_memory_impl(&lo_helper, values) + .map_err(|e| InstructionError::from_lilo(instruction.clone(), e))?; log::trace!( "array.lower_memory: pushing {}, {} on the stack", diff --git a/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs index 05134cc..23f513d 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs @@ -1,55 +1,110 @@ -use super::read_arrays::*; +use super::lilo::*; -use crate::{errors::InstructionError, interpreter::Instruction, IType, IValue}; +use crate::IType; +use crate::IValue; -pub(crate) fn array_lift_memory_impl<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, +use crate::interpreter::instructions::record_lift_memory_impl; +use it_lilo_utils::ser_type_size; + +pub(crate) fn array_lift_memory_impl( + li_helper: &LiHelper, value_type: &IType, offset: usize, elements_count: usize, - instruction: Instruction, -) -> Result -where - Export: crate::interpreter::wasm::structures::Export, - LocalImport: crate::interpreter::wasm::structures::LocalImport, - Memory: crate::interpreter::wasm::structures::Memory, - MemoryView: crate::interpreter::wasm::structures::MemoryView, - Instance: crate::interpreter::wasm::structures::Instance - + 'instance, -{ +) -> LiLoResult { if elements_count == 0 { return Ok(IValue::Array(vec![])); } - match value_type { - IType::Boolean => read_bool_array(instance, instruction, offset, elements_count), - IType::S8 => read_s8_array(instance, instruction, offset, elements_count), - IType::S16 => read_s16_array(instance, instruction, offset, elements_count), - IType::S32 => read_s32_array(instance, instruction, offset, elements_count), - IType::S64 => read_s64_array(instance, instruction, offset, elements_count), - IType::I32 => read_i32_array(instance, instruction, offset, elements_count), - IType::I64 => read_i64_array(instance, instruction, offset, elements_count), - IType::U8 => read_u8_array(instance, instruction, offset, elements_count), - IType::U16 => read_u16_array(instance, instruction, offset, elements_count), - IType::U32 => read_u32_array(instance, instruction, offset, elements_count), - IType::U64 => read_u64_array(instance, instruction, offset, elements_count), - IType::F32 => read_f32_array(instance, instruction, offset, elements_count), - IType::F64 => read_f64_array(instance, instruction, offset, elements_count), - IType::String => read_string_array(instance, instruction, offset, elements_count), - IType::Record(record_type_id) => read_record_array( - instance, - instruction, - *record_type_id, - offset, - elements_count, - ), - IType::ByteArray => read_array_array( - instance, - instruction, - &IType::ByteArray, - offset, - elements_count, - ), - IType::Array(ty) => read_array_array(instance, instruction, &ty, offset, elements_count), - } + let reader = &li_helper.reader; + + let ivalues = match value_type { + IType::Boolean => reader.read_bool_array(offset, elements_count)?, + IType::S8 => reader.read_s8_array(offset, elements_count)?, + IType::S16 => reader.read_s16_array(offset, elements_count)?, + IType::S32 => reader.read_s32_array(offset, elements_count)?, + IType::S64 => reader.read_s64_array(offset, elements_count)?, + IType::I32 => reader.read_i32_array(offset, elements_count)?, + IType::I64 => reader.read_i64_array(offset, elements_count)?, + IType::U8 => reader.read_u8_array(offset, elements_count)?, + IType::U16 => reader.read_u16_array(offset, elements_count)?, + IType::U32 => reader.read_u32_array(offset, elements_count)?, + IType::U64 => reader.read_u64_array(offset, elements_count)?, + IType::F32 => reader.read_f32_array(offset, elements_count)?, + IType::F64 => reader.read_f64_array(offset, elements_count)?, + IType::String => read_string_array(li_helper, offset, elements_count)?, + IType::ByteArray => read_array_array(li_helper, &IType::ByteArray, offset, elements_count)?, + IType::Array(ty) => read_array_array(li_helper, &ty, offset, elements_count)?, + IType::Record(record_type_id) => { + read_record_array(li_helper, *record_type_id, offset, elements_count)? + } + }; + + Ok(IValue::Array(ivalues)) +} + +fn read_string_array( + li_helper: &LiHelper, + offset: usize, + elements_count: usize, +) -> LiLoResult> { + let mut result = Vec::with_capacity(elements_count); + let seq_reader = li_helper + .reader + .sequential_reader(offset, ser_type_size(&IType::String) * elements_count)?; + + for _ in 0..elements_count { + let offset = seq_reader.read_u32(); + let size = seq_reader.read_u32(); + + let raw_str = li_helper.reader.read_raw_u8_array(offset as _, size as _)?; + let str = String::from_utf8(raw_str)?; + result.push(IValue::String(str)); + } + + Ok(result) +} + +fn read_array_array( + li_helper: &LiHelper, + ty: &IType, + offset: usize, + elements_count: usize, +) -> LiLoResult> { + let mut result = Vec::with_capacity(elements_count); + let seq_reader = li_helper + .reader + .sequential_reader(offset, ser_type_size(ty) * elements_count)?; + + for _ in 0..elements_count { + let offset = seq_reader.read_u32(); + let size = seq_reader.read_u32(); + + let array = array_lift_memory_impl(li_helper, ty, offset as _, size as _)?; + result.push(array); + } + + Ok(result) +} + +fn read_record_array( + li_helper: &LiHelper, + record_type_id: u64, + offset: usize, + elements_count: usize, +) -> LiLoResult> { + let mut result = Vec::with_capacity(elements_count); + let seq_reader = li_helper + .reader + .sequential_reader(offset, ser_type_size(&IType::Record(0)) * elements_count)?; + + for _ in 0..elements_count { + let offset = seq_reader.read_u32(); + let record_ty = (li_helper.record_resolver)(record_type_id)?; + + let record = record_lift_memory_impl(li_helper, &record_ty, offset as _)?; + result.push(record); + } + + Ok(result) } diff --git a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs index 2c1909f..1a6d727 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs @@ -1,105 +1,70 @@ -use super::memory_writer::MemoryWriter; -use super::write_to_instance_mem; +use super::lilo::*; -use crate::{ - errors::{InstructionError, InstructionErrorKind}, - interpreter::Instruction, - IValue, -}; +use crate::IValue; -pub(crate) fn array_lower_memory_impl( - instance: &mut Instance, - instruction: Instruction, +use it_lilo_utils::ser_value_size; +use it_lilo_utils::type_code_form_ivalue; + +pub(crate) fn array_lower_memory_impl( + lo_helper: &LoHelper, array_values: Vec, -) -> Result<(usize, usize), InstructionError> -where - Export: crate::interpreter::wasm::structures::Export, - LocalImport: crate::interpreter::wasm::structures::LocalImport, - Memory: crate::interpreter::wasm::structures::Memory, - MemoryView: crate::interpreter::wasm::structures::MemoryView, - Instance: - crate::interpreter::wasm::structures::Instance, -{ +) -> LiLoResult<(usize, usize)> { if array_values.is_empty() { return Ok((0, 0)); } let elements_count = array_values.len(); let size_to_allocate = ser_value_size(&array_values[0]) * elements_count; - let offset = super::allocate(instance, instruction.clone(), size_to_allocate)?; + let offset = (lo_helper.allocate)( + size_to_allocate as _, + type_code_form_ivalue(&array_values[0]) as _, + )?; - let memory_index = 0; - let memory_view = &instance - .memory(memory_index) - .ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::MemoryIsMissing { memory_index }, - ) - })? - .view(); - let writer = MemoryWriter::new(memory_view, offset); + let seq_writer = lo_helper + .writer + .sequential_writer(offset, size_to_allocate)?; // here it's known that all interface values have the same type for value in array_values { match value { - IValue::Boolean(value) => writer.write_u8(value as _), - IValue::S8(value) => writer.write_u8(value as _), - IValue::S16(value) => writer.write_array(value.to_le_bytes()), - IValue::S32(value) => writer.write_array(value.to_le_bytes()), - IValue::S64(value) => writer.write_array(value.to_le_bytes()), - IValue::U8(value) => writer.write_array(value.to_le_bytes()), - IValue::U16(value) => writer.write_array(value.to_le_bytes()), - IValue::U32(value) => writer.write_array(value.to_le_bytes()), - IValue::U64(value) => writer.write_array(value.to_le_bytes()), - IValue::I32(value) => writer.write_array(value.to_le_bytes()), - IValue::I64(value) => writer.write_array(value.to_le_bytes()), - IValue::F32(value) => writer.write_array(value.to_le_bytes()), - IValue::F64(value) => writer.write_array(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_array(value.to_le_bytes()), + IValue::S32(value) => seq_writer.write_array(value.to_le_bytes()), + IValue::S64(value) => seq_writer.write_array(value.to_le_bytes()), + IValue::U8(value) => seq_writer.write_array(value.to_le_bytes()), + IValue::U16(value) => seq_writer.write_array(value.to_le_bytes()), + IValue::U32(value) => seq_writer.write_array(value.to_le_bytes()), + IValue::U64(value) => seq_writer.write_array(value.to_le_bytes()), + IValue::I32(value) => seq_writer.write_array(value.to_le_bytes()), + IValue::I64(value) => seq_writer.write_array(value.to_le_bytes()), + IValue::F32(value) => seq_writer.write_array(value.to_le_bytes()), + IValue::F64(value) => seq_writer.write_array(value.to_le_bytes()), IValue::String(value) => { - let string_pointer = - write_to_instance_mem(instance, instruction.clone(), value.as_bytes())? as u32; - let string_size = value.len() as u32; + let offset = lo_helper.write_to_mem(value.as_bytes())? as u32; - writer.write_array(string_pointer.to_le_bytes()); - writer.write_array(string_size.to_le_bytes()); + seq_writer.write_array(offset.to_le_bytes()); + seq_writer.write_array((value.len() as u32).to_le_bytes()); } IValue::ByteArray(values) => { - let array_pointer = - write_to_instance_mem(instance, instruction.clone(), &values)? as u32; - let array_size = values.len() as u32; + let offset = lo_helper.write_to_mem(&values)? as u32; - writer.write_array(array_pointer.to_le_bytes()); - writer.write_array(array_size.to_le_bytes()); + seq_writer.write_array(offset.to_le_bytes()); + seq_writer.write_array((values.len() as u32).to_le_bytes()); } IValue::Array(values) => { - let (array_offset, array_size) = - array_lower_memory_impl(instance, instruction.clone(), values)?; + let (offset, size) = array_lower_memory_impl(lo_helper, values)?; - let (array_offset, array_size) = (array_offset as u32, array_size as u32); - writer.write_array(array_offset.to_le_bytes()); - writer.write_array(array_size.to_le_bytes()); + seq_writer.write_array((offset as u32).to_le_bytes()); + seq_writer.write_array((size as u32).to_le_bytes()); } IValue::Record(values) => { - let record_offset = - super::record_lower_memory_impl(instance, instruction.clone(), values)? as u32; - writer.write_array(record_offset.to_le_bytes()); + let offset = super::record_lower_memory_impl(lo_helper, values)? as u32; + seq_writer.write_array(offset.to_le_bytes()); } } } Ok((offset as _, elements_count as _)) } - -/// Size of a value in a serialized view. -pub fn ser_value_size(value: &IValue) -> usize { - match value { - IValue::Boolean(_) | IValue::S8(_) | IValue::U8(_) => 1, - IValue::S16(_) | IValue::U16(_) => 2, - IValue::S32(_) | IValue::U32(_) | IValue::F32(_) | IValue::I32(_) => 4, - IValue::S64(_) | IValue::U64(_) | IValue::F64(_) | IValue::I64(_) => 8, - IValue::String(_) | IValue::ByteArray(_) | IValue::Array(_) => 2 * 4, - IValue::Record(_) => 4, - } -} diff --git a/wasmer-it/src/interpreter/instructions/arrays/memory_writer.rs b/wasmer-it/src/interpreter/instructions/arrays/memory_writer.rs deleted file mode 100644 index 41d066e..0000000 --- a/wasmer-it/src/interpreter/instructions/arrays/memory_writer.rs +++ /dev/null @@ -1,48 +0,0 @@ -use std::cell::Cell; - -pub(super) struct MemoryWriter<'m> { - memory_view: &'m [Cell], - offset: Cell, -} - -impl<'m> MemoryWriter<'m> { - pub(crate) fn new(memory_view: &'m [Cell], offset: usize) -> Self { - let offset = Cell::new(offset); - - Self { - memory_view, - offset, - } - } - - pub(crate) fn write_u8(&self, value: u8) { - let offset = self.offset.get(); - self.memory_view[offset].set(value); - self.offset.set(offset + 1); - } - - #[allow(dead_code)] - pub(crate) fn write_slice(&self, values: &[u8]) { - let offset = self.offset.get(); - - for (id, value) in values.iter().enumerate() { - // don't check for memory overflow here for optimization purposes - // assuming that caller site work well - self.memory_view[offset + id].set(*value); - } - - self.offset.set(offset + values.len()); - } - - pub(crate) fn write_array(&self, values: [u8; N]) { - let offset = self.offset.get(); - - for id in 0..N { - // don't check for memory overflow here for optimization purposes - // assuming that caller site work well - self.memory_view[offset + id].set(values[id]); - } - - self.offset.set(offset + values.len()); - } -} diff --git a/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs b/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs deleted file mode 100644 index d41842e..0000000 --- a/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs +++ /dev/null @@ -1,440 +0,0 @@ -use crate::instr_error; -use crate::interpreter::wasm; -use crate::IValue; -use crate::{ - errors::{InstructionError, InstructionErrorKind}, - interpreter::Instruction, -}; - -use std::cell::Cell; - -macro_rules! def_read_func { - ($func_name: ident, ($ty:ident, $elements_count:ident), $ctor:expr) => { - pub(super) fn $func_name<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, - instruction: Instruction, - offset: usize, - $elements_count: usize, - ) -> Result - where - Export: wasm::structures::Export + 'instance, - LocalImport: wasm::structures::LocalImport + 'instance, - Memory: wasm::structures::Memory + 'instance, - MemoryView: wasm::structures::MemoryView, - Instance: wasm::structures::Instance, - { - let value_size = std::mem::size_of::<$ty>(); - - let ctor_ = $ctor; - - let ivalues = ivalues_from_mem( - instance, - instruction, - offset, - value_size * $elements_count, - ctor_, - )?; - - let ivalue = IValue::Array(ivalues); - Ok(ivalue) - } - }; -} - -macro_rules! value_der { - ($memory_view:expr, $element_id:expr, $element_size:expr, @seq_start $($ids:tt),* @seq_end) => { - [$(std::cell::Cell::get(&$memory_view[$element_size * $element_id + $ids])),+] - }; - - ($memory_view:expr, $element_id:expr, 1) => { - value_der!($memory_view, $element_id, 1, @seq_start 0 @seq_end); - }; - - ($memory_view:expr, $element_id:expr, 2) => { - value_der!($memory_view, $element_id, 2, @seq_start 0, 1 @seq_end); - }; - - ($memory_view:expr, $element_id:expr, 4) => { - value_der!($memory_view, $element_id, 4, @seq_start 0, 1, 2, 3 @seq_end); - }; - - ($memory_view:expr, $element_id:expr, 8) => { - value_der!($memory_view, $element_id, 8, @seq_start 0, 1, 2, 3, 4, 5, 6, 7 @seq_end); - }; -} - -fn ivalues_from_mem<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, - instruction: Instruction, - offset: usize, - size: usize, - ivalue_ctor: impl FnOnce(&[Cell]) -> Vec, -) -> Result, InstructionError> -where - Export: wasm::structures::Export + 'instance, - LocalImport: wasm::structures::LocalImport + 'instance, - Memory: wasm::structures::Memory + 'instance, - MemoryView: wasm::structures::MemoryView + 'instance, - Instance: wasm::structures::Instance, -{ - let memory_index = 0; - let memory_view = instance - .memory(memory_index) - .ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::MemoryIsMissing { memory_index }, - ) - })? - .view(); - - log::trace!("reading {} bytes from offset {}", size, offset); - - let right = offset + size; - if right < offset || right >= memory_view.len() { - return instr_error!( - instruction, - InstructionErrorKind::MemoryOutOfBoundsAccess { - index: right, - length: memory_view.len(), - } - ); - } - - let view = &memory_view[offset..offset + size]; - let ivalues = ivalue_ctor(view); - Ok(ivalues) -} - -def_read_func!(read_bool_array, (bool, elements_count), { - |memory_view: &[Cell]| { - let mut result = Vec::with_capacity(elements_count); - for element_id in 0..elements_count { - let value = Cell::get(&memory_view[element_id]); - result.push(IValue::Boolean(value != 0)); - } - - result - } -}); - -def_read_func!(read_u8_array, (u8, elements_count), { - |memory_view: &[Cell]| { - let mut result = Vec::with_capacity(elements_count); - for element_id in 0..elements_count { - let value = Cell::get(&memory_view[element_id]); - result.push(IValue::U8(value)); - } - - result - } -}); - -def_read_func!(read_s8_array, (i8, elements_count), { - |memory_view: &[Cell]| { - let mut result = Vec::with_capacity(elements_count); - for element_id in 0..elements_count { - let value = i8::from_le_bytes([Cell::get(&memory_view[element_id])]); - result.push(IValue::S8(value)); - } - - result - } -}); - -def_read_func!(read_u16_array, (u16, elements_count), { - |memory_view: &[Cell]| { - let mut result = Vec::with_capacity(elements_count); - for element_id in 0..elements_count { - let value = u16::from_le_bytes(value_der!(memory_view, element_id, 2)); - result.push(IValue::U16(value)); - } - - result - } -}); - -def_read_func!(read_s16_array, (i16, elements_count), { - |memory_view: &[Cell]| { - let mut result = Vec::with_capacity(elements_count); - for element_id in 0..elements_count { - let value = i16::from_le_bytes(value_der!(memory_view, element_id, 2)); - result.push(IValue::S16(value)); - } - - result - } -}); - -def_read_func!(read_u32_array, (u32, elements_count), { - |memory_view: &[Cell]| { - let mut result = Vec::with_capacity(elements_count); - for element_id in 0..elements_count { - let value = u32::from_le_bytes(value_der!(memory_view, element_id, 4)); - result.push(IValue::U32(value)); - } - - result - } -}); - -def_read_func!(read_f32_array, (f32, elements_count), { - |memory_view: &[Cell]| { - let mut result = Vec::with_capacity(elements_count); - for element_id in 0..elements_count { - let value = f32::from_le_bytes(value_der!(memory_view, element_id, 4)); - result.push(IValue::F32(value)); - } - - result - } -}); - -def_read_func!(read_s32_array, (i32, elements_count), { - |memory_view: &[Cell]| { - let mut result = Vec::with_capacity(elements_count); - for element_id in 0..elements_count { - let value = i32::from_le_bytes(value_der!(memory_view, element_id, 4)); - result.push(IValue::S32(value)); - } - - result - } -}); - -def_read_func!(read_i32_array, (i32, elements_count), { - |memory_view: &[Cell]| { - let mut result = Vec::with_capacity(elements_count); - for element_id in 0..elements_count { - let value = i32::from_le_bytes(value_der!(memory_view, element_id, 4)); - result.push(IValue::I32(value)); - } - - result - } -}); - -def_read_func!(read_u64_array, (u64, elements_count), { - |memory_view: &[Cell]| { - let mut result = Vec::with_capacity(elements_count); - for element_id in 0..elements_count { - let value = u64::from_le_bytes(value_der!(memory_view, element_id, 8)); - result.push(IValue::U64(value)); - } - - result - } -}); - -def_read_func!(read_f64_array, (f64, elements_count), { - |memory_view: &[Cell]| { - let mut result = Vec::with_capacity(elements_count); - for element_id in 0..elements_count { - let value = f64::from_le_bytes(value_der!(memory_view, element_id, 8)); - result.push(IValue::F64(value)); - } - - result - } -}); - -def_read_func!(read_s64_array, (i64, elements_count), { - |memory_view: &[Cell]| { - let mut result = Vec::with_capacity(elements_count); - for element_id in 0..elements_count { - let value = i64::from_le_bytes(value_der!(memory_view, element_id, 8)); - result.push(IValue::S64(value)); - } - - result - } -}); - -def_read_func!(read_i64_array, (i64, elements_count), { - |memory_view: &[Cell]| { - let mut result = Vec::with_capacity(elements_count); - for element_id in 0..elements_count { - let value = i64::from_le_bytes(value_der!(memory_view, element_id, 8)); - result.push(IValue::I64(value)); - } - - result - } -}); - -use super::read_from_instance_mem; -use safe_transmute::guard::AllOrNothingGuard; -use safe_transmute::transmute_many; - -const WASM_POINTER_SIZE: usize = 4; - -pub(super) fn read_string_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, - instruction: Instruction, - offset: usize, - elements_count: usize, -) -> Result -where - Export: crate::interpreter::wasm::structures::Export, - LocalImport: crate::interpreter::wasm::structures::LocalImport, - Memory: crate::interpreter::wasm::structures::Memory, - MemoryView: crate::interpreter::wasm::structures::MemoryView, - Instance: crate::interpreter::wasm::structures::Instance - + 'instance, -{ - let data = read_from_instance_mem( - instance, - instruction.clone(), - offset, - WASM_POINTER_SIZE * elements_count, - )?; - let data = transmute_many::(&data).unwrap(); - - if data.is_empty() { - return Ok(IValue::Array(vec![])); - } - - let mut result = Vec::with_capacity(data.len() / 2); - let mut data = data.iter(); - - while let Some(string_offset) = data.next() { - let string_size = data.next().ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::CorruptedArray(String::from( - "serialized array must contain even count of elements", - )), - ) - })?; - - let string_mem = read_from_instance_mem( - instance, - instruction.clone(), - *string_offset as _, - *string_size as _, - )?; - - let string = String::from_utf8(string_mem).map_err(|e| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::CorruptedUTF8String(e), - ) - })?; - result.push(IValue::String(string)); - } - - let result = IValue::Array(result); - - Ok(result) -} - -pub(super) fn read_record_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, - instruction: Instruction, - record_type_id: u64, - offset: usize, - elements_count: usize, -) -> Result -where - Export: crate::interpreter::wasm::structures::Export, - LocalImport: crate::interpreter::wasm::structures::LocalImport, - Memory: crate::interpreter::wasm::structures::Memory, - MemoryView: crate::interpreter::wasm::structures::MemoryView, - Instance: crate::interpreter::wasm::structures::Instance - + 'instance, -{ - let record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id }, - ) - })?; - - let data = read_from_instance_mem( - instance, - instruction.clone(), - offset, - WASM_POINTER_SIZE * elements_count, - )?; - let data = transmute_many::(&data).unwrap(); - - let mut result = Vec::with_capacity(data.len()); - - for record_offset in data { - result.push(super::record_lift_memory_impl( - instance, - record_type, - *record_offset as _, - instruction.clone(), - )?); - } - - let result = IValue::Array(result); - Ok(result) -} - -pub(super) fn read_array_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, - instruction: Instruction, - ty: &crate::IType, - offset: usize, - elements_count: usize, -) -> Result -where - Export: crate::interpreter::wasm::structures::Export, - LocalImport: crate::interpreter::wasm::structures::LocalImport, - Memory: crate::interpreter::wasm::structures::Memory, - MemoryView: crate::interpreter::wasm::structures::MemoryView, - Instance: crate::interpreter::wasm::structures::Instance - + 'instance, -{ - let data = read_from_instance_mem( - instance, - instruction.clone(), - offset, - WASM_POINTER_SIZE * elements_count, - )?; - let data = transmute_many::(&data).unwrap(); - - if data.is_empty() { - return Ok(IValue::Array(vec![])); - } - - let mut result = Vec::with_capacity(data.len() / 2); - let mut data = data.iter(); - - while let Some(array_offset) = data.next() { - let array_size = data.next().ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::CorruptedArray(String::from( - "serialized array must contain even count of elements", - )), - ) - })?; - - let value = match ty { - crate::IType::ByteArray => { - let value = read_from_instance_mem( - instance, - instruction.clone(), - *array_offset as _, - *array_size as _, - )?; - IValue::ByteArray(value) - } - _ => super::array_lift_memory_impl( - instance, - &*ty, - *array_offset as _, - *array_size as _, - instruction.clone(), - )?, - }; - - result.push(value); - } - - let result = IValue::Array(result); - Ok(result) -} diff --git a/wasmer-it/src/interpreter/instructions/call_core.rs b/wasmer-it/src/interpreter/instructions/call_core.rs index 4703249..faf2f1b 100644 --- a/wasmer-it/src/interpreter/instructions/call_core.rs +++ b/wasmer-it/src/interpreter/instructions/call_core.rs @@ -11,7 +11,7 @@ executable_instruction!( let index = FunctionIndex::new(function_index as usize); let local_or_import = instance.local_or_import(index).ok_or_else(|| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::LocalOrImportIsMissing { function_index, @@ -21,7 +21,7 @@ executable_instruction!( let inputs_cardinality = local_or_import.inputs_cardinality(); let inputs = runtime.stack.pop(inputs_cardinality).ok_or_else(|| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: inputs_cardinality, @@ -29,12 +29,13 @@ executable_instruction!( ) })?; - super::check_function_signature(&**instance, local_or_import, &inputs, instruction.clone())?; + super::check_function_signature(&**instance, local_or_import, &inputs) + .map_err(|e| InstructionError::from_error_kind(instruction.clone(), e))?; log::debug!("call-core: calling {} with arguments: {:?}", local_or_import.name(), inputs); let outputs = local_or_import.call(&inputs).map_err(|_| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::LocalOrImportCall { function_name: local_or_import.name().to_string(), diff --git a/wasmer-it/src/interpreter/instructions/dup.rs b/wasmer-it/src/interpreter/instructions/dup.rs index cc4c996..c726c69 100644 --- a/wasmer-it/src/interpreter/instructions/dup.rs +++ b/wasmer-it/src/interpreter/instructions/dup.rs @@ -7,7 +7,7 @@ executable_instruction!( dup(instruction: Instruction) -> _ { move |runtime| -> _ { let value = runtime.stack.peek1().ok_or_else(|| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, ) diff --git a/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs b/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs new file mode 100644 index 0000000..617baba --- /dev/null +++ b/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs @@ -0,0 +1,36 @@ +use super::LiLoResult; +use super::RecordResolver; +use crate::interpreter::wasm; + +use it_lilo_utils::memory_reader::MemoryReader; + +use std::cell::Cell; + +pub(crate) struct LiHelper<'i> { + pub(crate) reader: MemoryReader<'i>, + pub(crate) record_resolver: RecordResolver<'i>, +} + +impl<'instance> LiHelper<'instance> { + pub(crate) fn new( + instance: &'instance Instance, + memory: &'instance [Cell], + ) -> LiLoResult + where + Export: wasm::structures::Export + 'instance, + LocalImport: wasm::structures::LocalImport + 'instance, + Memory: wasm::structures::Memory + 'instance, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, + { + let record_resolver = super::build_record_resolver(instance)?; + let reader = MemoryReader::new(memory); + + let helper = Self { + reader, + record_resolver, + }; + + Ok(helper) + } +} diff --git a/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs b/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs new file mode 100644 index 0000000..2bbd62a --- /dev/null +++ b/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs @@ -0,0 +1,45 @@ +use super::AllocateFunc; +use super::LiLoResult; + +use crate::interpreter::wasm; +use crate::IType; + +use it_lilo_utils::memory_writer::MemoryWriter; +use it_lilo_utils::type_code_form_itype; + +use std::cell::Cell; + +pub(crate) struct LoHelper<'i> { + pub(crate) writer: MemoryWriter<'i>, + pub(crate) allocate: AllocateFunc<'i>, +} + +impl<'instance> LoHelper<'instance> { + pub(crate) fn new( + instance: &'instance Instance, + memory: &'instance [Cell], + ) -> LiLoResult + where + Export: wasm::structures::Export + 'instance, + LocalImport: wasm::structures::LocalImport + 'instance, + Memory: wasm::structures::Memory + 'instance, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, + { + let allocate = super::build_allocate_func(instance)?; + let writer = MemoryWriter::new(memory); + + let helper = Self { writer, allocate }; + + Ok(helper) + } + + pub(crate) fn write_to_mem(&self, bytes: &[u8]) -> LiLoResult { + let alloc_type_code = type_code_form_itype(&IType::U8); + let offset = (self.allocate)(bytes.len() as _, alloc_type_code as _)?; + + self.writer.write_bytes(offset, bytes)?; + + Ok(offset) + } +} diff --git a/wasmer-it/src/interpreter/instructions/lilo/mod.rs b/wasmer-it/src/interpreter/instructions/lilo/mod.rs new file mode 100644 index 0000000..f14ce7e --- /dev/null +++ b/wasmer-it/src/interpreter/instructions/lilo/mod.rs @@ -0,0 +1,13 @@ +mod li_helper; +mod lo_helper; +mod utils; + +pub(crate) use crate::errors::LiLoError; +pub(crate) use li_helper::LiHelper; +pub(crate) use lo_helper::LoHelper; +pub(crate) use utils::AllocateFunc; +pub(crate) use utils::RecordResolver; + +pub(crate) type LiLoResult = std::result::Result; + +pub(self) use utils::*; diff --git a/wasmer-it/src/interpreter/instructions/lilo/utils.rs b/wasmer-it/src/interpreter/instructions/lilo/utils.rs new file mode 100644 index 0000000..0065aeb --- /dev/null +++ b/wasmer-it/src/interpreter/instructions/lilo/utils.rs @@ -0,0 +1,79 @@ +use super::LiLoError; +use super::LiLoResult; +use crate::interpreter::instructions::ALLOCATE_FUNC_INDEX; +use crate::interpreter::wasm; +use crate::interpreter::wasm::structures::{FunctionIndex, TypedIndex}; + +use crate::IRecordType; +use crate::IValue; + +use std::rc::Rc; + +pub(crate) type AllocateFunc<'i> = Box LiLoResult + 'i>; +pub(crate) type RecordResolver<'i> = Box LiLoResult> + 'i>; + +pub(super) fn build_allocate_func<'instance, Instance, Export, LocalImport, Memory, MemoryView>( + instance: &'instance Instance, +) -> LiLoResult> +where + Export: wasm::structures::Export + 'instance, + LocalImport: wasm::structures::LocalImport + 'instance, + Memory: wasm::structures::Memory + 'instance, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, +{ + let closure = move |size: usize, ty: usize| { + let index = FunctionIndex::new(ALLOCATE_FUNC_INDEX as usize); + let local_or_import = + instance + .local_or_import(index) + .ok_or(LiLoError::AllocateFuncIsMissing { + function_index: ALLOCATE_FUNC_INDEX, + })?; + + let inputs = vec![IValue::I32(size as _), IValue::I32(ty as _)]; + // TODO: we could check it only once on the module startup or memorize check result + crate::interpreter::instructions::check_function_signature( + instance, + local_or_import, + &inputs, + ) + .map_err(|_| LiLoError::AllocateFuncIncompatibleSignature)?; + + let outcome = local_or_import + .call(&inputs) + .map_err(|_| LiLoError::AllocateCallFailed)?; + + if outcome.len() != 1 { + return Err(LiLoError::AllocateFuncIncompatibleOutput); + } + + match outcome[0] { + IValue::I32(offset) => Ok(offset as _), + _ => Err(LiLoError::AllocateFuncIncompatibleOutput), + } + }; + + Ok(Box::new(closure)) +} + +pub(super) fn build_record_resolver<'instance, Instance, Export, LocalImport, Memory, MemoryView>( + instance: &'instance Instance, +) -> LiLoResult> +where + Export: wasm::structures::Export + 'instance, + LocalImport: wasm::structures::LocalImport + 'instance, + Memory: wasm::structures::Memory + 'instance, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, +{ + let resolver = move |record_type_id: u64| { + let record = instance + .wit_record_by_id(record_type_id) + .ok_or(LiLoError::RecordTypeByNameIsMissing { record_type_id })?; + + Ok(record.clone()) + }; + + Ok(Box::new(resolver)) +} diff --git a/wasmer-it/src/interpreter/instructions/mod.rs b/wasmer-it/src/interpreter/instructions/mod.rs index 9ff83ff..b2c31a5 100644 --- a/wasmer-it/src/interpreter/instructions/mod.rs +++ b/wasmer-it/src/interpreter/instructions/mod.rs @@ -2,24 +2,20 @@ mod argument_get; mod arrays; mod call_core; mod dup; +pub(self) mod lilo; mod numbers; mod records; mod strings; mod swap2; -mod utils; use crate::errors::{ InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError, }; -use crate::instr_error; use crate::interpreter::wasm; use crate::IType; use crate::IValue; use crate::NEVec; -pub use arrays::ser_value_size; -pub use records::record_size; - pub(crate) use argument_get::argument_get; pub(crate) use arrays::*; pub(crate) use call_core::call_core; @@ -28,7 +24,6 @@ pub(crate) use numbers::*; pub(crate) use records::*; pub(crate) use strings::*; pub(crate) use swap2::swap2; -pub(self) use utils::*; use fluence_it_types::NativeType; use serde::Deserialize; @@ -204,8 +199,9 @@ pub(crate) fn to_native<'a, T>( where T: NativeType + TryFrom<&'a IValue, Error = WasmValueNativeCastError>, { - T::try_from(wit_value) - .map_err(|error| InstructionError::new(instruction, InstructionErrorKind::ToNative(error))) + T::try_from(wit_value).map_err(|error| { + InstructionError::from_error_kind(instruction, InstructionErrorKind::ToNative(error)) + }) } pub(crate) fn check_function_signature< @@ -219,8 +215,7 @@ pub(crate) fn check_function_signature< instance: &'instance Instance, local_import: &LocalImport, values: &[IValue], - instruction: Instruction, -) -> Result<(), InstructionError> +) -> Result<(), InstructionErrorKind> where Export: wasm::structures::Export + 'instance, LocalImport: wasm::structures::LocalImport + 'instance, @@ -231,7 +226,7 @@ where let func_inputs = local_import.arguments(); for (func_input_arg, value) in func_inputs.iter().zip(values.iter()) { - is_value_compatible_to_type(instance, &func_input_arg.ty, value, instruction.clone())?; + is_value_compatible_to_type(instance, &func_input_arg.ty, value)?; } Ok(()) @@ -249,8 +244,7 @@ pub(crate) fn is_value_compatible_to_type< instance: &'instance Instance, interface_type: &IType, interface_value: &IValue, - instruction: Instruction, -) -> Result<(), InstructionError> +) -> Result<(), InstructionErrorKind> where Export: wasm::structures::Export + 'instance, LocalImport: wasm::structures::LocalImport + 'instance, @@ -276,14 +270,14 @@ where (IType::ByteArray, IValue::ByteArray(_)) => Ok(()), (IType::Array(ty), IValue::Array(values)) => { for value in values { - is_value_compatible_to_type(instance, ty, value, instruction.clone())? + is_value_compatible_to_type(instance, ty, value)? } Ok(()) } (IType::ByteArray, IValue::Array(values)) => { for value in values { - is_value_compatible_to_type(instance, &IType::U8, value, instruction.clone())? + is_value_compatible_to_type(instance, &IType::U8, value)? } Ok(()) @@ -293,31 +287,20 @@ where return Ok(()); } - instr_error!( - instruction, - InstructionErrorKind::InvalidValueOnTheStack { - expected_type: interface_type.clone(), - received_value: interface_value.clone(), - } - ) + Err(InstructionErrorKind::InvalidValueOnTheStack { + expected_type: interface_type.clone(), + received_value: interface_value.clone(), + }) } (IType::Record(ref record_type_id), IValue::Record(record_fields)) => { - is_record_fields_compatible_to_type( - instance, - *record_type_id, - record_fields, - instruction, - )?; + is_record_fields_compatible_to_type(instance, *record_type_id, record_fields)?; Ok(()) } - _ => instr_error!( - instruction, - InstructionErrorKind::InvalidValueOnTheStack { - expected_type: interface_type.clone(), - received_value: interface_value.clone(), - } - ), + _ => Err(InstructionErrorKind::InvalidValueOnTheStack { + expected_type: interface_type.clone(), + received_value: interface_value.clone(), + }), } } @@ -332,8 +315,7 @@ pub(crate) fn is_record_fields_compatible_to_type< instance: &'instance Instance, record_type_id: u64, record_fields: &[IValue], - instruction: Instruction, -) -> Result<(), InstructionError> +) -> Result<(), InstructionErrorKind> where Export: wasm::structures::Export + 'instance, LocalImport: wasm::structures::LocalImport + 'instance, @@ -341,33 +323,22 @@ where MemoryView: wasm::structures::MemoryView, Instance: wasm::structures::Instance, { - let record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id }, - ) - })?; + let record_type = instance + .wit_record_by_id(record_type_id) + .ok_or(InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id })?; if record_fields.len() != record_type.fields.len() { - return instr_error!( - instruction.clone(), - InstructionErrorKind::InvalidValueOnTheStack { - expected_type: IType::Record(record_type_id), - // unwrap is safe here - len's been already checked - received_value: IValue::Record(NEVec::new(record_fields.to_vec()).unwrap()), - } - ); + return Err(InstructionErrorKind::InvalidValueOnTheStack { + expected_type: IType::Record(record_type_id), + // unwrap is safe here - len's been already checked + received_value: IValue::Record(NEVec::new(record_fields.to_vec()).unwrap()), + }); } for (record_type_field, record_value_field) in record_type.fields.iter().zip(record_fields.iter()) { - is_value_compatible_to_type( - instance, - &record_type_field.ty, - record_value_field, - instruction.clone(), - )?; + is_value_compatible_to_type(instance, &record_type_field.ty, record_value_field)?; } Ok(()) diff --git a/wasmer-it/src/interpreter/instructions/numbers.rs b/wasmer-it/src/interpreter/instructions/numbers.rs index d1ecbab..6eab229 100644 --- a/wasmer-it/src/interpreter/instructions/numbers.rs +++ b/wasmer-it/src/interpreter/instructions/numbers.rs @@ -20,7 +20,7 @@ macro_rules! lowering_lifting { .push({ let converted_value = IValue::$to_variant(value.try_into().map_err( |_| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::LoweringLifting { from: IType::$from_variant, diff --git a/wasmer-it/src/interpreter/instructions/records.rs b/wasmer-it/src/interpreter/instructions/records.rs index 1ac952e..a0a3c00 100644 --- a/wasmer-it/src/interpreter/instructions/records.rs +++ b/wasmer-it/src/interpreter/instructions/records.rs @@ -1,19 +1,12 @@ -mod error; mod lift_record; mod lower_record; -pub use lift_record::record_size; - pub(crate) use lift_record::record_lift_memory_impl; pub(crate) use lower_record::record_lower_memory_impl; -pub(self) use error::LiLoRecordError; -pub(self) type LiLoResult = std::result::Result; - use super::array_lift_memory_impl; use super::array_lower_memory_impl; -use super::read_from_instance_mem; -use super::write_to_instance_mem; +use super::lilo; use crate::instr_error; use crate::interpreter::instructions::{is_record_fields_compatible_to_type, to_native}; @@ -40,7 +33,7 @@ where Box::new({ move |runtime| -> _ { let inputs = runtime.stack.pop(1).ok_or_else(|| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, ) @@ -49,12 +42,12 @@ where let offset: usize = to_native::(&inputs[0], instruction.clone())? .try_into() .map_err(|e| (e, "offset").into()) - .map_err(|k| InstructionError::new(instruction.clone(), k))?; + .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; // TODO: size = 0 let instance = &runtime.wasm_instance; let record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id }, ) @@ -66,8 +59,22 @@ where record_type_id ); - let record = - record_lift_memory_impl(&**instance, record_type, offset, instruction.clone())?; + let memory_index = 0; + let memory_view = instance + .memory(memory_index) + .ok_or_else(|| { + InstructionError::from_error_kind( + instruction.clone(), + InstructionErrorKind::MemoryIsMissing { memory_index }, + ) + })? + .view(); + let memory = memory_view.deref(); + + let li_helper = lilo::LiHelper::new(&**instance, memory) + .map_err(|e| InstructionError::from_lilo(instruction.clone(), e))?; + let record = record_lift_memory_impl(&li_helper, record_type, offset) + .map_err(|e| InstructionError::from_lilo(instruction.clone(), e))?; log::debug!("record.lift_memory: pushing {:?} on the stack", record); runtime.stack.push(record); @@ -101,13 +108,27 @@ where &**instance, record_type_id, &record_fields, - instruction.clone(), - )?; + ) + .map_err(|e| InstructionError::from_error_kind(instruction.clone(), e))?; log::debug!("record.lower_memory: obtained {:?} values on the stack for record type = {}", record_fields, record_type_id); - let offset = - record_lower_memory_impl(*instance, instruction.clone(), record_fields)?; + let memory_index = 0; + let memory_view = instance + .memory(memory_index) + .ok_or_else(|| { + InstructionError::from_error_kind( + instruction.clone(), + InstructionErrorKind::MemoryIsMissing { memory_index }, + ) + })? + .view(); + let memory = memory_view.deref(); + + let lo_helper = lilo::LoHelper::new(&**instance, memory) + .map_err(|e| InstructionError::from_lilo(instruction.clone(), e))?; + let offset = record_lower_memory_impl(&lo_helper, record_fields) + .map_err(|e| InstructionError::from_lilo(instruction.clone(), e))?; log::debug!("record.lower_memory: pushing {} on the stack", offset); runtime.stack.push(IValue::I32(offset)); diff --git a/wasmer-it/src/interpreter/instructions/records/error.rs b/wasmer-it/src/interpreter/instructions/records/error.rs deleted file mode 100644 index 15ce57a..0000000 --- a/wasmer-it/src/interpreter/instructions/records/error.rs +++ /dev/null @@ -1,17 +0,0 @@ -use it_lilo_utils::error::MemoryAccessError; -use thiserror::Error as ThisError; - -#[derive(Debug, ThisError)] -pub(crate) enum LiLoRecordError { - /// This error occurred from out-of-bound memory access. - #[error("{0}")] - MemoryAccessError(#[from] MemoryAccessError), - - /// An error related to not found record in module record types. - #[error("Record with type id {0} not found")] - RecordTypeNotFound(u64), - - /// This error occurred when a record is created from empty values array. - #[error("Record with name '{0}' can't be empty")] - EmptyRecord(String), -} diff --git a/wasmer-it/src/interpreter/instructions/records/lift_record.rs b/wasmer-it/src/interpreter/instructions/records/lift_record.rs index 5793696..0ecc24b 100644 --- a/wasmer-it/src/interpreter/instructions/records/lift_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lift_record.rs @@ -1,27 +1,24 @@ -use super::LiLoRecordError; -use super::LiLoResult; +use super::lilo::*; use crate::IRecordType; use crate::IType; use crate::IValue; use crate::NEVec; -use crate::{ - errors::{InstructionError, InstructionErrorKind}, - interpreter::Instruction, -}; use it_lilo_utils::memory_reader::MemoryReader; use it_lilo_utils::memory_reader::SequentialReader; +use it_lilo_utils::record_size; #[rustfmt::skip] pub(crate) fn record_lift_memory_impl( - reader: &MemoryReader<'_>, + li_helper: &LiHelper<'_>, record_type: &IRecordType, offset: usize, ) -> LiLoResult { let mut values = Vec::with_capacity(record_type.fields.len()); let size = record_size(record_type); + let reader = &li_helper.reader; let seq_reader = reader.sequential_reader(offset, size)?; for field in (*record_type.fields).iter() { @@ -41,45 +38,24 @@ pub(crate) fn record_lift_memory_impl( IType::F64 => values.push(IValue::F64(seq_reader.read_f64())), IType::String => values.push(IValue::String(read_string(reader, &seq_reader)?)), IType::ByteArray => values.push(read_byte_array(reader, &seq_reader)?), - IType::Array(ty) => values.push(read_array(&reader, &seq_reader, &**ty)?), - IType::Record(record_type_id) => values.push(read_record(&reader, &seq_reader, *record_type_id)?), + IType::Array(ty) => values.push(read_array(&li_helper, &seq_reader, &**ty)?), + IType::Record(record_type_id) => values.push(read_record(li_helper, &seq_reader, *record_type_id)?), } } let record = NEVec::new(values.into_iter().collect()) - .map_err(|_| LiLoRecordError::EmptyRecord(record_type.name.clone()))?; + .map_err(|_| LiLoError::EmptyRecord(record_type.name.clone()))?; Ok(IValue::Record(record)) } -/// Returns the record size in bytes. -pub fn record_size(record_type: &IRecordType) -> usize { - let mut record_size = 0; - - for field_type in record_type.fields.iter() { - record_size += match field_type.ty { - IType::Boolean | IType::S8 | IType::U8 => 1, - IType::S16 | IType::U16 => 2, - IType::S32 | IType::U32 | IType::I32 | IType::F32 => 4, - IType::Record(_) => 4, - IType::String | IType::ByteArray | IType::Array(_) => 2 * 4, - IType::S64 | IType::U64 | IType::I64 | IType::F64 => 8, - }; - } - - record_size -} - fn read_string(reader: &MemoryReader, seq_reader: &SequentialReader) -> LiLoResult { let offset = seq_reader.read_u32(); let size = seq_reader.read_u32(); let string_mem = reader.read_raw_u8_array(offset as _, size as _)?; - let string = String::from_utf8(string_mem).map_err(|e| { - InstructionError::new(instruction, InstructionErrorKind::CorruptedUTF8String(e)) - })?; - + let string = String::from_utf8(string_mem)?; Ok(string) } @@ -93,29 +69,24 @@ fn read_byte_array(reader: &MemoryReader, seq_reader: &SequentialReader) -> LiLo } fn read_array( - reader: &MemoryReader, + li_helper: &LiHelper, seq_reader: &SequentialReader, value_type: &IType, ) -> LiLoResult { let offset = seq_reader.read_u32(); let size = seq_reader.read_u32(); - super::array_lift_memory_impl(reader, value_type, offset as _, size as _) + super::array_lift_memory_impl(li_helper, value_type, offset as _, size as _) } fn read_record( - reader: &MemoryReader, + li_helper: &LiHelper, seq_reader: &SequentialReader, record_type_id: u64, ) -> LiLoResult { let offset = seq_reader.read_u32(); - let record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id }, - ) - })?; + let record_type = (li_helper.record_resolver)(record_type_id)?; - record_lift_memory_impl(reader, record_type, offset as _) + record_lift_memory_impl(li_helper, &record_type, offset as _) } diff --git a/wasmer-it/src/interpreter/instructions/records/lower_record.rs b/wasmer-it/src/interpreter/instructions/records/lower_record.rs index 258f744..f32e1d6 100644 --- a/wasmer-it/src/interpreter/instructions/records/lower_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lower_record.rs @@ -1,13 +1,10 @@ -use super::write_to_instance_mem; -use super::LiLoResult; -use super::LiLoRecordError; +use super::lilo::*; + use crate::IValue; use crate::NEVec; -use it_lilo_utils::memory_writer::MemoryWriter; - pub(crate) fn record_lower_memory_impl( - writer: &MemoryWriter, + lo_helper: &LoHelper, values: NEVec, ) -> LiLoResult { let average_field_size = 4; @@ -29,38 +26,34 @@ pub(crate) fn record_lower_memory_impl( IValue::F32(value) => result.extend_from_slice(&value.to_le_bytes()), IValue::F64(value) => result.extend_from_slice(&value.to_le_bytes()), IValue::String(value) => { - let offset = - write_to_instance_mem(instance, instruction.clone(), value.as_bytes())? as u32; + let offset = lo_helper.write_to_mem(value.as_bytes())? as u32; result.extend_from_slice(&offset.to_le_bytes()); result.extend_from_slice(&(value.len() as u32).to_le_bytes()); } IValue::ByteArray(value) => { - let array_pointer = - write_to_instance_mem(instance, instruction.clone(), &value)? as u32; + let offset = lo_helper.write_to_mem(&value)? as u32; - result.extend_from_slice(&array_pointer.to_le_bytes()); + result.extend_from_slice(&offset.to_le_bytes()); result.extend_from_slice(&(value.len() as u32).to_le_bytes()); } IValue::Array(values) => { - let (offset, size) = - super::array_lower_memory_impl(instance, instruction.clone(), values)?; + let (offset, size) = super::array_lower_memory_impl(lo_helper, values)?; result.extend_from_slice(&(offset as u32).to_le_bytes()); result.extend_from_slice(&(size as u32).to_le_bytes()); } IValue::Record(values) => { - let record_ptr = - record_lower_memory_impl(instance, instruction.clone(), values)? as u32; + let offset = record_lower_memory_impl(lo_helper, values)? as u32; - result.extend_from_slice(&record_ptr.to_le_bytes()); + result.extend_from_slice(&offset.to_le_bytes()); } } } - let result_pointer = write_to_instance_mem(instance, instruction, &result)?; + let result_pointer = lo_helper.write_to_mem(&result)?; Ok(result_pointer as _) } diff --git a/wasmer-it/src/interpreter/instructions/strings.rs b/wasmer-it/src/interpreter/instructions/strings.rs index e50367d..1805be0 100644 --- a/wasmer-it/src/interpreter/instructions/strings.rs +++ b/wasmer-it/src/interpreter/instructions/strings.rs @@ -13,7 +13,7 @@ executable_instruction!( string_lift_memory(instruction: Instruction) -> _ { move |runtime| -> _ { let inputs = runtime.stack.pop(2).ok_or_else(|| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 2 }, ) @@ -24,7 +24,7 @@ executable_instruction!( .wasm_instance .memory(memory_index) .ok_or_else(|| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::MemoryIsMissing { memory_index }, ) @@ -33,11 +33,11 @@ executable_instruction!( let pointer: usize = to_native::(&inputs[0], instruction.clone())? .try_into() .map_err(|e| (e, "pointer").into()) - .map_err(|k| InstructionError::new(instruction.clone(), k))?; + .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; let length: usize = to_native::(&inputs[1], instruction.clone())? .try_into() .map_err(|e| (e, "length").into()) - .map_err(|k| InstructionError::new(instruction.clone(), k))?; + .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; let memory_view = memory.view(); if length == 0 { @@ -62,7 +62,7 @@ executable_instruction!( .collect(); let string = String::from_utf8(data) - .map_err(|error| InstructionError::new(instruction.clone(), InstructionErrorKind::String(error)))?; + .map_err(|error| InstructionError::from_error_kind(instruction.clone(), InstructionErrorKind::String(error)))?; log::debug!("string.lift_memory: pushing {:?} on the stack", string); runtime.stack.push(IValue::String(string)); @@ -76,7 +76,7 @@ executable_instruction!( string_lower_memory(instruction: Instruction) -> _ { move |runtime| -> _ { let inputs = runtime.stack.pop(2).ok_or_else(|| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 2 }, ) @@ -85,11 +85,11 @@ executable_instruction!( let string_pointer: usize = to_native::(&inputs[0], instruction.clone())? .try_into() .map_err(|e| (e, "pointer").into()) - .map_err(|k| InstructionError::new(instruction.clone(), k))?; + .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; let string: String = to_native(&inputs[1], instruction.clone())?; let string_bytes = string.as_bytes(); let string_length: i32 = string_bytes.len().try_into().map_err(|_| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::NegativeValue { subject: "string_length" }, ) @@ -100,7 +100,7 @@ executable_instruction!( let memory_view = instance .memory(memory_index) .ok_or_else(|| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::MemoryIsMissing { memory_index }, ) diff --git a/wasmer-it/src/interpreter/instructions/swap2.rs b/wasmer-it/src/interpreter/instructions/swap2.rs index ad08bea..fc855a8 100644 --- a/wasmer-it/src/interpreter/instructions/swap2.rs +++ b/wasmer-it/src/interpreter/instructions/swap2.rs @@ -7,7 +7,7 @@ executable_instruction!( swap2(instruction: Instruction) -> _ { move |runtime| -> _ { let mut values = runtime.stack.pop(2).ok_or_else(|| { - InstructionError::new( + InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, ) diff --git a/wasmer-it/src/interpreter/instructions/utils.rs b/wasmer-it/src/interpreter/instructions/utils.rs deleted file mode 100644 index 0544b40..0000000 --- a/wasmer-it/src/interpreter/instructions/utils.rs +++ /dev/null @@ -1,179 +0,0 @@ -use crate::interpreter::instructions::ALLOCATE_FUNC_INDEX; -use crate::interpreter::wasm; -use crate::interpreter::wasm::structures::{FunctionIndex, TypedIndex}; - -use crate::instr_error; -use crate::interpreter::instructions::to_native; -use crate::IType; -use crate::IValue; -use crate::{ - errors::{InstructionError, InstructionErrorKind}, - interpreter::Instruction, -}; - -pub(super) fn read_from_instance_mem<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, - instruction: Instruction, - offset: usize, - size: usize, -) -> Result, InstructionError> -where - Export: wasm::structures::Export + 'instance, - LocalImport: wasm::structures::LocalImport + 'instance, - Memory: wasm::structures::Memory + 'instance, - MemoryView: wasm::structures::MemoryView, - Instance: wasm::structures::Instance, -{ - if size == 0 { - return Ok(vec![]); - } - - let memory_index = 0; - let memory_view = instance - .memory(memory_index) - .ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::MemoryIsMissing { memory_index }, - ) - })? - .view(); - - log::trace!("reading {} bytes from offset {}", size, offset); - - let right = offset + size; - if right < offset || right >= memory_view.len() { - return instr_error!( - instruction, - InstructionErrorKind::MemoryOutOfBoundsAccess { - index: right, - length: memory_view.len(), - } - ); - } - - Ok((&memory_view[offset..offset + size]) - .iter() - .map(std::cell::Cell::get) - .collect::>()) -} - -pub(super) fn write_to_instance_mem<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, - instruction: Instruction, - bytes: &[u8], -) -> Result -where - Export: wasm::structures::Export + 'instance, - LocalImport: wasm::structures::LocalImport + 'instance, - Memory: wasm::structures::Memory + 'instance, - MemoryView: wasm::structures::MemoryView, - Instance: wasm::structures::Instance, -{ - if bytes.is_empty() { - return Ok(0); - } - - let offset = allocate(instance, instruction.clone(), bytes.len() as _)?; - - let memory_index = 0; - let memory_view = instance - .memory(memory_index) - .ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::MemoryIsMissing { memory_index }, - ) - })? - .view(); - - log::trace!("writing {} bytes from offset {}", bytes.len(), offset); - - let right = offset + bytes.len(); - if right < offset || right >= memory_view.len() { - return instr_error!( - instruction, - InstructionErrorKind::MemoryOutOfBoundsAccess { - index: right, - length: memory_view.len(), - } - ); - } - - for (byte_id, byte) in bytes.iter().enumerate() { - memory_view[offset + byte_id].set(*byte); - } - - Ok(offset) -} - -pub(super) fn allocate<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, - instruction: Instruction, - size: usize, -) -> Result -where - Export: wasm::structures::Export + 'instance, - LocalImport: wasm::structures::LocalImport + 'instance, - Memory: wasm::structures::Memory + 'instance, - MemoryView: wasm::structures::MemoryView, - Instance: wasm::structures::Instance, -{ - let values = call_core( - instance, - ALLOCATE_FUNC_INDEX, - instruction.clone(), - vec![IValue::I32(size as _)], - )?; - if values.len() != 1 { - return instr_error!( - instruction, - InstructionErrorKind::LocalOrImportSignatureMismatch { - function_index: ALLOCATE_FUNC_INDEX, - expected: (vec![IType::I32], vec![]), - received: (vec![], vec![]), - } - ); - } - to_native::(&values[0], instruction).map(|v| v as usize) -} - -fn call_core<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, - function_index: u32, - instruction: Instruction, - inputs: Vec, -) -> Result, InstructionError> -where - Export: wasm::structures::Export + 'instance, - LocalImport: wasm::structures::LocalImport + 'instance, - Memory: wasm::structures::Memory + 'instance, - MemoryView: wasm::structures::MemoryView, - Instance: wasm::structures::Instance, -{ - let index = FunctionIndex::new(function_index as usize); - let local_or_import = instance.local_or_import(index).ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::LocalOrImportIsMissing { function_index }, - ) - })?; - - crate::interpreter::instructions::check_function_signature( - instance, - local_or_import, - &inputs, - instruction.clone(), - )?; - - let outputs = local_or_import.call(&inputs).map_err(|_| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::LocalOrImportCall { - function_name: local_or_import.name().to_string(), - }, - ) - })?; - - Ok(outputs) -} diff --git a/wasmer-it/src/interpreter/mod.rs b/wasmer-it/src/interpreter/mod.rs index 246d0e8..868f76f 100644 --- a/wasmer-it/src/interpreter/mod.rs +++ b/wasmer-it/src/interpreter/mod.rs @@ -4,8 +4,6 @@ mod instructions; pub mod stack; pub mod wasm; -pub use instructions::record_size; -pub use instructions::ser_value_size; pub use instructions::Instruction; use crate::errors::{InstructionResult, InterpreterResult}; diff --git a/wasmer-it/src/lib.rs b/wasmer-it/src/lib.rs index 5b55510..d4d5936 100644 --- a/wasmer-it/src/lib.rs +++ b/wasmer-it/src/lib.rs @@ -74,9 +74,6 @@ pub use fluence_it_types::IValue; pub use it_to_bytes::ToBytes; -pub use crate::interpreter::record_size; -pub use crate::interpreter::ser_value_size; - #[cfg(feature = "serde")] pub use crate::serde::de::from_interface_values;