mirror of
https://github.com/fluencelabs/interface-types
synced 2024-12-04 15:20:20 +00:00
save point
This commit is contained in:
parent
5d219e963b
commit
aa8ab1b1e3
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -272,6 +272,7 @@ dependencies = [
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"wast",
|
||||
]
|
||||
|
||||
|
@ -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<T> = std::result::Result<T, error::MemoryAccessError>;
|
||||
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<SequentialWriter<'_, '_>> {
|
||||
pub fn sequential_writer(
|
||||
&self,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
) -> MResult<SequentialWriter<'_, '_>> {
|
||||
self.check_access(offset, size)?;
|
||||
|
||||
Ok(SequentialWriter::new(&self, offset))
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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::<i32>(&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::<i32>(&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",
|
||||
|
@ -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<IValue, InstructionError>
|
||||
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>
|
||||
+ 'instance,
|
||||
{
|
||||
) -> LiLoResult<IValue> {
|
||||
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<Vec<IValue>> {
|
||||
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<Vec<IValue>> {
|
||||
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<Vec<IValue>> {
|
||||
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)
|
||||
}
|
||||
|
@ -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, Export, LocalImport, Memory, MemoryView>(
|
||||
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<IValue>,
|
||||
) -> Result<(usize, usize), InstructionError>
|
||||
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>,
|
||||
{
|
||||
) -> 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,
|
||||
}
|
||||
}
|
||||
|
@ -1,48 +0,0 @@
|
||||
use std::cell::Cell;
|
||||
|
||||
pub(super) struct MemoryWriter<'m> {
|
||||
memory_view: &'m [Cell<u8>],
|
||||
offset: Cell<usize>,
|
||||
}
|
||||
|
||||
impl<'m> MemoryWriter<'m> {
|
||||
pub(crate) fn new(memory_view: &'m [Cell<u8>], 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<const N: usize>(&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());
|
||||
}
|
||||
}
|
@ -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<IValue, InstructionError>
|
||||
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>,
|
||||
{
|
||||
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<u8>]) -> Vec<IValue>,
|
||||
) -> Result<Vec<IValue>, InstructionError>
|
||||
where
|
||||
Export: wasm::structures::Export + 'instance,
|
||||
LocalImport: wasm::structures::LocalImport + 'instance,
|
||||
Memory: wasm::structures::Memory<MemoryView> + 'instance,
|
||||
MemoryView: wasm::structures::MemoryView + 'instance,
|
||||
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
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<u8>]| {
|
||||
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<u8>]| {
|
||||
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<u8>]| {
|
||||
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<u8>]| {
|
||||
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<u8>]| {
|
||||
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<u8>]| {
|
||||
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<u8>]| {
|
||||
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<u8>]| {
|
||||
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<u8>]| {
|
||||
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<u8>]| {
|
||||
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<u8>]| {
|
||||
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<u8>]| {
|
||||
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<u8>]| {
|
||||
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<IValue, InstructionError>
|
||||
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>
|
||||
+ 'instance,
|
||||
{
|
||||
let data = read_from_instance_mem(
|
||||
instance,
|
||||
instruction.clone(),
|
||||
offset,
|
||||
WASM_POINTER_SIZE * elements_count,
|
||||
)?;
|
||||
let data = transmute_many::<u32, AllOrNothingGuard>(&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<IValue, InstructionError>
|
||||
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>
|
||||
+ '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::<u32, AllOrNothingGuard>(&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<IValue, InstructionError>
|
||||
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>
|
||||
+ 'instance,
|
||||
{
|
||||
let data = read_from_instance_mem(
|
||||
instance,
|
||||
instruction.clone(),
|
||||
offset,
|
||||
WASM_POINTER_SIZE * elements_count,
|
||||
)?;
|
||||
let data = transmute_many::<u32, AllOrNothingGuard>(&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)
|
||||
}
|
@ -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(),
|
||||
|
@ -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 },
|
||||
)
|
||||
|
36
wasmer-it/src/interpreter/instructions/lilo/li_helper.rs
Normal file
36
wasmer-it/src/interpreter/instructions/lilo/li_helper.rs
Normal file
@ -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, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance Instance,
|
||||
memory: &'instance [Cell<u8>],
|
||||
) -> LiLoResult<Self>
|
||||
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>,
|
||||
{
|
||||
let record_resolver = super::build_record_resolver(instance)?;
|
||||
let reader = MemoryReader::new(memory);
|
||||
|
||||
let helper = Self {
|
||||
reader,
|
||||
record_resolver,
|
||||
};
|
||||
|
||||
Ok(helper)
|
||||
}
|
||||
}
|
45
wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs
Normal file
45
wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs
Normal file
@ -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, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance Instance,
|
||||
memory: &'instance [Cell<u8>],
|
||||
) -> LiLoResult<Self>
|
||||
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>,
|
||||
{
|
||||
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<usize> {
|
||||
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)
|
||||
}
|
||||
}
|
13
wasmer-it/src/interpreter/instructions/lilo/mod.rs
Normal file
13
wasmer-it/src/interpreter/instructions/lilo/mod.rs
Normal file
@ -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<T> = std::result::Result<T, LiLoError>;
|
||||
|
||||
pub(self) use utils::*;
|
79
wasmer-it/src/interpreter/instructions/lilo/utils.rs
Normal file
79
wasmer-it/src/interpreter/instructions/lilo/utils.rs
Normal file
@ -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<dyn Fn(usize, usize) -> LiLoResult<usize> + 'i>;
|
||||
pub(crate) type RecordResolver<'i> = Box<dyn Fn(u64) -> LiLoResult<Rc<IRecordType>> + 'i>;
|
||||
|
||||
pub(super) fn build_allocate_func<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance Instance,
|
||||
) -> LiLoResult<AllocateFunc<'instance>>
|
||||
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>,
|
||||
{
|
||||
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<RecordResolver<'instance>>
|
||||
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>,
|
||||
{
|
||||
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))
|
||||
}
|
@ -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<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
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(())
|
||||
|
@ -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,
|
||||
|
@ -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<T> = std::result::Result<T, LiLoRecordError>;
|
||||
|
||||
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::<i32>(&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));
|
||||
|
@ -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),
|
||||
}
|
@ -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<IValue> {
|
||||
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<String> {
|
||||
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<IValue> {
|
||||
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<IValue> {
|
||||
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 _)
|
||||
}
|
||||
|
@ -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<IValue>,
|
||||
) -> LiLoResult<i32> {
|
||||
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 _)
|
||||
}
|
||||
|
@ -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::<i32>(&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::<i32>(&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::<i32>(&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 },
|
||||
)
|
||||
|
@ -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 },
|
||||
)
|
||||
|
@ -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<Vec<u8>, InstructionError>
|
||||
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>,
|
||||
{
|
||||
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::<Vec<u8>>())
|
||||
}
|
||||
|
||||
pub(super) fn write_to_instance_mem<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance Instance,
|
||||
instruction: Instruction,
|
||||
bytes: &[u8],
|
||||
) -> Result<usize, InstructionError>
|
||||
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>,
|
||||
{
|
||||
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<usize, InstructionError>
|
||||
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>,
|
||||
{
|
||||
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::<i32>(&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<IValue>,
|
||||
) -> Result<Vec<IValue>, InstructionError>
|
||||
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>,
|
||||
{
|
||||
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)
|
||||
}
|
@ -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};
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user