From 41555d4d32a32e64f548d8140450b869cf3a2881 Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 18 Apr 2021 19:43:29 +0300 Subject: [PATCH 01/27] improve array passing --- Cargo.lock | 16 + crates/it-types/src/impls/types.rs | 14 +- crates/it-types/src/types.rs | 12 +- crates/it-types/src/values.rs | 9 +- wasmer-it/Cargo.toml | 1 + wasmer-it/src/decoders/binary.rs | 3 +- wasmer-it/src/encoders/wat.rs | 1 - wasmer-it/src/errors.rs | 10 + .../interpreter/instructions/argument_get.rs | 12 +- .../src/interpreter/instructions/arrays.rs | 208 ++------ .../instructions/arrays/read_arrays.rs | 476 ++++++++++++++++++ wasmer-it/src/interpreter/instructions/mod.rs | 14 +- .../src/interpreter/instructions/numbers.rs | 12 +- .../src/interpreter/instructions/records.rs | 16 +- .../src/interpreter/instructions/strings.rs | 20 +- .../src/interpreter/instructions/utils.rs | 19 +- wasmer-it/src/interpreter/mod.rs | 9 - 17 files changed, 624 insertions(+), 228 deletions(-) create mode 100644 wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs diff --git a/Cargo.lock b/Cargo.lock index 05ae0f4..9c1243f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + [[package]] name = "fluence-it-types" version = "0.1.1" @@ -34,6 +40,15 @@ dependencies = [ name = "it-to-bytes" version = "0.1.0" +[[package]] +name = "itertools" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.7" @@ -214,6 +229,7 @@ version = "0.19.0" dependencies = [ "fluence-it-types", "it-to-bytes", + "itertools", "log", "nom", "safe-transmute", diff --git a/crates/it-types/src/impls/types.rs b/crates/it-types/src/impls/types.rs index 963818a..afc9b86 100644 --- a/crates/it-types/src/impls/types.rs +++ b/crates/it-types/src/impls/types.rs @@ -18,6 +18,7 @@ where { fn to_bytes(&self, writer: &mut W) -> io::Result<()> { match self { + IType::Boolean => 0x0b_u8.to_bytes(writer), IType::S8 => 0x00_u8.to_bytes(writer), IType::S16 => 0x01_u8.to_bytes(writer), IType::S32 => 0x02_u8.to_bytes(writer), @@ -29,11 +30,11 @@ where IType::F32 => 0x08_u8.to_bytes(writer), IType::F64 => 0x09_u8.to_bytes(writer), IType::String => 0x0a_u8.to_bytes(writer), + IType::ByteArray => 0x3C_u8.to_bytes(writer), IType::Array(ty) => { 0x36_u8.to_bytes(writer)?; ty.to_bytes(writer) } - IType::Anyref => 0x0b_u8.to_bytes(writer), IType::I32 => 0x0c_u8.to_bytes(writer), IType::I64 => 0x0d_u8.to_bytes(writer), IType::Record(record_id) => { @@ -77,6 +78,7 @@ mod keyword { custom_keyword!(field); // New types. + custom_keyword!(boolean); custom_keyword!(s8); custom_keyword!(s16); custom_keyword!(s32); @@ -92,7 +94,11 @@ mod keyword { impl Parse<'_> for IType { fn parse(parser: Parser<'_>) -> Result { let mut lookahead = parser.lookahead1(); - if lookahead.peek::() { + if lookahead.peek::() { + parser.parse::()?; + + Ok(IType::Boolean) + } else if lookahead.peek::() { parser.parse::()?; Ok(IType::S8) @@ -142,10 +148,6 @@ impl Parse<'_> for IType { let array_type = parser.parens(|p| p.parse())?; Ok(IType::Array(Box::new(array_type))) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(IType::Anyref) } else if lookahead.peek::() { parser.parse::()?; diff --git a/crates/it-types/src/types.rs b/crates/it-types/src/types.rs index 70ca577..c3caced 100644 --- a/crates/it-types/src/types.rs +++ b/crates/it-types/src/types.rs @@ -8,6 +8,9 @@ use serde::Serialize; /// Represents the types supported by WIT. #[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)] pub enum IType { + /// Boolean. + Boolean, + /// A 8-bits signed integer. S8, @@ -41,12 +44,12 @@ pub enum IType { /// A string. String, + /// Specialization of arrays for byte vector. + ByteArray, + /// An array of values of the same type. Array(Box), - /// An `any` reference. - Anyref, - /// A 32-bits integer (as defined in WebAssembly core). I32, @@ -98,6 +101,7 @@ impl Default for RecordType { impl ToString for &IType { fn to_string(&self) -> String { match &self { + IType::Boolean => "boolean".to_string(), IType::S8 => "s8".to_string(), IType::S16 => "s16".to_string(), IType::S32 => "s32".to_string(), @@ -109,8 +113,8 @@ impl ToString for &IType { IType::F32 => "f32".to_string(), IType::F64 => "f64".to_string(), IType::String => "string".to_string(), + IType::ByteArray => "array (u8)".to_string(), IType::Array(ty) => format!("array ({})", ty.as_ref().to_string()), - IType::Anyref => "anyref".to_string(), IType::I32 => "i32".to_string(), IType::I64 => "i64".to_string(), IType::Record(record_type_id) => format!("record {}", record_type_id), diff --git a/crates/it-types/src/values.rs b/crates/it-types/src/values.rs index a2835f2..2e0a237 100644 --- a/crates/it-types/src/values.rs +++ b/crates/it-types/src/values.rs @@ -5,6 +5,9 @@ use crate::ne_vec::NEVec; /// A WIT value. #[derive(Debug, Clone, PartialEq)] pub enum IValue { + /// Boolean value. + Boolean(bool), + /// A 8-bits signed integer. S8(i8), @@ -38,14 +41,16 @@ pub enum IValue { /// A string. String(String), + /// Specialization of array type for byte vector. + ByteArray(Vec), + /// A byte array. Array(Vec), - //Anyref(?), /// A 32-bits integer (as defined in WebAssembly core). I32(i32), - /// A 64-bits integer (as defiend in WebAssembly core). + /// A 64-bits integer (as defined in WebAssembly core). I64(i64), /// A record. diff --git a/wasmer-it/Cargo.toml b/wasmer-it/Cargo.toml index 4e0d8bb..9b1521b 100644 --- a/wasmer-it/Cargo.toml +++ b/wasmer-it/Cargo.toml @@ -21,6 +21,7 @@ serde = { version = "1.0", features = ["derive", "rc"], optional = true } serde_json = "1.0" safe-transmute = "0.11.0" log = "0.4.11" +itertools = "0.10.0" semver = "0.11.0" diff --git a/wasmer-it/src/decoders/binary.rs b/wasmer-it/src/decoders/binary.rs index aeff345..9868d65 100644 --- a/wasmer-it/src/decoders/binary.rs +++ b/wasmer-it/src/decoders/binary.rs @@ -112,6 +112,7 @@ fn ty<'input, E: ParseError<&'input [u8]>>( consume!((input, opcode) = byte(input)?); let ty = match opcode { + 0x0b => IType::Boolean, 0x00 => IType::S8, 0x01 => IType::S16, 0x02 => IType::S32, @@ -123,12 +124,12 @@ fn ty<'input, E: ParseError<&'input [u8]>>( 0x08 => IType::F32, 0x09 => IType::F64, 0x0a => IType::String, + 0x3c => IType::ByteArray, 0x36 => { consume!((input, array_value_type) = ty(input)?); IType::Array(Box::new(array_value_type)) } - 0x0b => IType::Anyref, 0x0c => IType::I32, 0x0d => IType::I64, 0x0e => { diff --git a/wasmer-it/src/encoders/wat.rs b/wasmer-it/src/encoders/wat.rs index cbb89f5..ca71739 100644 --- a/wasmer-it/src/encoders/wat.rs +++ b/wasmer-it/src/encoders/wat.rs @@ -354,7 +354,6 @@ mod tests { (&IType::F32).to_string(), (&IType::F64).to_string(), (&IType::String).to_string(), - (&IType::Anyref).to_string(), (&IType::I32).to_string(), (&IType::I64).to_string(), (&IType::Record(RecordType { diff --git a/wasmer-it/src/errors.rs b/wasmer-it/src/errors.rs index 215e291..7f63489 100644 --- a/wasmer-it/src/errors.rs +++ b/wasmer-it/src/errors.rs @@ -41,6 +41,16 @@ impl InstructionError { impl Error for InstructionError {} +#[macro_export] +macro_rules! instr_error { + ($instruction:expr, $error_kind:expr) => { + Err(crate::errors::InstructionError::new( + $instruction, + $error_kind, + )) + }; +} + impl Display for InstructionError { fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { write!( diff --git a/wasmer-it/src/interpreter/instructions/argument_get.rs b/wasmer-it/src/interpreter/instructions/argument_get.rs index 35825e4..f0c4be4 100644 --- a/wasmer-it/src/interpreter/instructions/argument_get.rs +++ b/wasmer-it/src/interpreter/instructions/argument_get.rs @@ -1,7 +1,5 @@ -use crate::{ - errors::{InstructionError, InstructionErrorKind}, - interpreter::Instruction, -}; +use crate::instr_error; +use crate::{errors::InstructionErrorKind, interpreter::Instruction}; executable_instruction!( argument_get(index: u32, instruction: Instruction) -> _ { @@ -9,10 +7,10 @@ executable_instruction!( let invocation_inputs = runtime.invocation_inputs; if (index as usize) >= invocation_inputs.len() { - return Err(InstructionError::new( + return instr_error!( instruction.clone(), - InstructionErrorKind::InvocationInputIsMissing { index }, - )); + InstructionErrorKind::InvocationInputIsMissing { index } + ); } log::debug!("arg.get: pushing {:?} on the stack", invocation_inputs[index as usize]); diff --git a/wasmer-it/src/interpreter/instructions/arrays.rs b/wasmer-it/src/interpreter/instructions/arrays.rs index fb7e307..28d732f 100644 --- a/wasmer-it/src/interpreter/instructions/arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays.rs @@ -1,6 +1,11 @@ -use super::read_from_instance_mem; -use super::write_to_instance_mem; +mod read_arrays; +use super::read_from_instance_mem; +use super::record_lift_memory_; +use super::write_to_instance_mem; +use read_arrays::*; + +use crate::instr_error; use crate::interpreter::instructions::to_native; use crate::{ errors::{InstructionError, InstructionErrorKind}, @@ -14,9 +19,9 @@ pub(super) fn array_lift_memory_<'instance, Instance, Export, LocalImport, Memor instance: &'instance Instance, value_type: &IType, offset: usize, - size: usize, + elements_count: usize, instruction: Instruction, -) -> Result, InstructionError> +) -> Result where Export: crate::interpreter::wasm::structures::Export, LocalImport: crate::interpreter::wasm::structures::LocalImport, @@ -25,162 +30,43 @@ where Instance: crate::interpreter::wasm::structures::Instance + 'instance, { - use safe_transmute::guard::AllOrNothingGuard; - use safe_transmute::transmute_many; - use safe_transmute::transmute_vec; - - if size == 0 { - return Ok(vec![]); + if elements_count == 0 { + return Ok(IValue::Array(vec![])); } - let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?; - - let result_array = match value_type { - IType::S8 => { - let data = transmute_vec::(data).unwrap(); - data.into_iter().map(IValue::S8).collect::>() - } - IType::S16 => { - let data = transmute_many::(&data).unwrap(); - - data.iter().map(|v| IValue::S16(*v)).collect::>() - } - IType::S32 => { - let data = transmute_many::(&data).unwrap(); - data.iter().map(|v| IValue::S32(*v)).collect::>() - } - IType::S64 => { - let data = transmute_many::(&data).unwrap(); - data.iter().map(|v| IValue::S64(*v)).collect::>() - } - IType::I32 => { - let data = transmute_many::(&data).unwrap(); - data.iter().map(|v| IValue::I32(*v)).collect::>() - } - IType::I64 => { - let data = transmute_many::(&data).unwrap(); - data.iter().map(|v| IValue::S64(*v)).collect::>() - } - IType::U8 => data.into_iter().map(IValue::U8).collect::>(), - IType::U16 => { - let data = transmute_many::(&data).unwrap(); - data.iter().map(|v| IValue::U16(*v)).collect::>() - } - IType::U32 => { - let data = transmute_many::(&data).unwrap(); - data.iter().map(|v| IValue::U32(*v)).collect::>() - } - IType::U64 => { - let data = transmute_many::(&data).unwrap(); - data.iter().map(|v| IValue::U64(*v)).collect::>() - } - IType::F32 => { - let data = transmute_many::(&data).unwrap(); - data.iter() - .map(|v| IValue::F32(f32::from_bits(*v))) - .collect::>() - } - IType::F64 => { - let data = transmute_many::(&data).unwrap(); - data.iter() - .map(|v| IValue::F64(f64::from_bits(*v))) - .collect::>() - } - IType::Anyref => unimplemented!(), - IType::String => { - let data = transmute_many::(&data).unwrap(); - - if data.is_empty() { - return Ok(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 _, - )?; - - // TODO: check - let string = String::from_utf8(string_mem).unwrap(); - result.push(IValue::String(string)); - } - - result - } + match value_type { + IType::Boolean => read_bool_array(instance, instruction.clone(), offset, elements_count), + IType::S8 => read_s8_array(instance, instruction.clone(), offset, elements_count), + IType::S16 => read_s16_array(instance, instruction.clone(), offset, elements_count), + IType::S32 => read_s32_array(instance, instruction.clone(), offset, elements_count), + IType::S64 => read_s64_array(instance, instruction.clone(), offset, elements_count), + IType::I32 => read_i32_array(instance, instruction.clone(), offset, elements_count), + IType::I64 => read_i64_array(instance, instruction.clone(), offset, elements_count), + IType::U8 => read_u8_array(instance, instruction.clone(), offset, elements_count), + IType::U16 => read_u16_array(instance, instruction.clone(), offset, elements_count), + IType::U32 => read_u32_array(instance, instruction.clone(), offset, elements_count), + IType::U64 => read_u64_array(instance, instruction.clone(), offset, elements_count), + IType::F32 => read_f32_array(instance, instruction.clone(), offset, elements_count), + IType::F64 => read_f64_array(instance, instruction.clone(), offset, elements_count), + IType::String => read_string_array(instance, instruction.clone(), offset, elements_count), + IType::Record(record_type_id) => read_record_array( + instance, + instruction.clone(), + *record_type_id, + offset, + elements_count, + ), + IType::ByteArray => read_array_array( + instance, + instruction.clone(), + &IType::ByteArray, + offset, + elements_count, + ), IType::Array(ty) => { - let data = transmute_many::(&data).unwrap(); - - if data.is_empty() { - return Ok(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 = array_lift_memory_( - instance, - &*ty, - *array_offset as _, - *array_size as _, - instruction.clone(), - )?; - - result.push(IValue::Array(value)); - } - - result + read_array_array(instance, instruction.clone(), &ty, offset, elements_count) } - IType::Record(record_type_id) => { - let record_type = instance.wit_record_by_id(*record_type_id).ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::RecordTypeByNameIsMissing { - record_type_id: *record_type_id, - }, - ) - })?; - - 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_( - instance, - record_type, - *record_offset as _, - instruction.clone(), - )?); - } - result - } - }; - - Ok(result_array) + } } pub(crate) fn array_lift_memory( @@ -233,7 +119,7 @@ where )?; log::trace!("array.lift_memory: pushing {:?} on the stack", array); - runtime.stack.push(IValue::Array(array)); + runtime.stack.push(array); Ok(()) } @@ -356,13 +242,13 @@ where Ok(()) } - _ => Err(InstructionError::new( + _ => instr_error!( instruction.clone(), InstructionErrorKind::InvalidValueOnTheStack { expected_type: IType::Array(Box::new(value_type.clone())), - received_value: stack_value.clone(), - }, - )), + received_value: stack_value.clone() + } + ), } } }) diff --git a/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs b/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs new file mode 100644 index 0000000..dafd139 --- /dev/null +++ b/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs @@ -0,0 +1,476 @@ +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) + } + }; +} + +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: u32 = 0; + let memory_view = instance + .memory(memory_index as usize) + .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 == 1)); + } + + 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_be_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_be_bytes([ + Cell::get(&memory_view[2 * element_id]), + Cell::get(&memory_view[2 * element_id + 1]), + ]); + 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_be_bytes([ + Cell::get(&memory_view[2 * element_id]), + Cell::get(&memory_view[2 * element_id + 1]), + ]); + 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_be_bytes([ + Cell::get(&memory_view[4 * element_id]), + Cell::get(&memory_view[4 * element_id + 1]), + Cell::get(&memory_view[4 * element_id + 2]), + Cell::get(&memory_view[4 * element_id + 3]), + ]); + 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_be_bytes([ + Cell::get(&memory_view[4 * element_id]), + Cell::get(&memory_view[4 * element_id + 1]), + Cell::get(&memory_view[4 * element_id + 2]), + Cell::get(&memory_view[4 * element_id + 3]), + ]); + 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_be_bytes([ + Cell::get(&memory_view[4 * element_id]), + Cell::get(&memory_view[4 * element_id + 1]), + Cell::get(&memory_view[4 * element_id + 2]), + Cell::get(&memory_view[4 * element_id + 3]), + ]); + 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_be_bytes([ + Cell::get(&memory_view[4 * element_id]), + Cell::get(&memory_view[4 * element_id + 1]), + Cell::get(&memory_view[4 * element_id + 2]), + Cell::get(&memory_view[4 * element_id + 3]), + ]); + 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_be_bytes([ + Cell::get(&memory_view[4 * element_id]), + Cell::get(&memory_view[4 * element_id + 1]), + Cell::get(&memory_view[4 * element_id + 2]), + Cell::get(&memory_view[4 * element_id + 3]), + Cell::get(&memory_view[4 * element_id + 4]), + Cell::get(&memory_view[4 * element_id + 5]), + Cell::get(&memory_view[4 * element_id + 6]), + Cell::get(&memory_view[4 * element_id + 7]), + ]); + 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_be_bytes([ + Cell::get(&memory_view[4 * element_id]), + Cell::get(&memory_view[4 * element_id + 1]), + Cell::get(&memory_view[4 * element_id + 2]), + Cell::get(&memory_view[4 * element_id + 3]), + Cell::get(&memory_view[4 * element_id + 4]), + Cell::get(&memory_view[4 * element_id + 5]), + Cell::get(&memory_view[4 * element_id + 6]), + Cell::get(&memory_view[4 * element_id + 7]), + ]); + 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_be_bytes([ + Cell::get(&memory_view[4 * element_id]), + Cell::get(&memory_view[4 * element_id + 1]), + Cell::get(&memory_view[4 * element_id + 2]), + Cell::get(&memory_view[4 * element_id + 3]), + Cell::get(&memory_view[4 * element_id + 4]), + Cell::get(&memory_view[4 * element_id + 5]), + Cell::get(&memory_view[4 * element_id + 6]), + Cell::get(&memory_view[4 * element_id + 7]), + ]); + 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_be_bytes([ + Cell::get(&memory_view[4 * element_id]), + Cell::get(&memory_view[4 * element_id + 1]), + Cell::get(&memory_view[4 * element_id + 2]), + Cell::get(&memory_view[4 * element_id + 3]), + Cell::get(&memory_view[4 * element_id + 4]), + Cell::get(&memory_view[4 * element_id + 5]), + Cell::get(&memory_view[4 * element_id + 6]), + Cell::get(&memory_view[4 * element_id + 7]), + ]); + 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 _, + )?; + + // TODO: check + let string = String::from_utf8(string_mem).unwrap(); + 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_( + 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_( + 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/mod.rs b/wasmer-it/src/interpreter/instructions/mod.rs index d4b2744..6f70ef4 100644 --- a/wasmer-it/src/interpreter/instructions/mod.rs +++ b/wasmer-it/src/interpreter/instructions/mod.rs @@ -11,10 +11,12 @@ 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(crate) use argument_get::argument_get; pub(crate) use arrays::*; pub(crate) use call_core::call_core; @@ -292,13 +294,13 @@ where Ok(()) } - _ => Err(InstructionError::new( + _ => instr_error!( instruction, InstructionErrorKind::InvalidValueOnTheStack { expected_type: interface_type.clone(), received_value: interface_value.clone(), - }, - )), + } + ), } } @@ -330,14 +332,14 @@ where })?; if record_fields.len() != record_type.fields.len() { - return Err(InstructionError::new( + 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()), - }, - )); + } + ); } for (record_type_field, record_value_field) in diff --git a/wasmer-it/src/interpreter/instructions/numbers.rs b/wasmer-it/src/interpreter/instructions/numbers.rs index a85c109..30de571 100644 --- a/wasmer-it/src/interpreter/instructions/numbers.rs +++ b/wasmer-it/src/interpreter/instructions/numbers.rs @@ -1,9 +1,11 @@ +use crate::instr_error; use crate::IType; use crate::IValue; use crate::{ errors::{InstructionError, InstructionErrorKind}, interpreter::Instruction, }; + use std::convert::TryInto; macro_rules! lowering_lifting { @@ -34,20 +36,20 @@ macro_rules! lowering_lifting { }) } Some(wrong_value) => { - return Err(InstructionError::new( + return instr_error!( instruction.clone(), InstructionErrorKind::InvalidValueOnTheStack { expected_type: IType::$from_variant, received_value: wrong_value, } - )) + ) }, None => { - return Err(InstructionError::new( + return instr_error!( instruction.clone(), - InstructionErrorKind::StackIsTooSmall { needed: 1 }, - )) + InstructionErrorKind::StackIsTooSmall { needed: 1 } + ) } } diff --git a/wasmer-it/src/interpreter/instructions/records.rs b/wasmer-it/src/interpreter/instructions/records.rs index abd1c95..ede5fc0 100644 --- a/wasmer-it/src/interpreter/instructions/records.rs +++ b/wasmer-it/src/interpreter/instructions/records.rs @@ -1,6 +1,7 @@ use super::read_from_instance_mem; use super::write_to_instance_mem; +use crate::instr_error; use crate::interpreter::instructions::{is_record_fields_compatible_to_type, to_native}; use crate::IRecordType; use crate::IType; @@ -175,7 +176,6 @@ where values.push(IValue::F32(value as _)); } IType::F64 => values.push(IValue::F64(f64::from_bits(value))), - IType::Anyref => {} IType::String => { let string_offset = value; field_id += 1; @@ -209,7 +209,7 @@ where array_size as _, instruction.clone(), )?; - values.push(IValue::Array(array)); + values.push(array); } else { values.push(IValue::Array(vec![])); } @@ -399,17 +399,17 @@ where Ok(()) } - Some(value) => Err(InstructionError::new( + Some(value) => instr_error!( instruction.clone(), InstructionErrorKind::InvalidValueOnTheStack { expected_type: IType::Record(record_type_id), received_value: value, - }, - )), - None => Err(InstructionError::new( + } + ), + None => instr_error!( instruction.clone(), - InstructionErrorKind::StackIsTooSmall { needed: 1 }, - )), + InstructionErrorKind::StackIsTooSmall { needed: 1 } + ), } } }) diff --git a/wasmer-it/src/interpreter/instructions/strings.rs b/wasmer-it/src/interpreter/instructions/strings.rs index d8ffed6..b3c2ae2 100644 --- a/wasmer-it/src/interpreter/instructions/strings.rs +++ b/wasmer-it/src/interpreter/instructions/strings.rs @@ -1,10 +1,12 @@ use super::to_native; +use crate::instr_error; use crate::IType; use crate::IValue; use crate::{ errors::{InstructionError, InstructionErrorKind}, interpreter::Instruction, }; + use std::{cell::Cell, convert::TryInto}; executable_instruction!( @@ -45,13 +47,13 @@ executable_instruction!( } if memory_view.len() < pointer + length { - return Err(InstructionError::new( + return instr_error!( instruction.clone(), InstructionErrorKind::MemoryOutOfBoundsAccess { index: pointer + length, length: memory_view.len(), - }, - )); + } + ); } let data: Vec = (&memory_view[pointer..pointer + length]) @@ -131,18 +133,18 @@ executable_instruction!( Ok(()) }, - Some(value) => Err(InstructionError::new( + Some(value) => instr_error!( instruction.clone(), InstructionErrorKind::InvalidValueOnTheStack { expected_type: IType::String, received_value: (&value).clone(), - }, - )), + } + ), - None => Err(InstructionError::new( + None => instr_error!( instruction.clone(), - InstructionErrorKind::StackIsTooSmall { needed: 1 }, - )), + InstructionErrorKind::StackIsTooSmall { needed: 1 } + ), } } } diff --git a/wasmer-it/src/interpreter/instructions/utils.rs b/wasmer-it/src/interpreter/instructions/utils.rs index 507ebf7..8a330f1 100644 --- a/wasmer-it/src/interpreter/instructions/utils.rs +++ b/wasmer-it/src/interpreter/instructions/utils.rs @@ -2,6 +2,7 @@ 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; @@ -38,13 +39,13 @@ where let right = offset + size; if right < offset || right >= memory_view.len() { - return Err(InstructionError::new( + return instr_error!( instruction, InstructionErrorKind::MemoryOutOfBoundsAccess { index: right, length: memory_view.len(), - }, - )); + } + ); } Ok((&memory_view[offset..offset + size]) @@ -82,13 +83,13 @@ where let right = offset + bytes.len(); if right < offset || right >= memory_view.len() { - return Err(InstructionError::new( + return instr_error!( instruction, InstructionErrorKind::MemoryOutOfBoundsAccess { index: right, length: memory_view.len(), - }, - )); + } + ); } for (byte_id, byte) in bytes.iter().enumerate() { @@ -117,14 +118,14 @@ where vec![IValue::I32(size as _)], )?; if values.len() != 1 { - return Err(InstructionError::new( + 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) } diff --git a/wasmer-it/src/interpreter/mod.rs b/wasmer-it/src/interpreter/mod.rs index 9c023aa..8aada2e 100644 --- a/wasmer-it/src/interpreter/mod.rs +++ b/wasmer-it/src/interpreter/mod.rs @@ -242,15 +242,6 @@ where let value_type = value_type.clone(); instructions::array_lower_memory(instruction, value_type) } - - /* - Instruction::RecordLift { type_index } => { - instructions::record_lift(*type_index, instruction) - } - Instruction::RecordLower { type_index } => { - instructions::record_lower(*type_index, instruction) - } - */ Instruction::RecordLiftMemory { record_type_id } => { instructions::record_lift_memory(record_type_id as _, instruction) } From 51af2df63e6c3c7606b5641488fb6415f0499495 Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 18 Apr 2021 22:12:10 +0300 Subject: [PATCH 02/27] refactoring --- wasmer-it/src/errors.rs | 4 +- .../src/interpreter/instructions/arrays.rs | 134 +--------- .../instructions/arrays/lift_array.rs | 57 ++++ .../instructions/arrays/lower_array.rs | 107 ++++++++ .../instructions/arrays/read_arrays.rs | 28 +- .../interpreter/instructions/arrays/utils.rs | 47 ++++ .../instructions/arrays/write_arrays.rs | 1 + .../src/interpreter/instructions/records.rs | 251 ++++-------------- .../instructions/records/lift_record.rs | 0 .../instructions/records/lower_record.rs | 0 .../src/interpreter/instructions/strings.rs | 8 +- .../src/interpreter/instructions/utils.rs | 12 +- 12 files changed, 306 insertions(+), 343 deletions(-) create mode 100644 wasmer-it/src/interpreter/instructions/arrays/lift_array.rs create mode 100644 wasmer-it/src/interpreter/instructions/arrays/lower_array.rs create mode 100644 wasmer-it/src/interpreter/instructions/arrays/utils.rs create mode 100644 wasmer-it/src/interpreter/instructions/arrays/write_arrays.rs create mode 100644 wasmer-it/src/interpreter/instructions/records/lift_record.rs create mode 100644 wasmer-it/src/interpreter/instructions/records/lower_record.rs diff --git a/wasmer-it/src/errors.rs b/wasmer-it/src/errors.rs index 7f63489..aa5c267 100644 --- a/wasmer-it/src/errors.rs +++ b/wasmer-it/src/errors.rs @@ -127,8 +127,8 @@ pub enum InstructionErrorKind { /// The memory doesn't exist. MemoryIsMissing { - /// The memory indeX. - memory_index: u32, + /// The memory index. + memory_index: usize, }, /// Tried to read out of bounds of the memory. diff --git a/wasmer-it/src/interpreter/instructions/arrays.rs b/wasmer-it/src/interpreter/instructions/arrays.rs index 28d732f..3c9834e 100644 --- a/wasmer-it/src/interpreter/instructions/arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays.rs @@ -1,9 +1,17 @@ +mod lift_array; +mod lower_array; mod read_arrays; +mod utils; +mod write_arrays; +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_; +use super::record_lower_memory_; use super::write_to_instance_mem; -use read_arrays::*; use crate::instr_error; use crate::interpreter::instructions::to_native; @@ -15,60 +23,6 @@ use crate::{ use std::convert::TryInto; -pub(super) fn array_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, - 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, -{ - if elements_count == 0 { - return Ok(IValue::Array(vec![])); - } - - match value_type { - IType::Boolean => read_bool_array(instance, instruction.clone(), offset, elements_count), - IType::S8 => read_s8_array(instance, instruction.clone(), offset, elements_count), - IType::S16 => read_s16_array(instance, instruction.clone(), offset, elements_count), - IType::S32 => read_s32_array(instance, instruction.clone(), offset, elements_count), - IType::S64 => read_s64_array(instance, instruction.clone(), offset, elements_count), - IType::I32 => read_i32_array(instance, instruction.clone(), offset, elements_count), - IType::I64 => read_i64_array(instance, instruction.clone(), offset, elements_count), - IType::U8 => read_u8_array(instance, instruction.clone(), offset, elements_count), - IType::U16 => read_u16_array(instance, instruction.clone(), offset, elements_count), - IType::U32 => read_u32_array(instance, instruction.clone(), offset, elements_count), - IType::U64 => read_u64_array(instance, instruction.clone(), offset, elements_count), - IType::F32 => read_f32_array(instance, instruction.clone(), offset, elements_count), - IType::F64 => read_f64_array(instance, instruction.clone(), offset, elements_count), - IType::String => read_string_array(instance, instruction.clone(), offset, elements_count), - IType::Record(record_type_id) => read_record_array( - instance, - instruction.clone(), - *record_type_id, - offset, - elements_count, - ), - IType::ByteArray => read_array_array( - instance, - instruction.clone(), - &IType::ByteArray, - offset, - elements_count, - ), - IType::Array(ty) => { - read_array_array(instance, instruction.clone(), &ty, offset, elements_count) - } - } -} - pub(crate) fn array_lift_memory( instruction: Instruction, value_type: IType, @@ -110,7 +64,7 @@ where ); let instance = &mut runtime.wasm_instance; - let array = array_lift_memory_( + let array = array_lift_memory_impl( *instance, &value_type, offset as _, @@ -126,72 +80,6 @@ where }) } -pub(super) fn array_lower_memory_( - instance: &mut Instance, - instruction: Instruction, - 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, -{ - let mut result: Vec = Vec::with_capacity(array_values.len()); - - // here it's known that all interface values have the same type - for value in array_values { - match value { - IValue::S8(value) => result.push(value as _), - IValue::S16(value) => result.push(value as _), - IValue::S32(value) => result.push(value as _), - IValue::S64(value) => result.push(value as _), - IValue::U8(value) => result.push(value as _), - IValue::U16(value) => result.push(value as _), - IValue::U32(value) => result.push(value as _), - IValue::U64(value) => result.push(value as _), - IValue::I32(value) => result.push(value as _), - IValue::I64(value) => result.push(value as _), - IValue::F32(value) => result.push(value as _), - IValue::F64(value) => result.push(value.to_bits()), - IValue::String(value) => { - let string_pointer = if !value.is_empty() { - write_to_instance_mem(instance, instruction.clone(), value.as_bytes())? - } else { - 0 - }; - - result.push(string_pointer as _); - result.push(value.len() as _); - } - - IValue::Array(values) => { - let (array_offset, array_size) = if !values.is_empty() { - array_lower_memory_(instance, instruction.clone(), values)? - } else { - (0, 0) - }; - - result.push(array_offset as _); - result.push(array_size as _); - } - - IValue::Record(values) => { - let record_offset = - super::record_lower_memory_(instance, instruction.clone(), values)?; - result.push(record_offset as _); - } - } - } - - let result = safe_transmute::transmute_to_bytes::(&result); - let result_pointer = write_to_instance_mem(instance, instruction, &result)?; - - Ok((result_pointer as _, result.len() as _)) -} - pub(crate) fn array_lower_memory( instruction: Instruction, value_type: IType, @@ -230,7 +118,7 @@ where } let (offset, size) = - array_lower_memory_(*instance, instruction.clone(), values)?; + array_lower_memory_impl(*instance, instruction.clone(), values)?; 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 new file mode 100644 index 0000000..4520d0f --- /dev/null +++ b/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs @@ -0,0 +1,57 @@ +use super::read_arrays::*; + +use crate::{errors::InstructionError, interpreter::Instruction, IType, IValue}; + +pub(crate) fn array_lift_memory_impl<'instance, Instance, Export, LocalImport, Memory, MemoryView>( + instance: &'instance Instance, + 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, +{ + if elements_count == 0 { + return Ok(IValue::Array(vec![])); + } + + match value_type { + IType::Boolean => read_bool_array(instance, instruction.clone(), offset, elements_count), + IType::S8 => read_s8_array(instance, instruction.clone(), offset, elements_count), + IType::S16 => read_s16_array(instance, instruction.clone(), offset, elements_count), + IType::S32 => read_s32_array(instance, instruction.clone(), offset, elements_count), + IType::S64 => read_s64_array(instance, instruction.clone(), offset, elements_count), + IType::I32 => read_i32_array(instance, instruction.clone(), offset, elements_count), + IType::I64 => read_i64_array(instance, instruction.clone(), offset, elements_count), + IType::U8 => read_u8_array(instance, instruction.clone(), offset, elements_count), + IType::U16 => read_u16_array(instance, instruction.clone(), offset, elements_count), + IType::U32 => read_u32_array(instance, instruction.clone(), offset, elements_count), + IType::U64 => read_u64_array(instance, instruction.clone(), offset, elements_count), + IType::F32 => read_f32_array(instance, instruction.clone(), offset, elements_count), + IType::F64 => read_f64_array(instance, instruction.clone(), offset, elements_count), + IType::String => read_string_array(instance, instruction.clone(), offset, elements_count), + IType::Record(record_type_id) => read_record_array( + instance, + instruction.clone(), + *record_type_id, + offset, + elements_count, + ), + IType::ByteArray => read_array_array( + instance, + instruction.clone(), + &IType::ByteArray, + offset, + elements_count, + ), + IType::Array(ty) => { + read_array_array(instance, instruction.clone(), &ty, offset, elements_count) + } + } +} diff --git a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs new file mode 100644 index 0000000..b539878 --- /dev/null +++ b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs @@ -0,0 +1,107 @@ +use super::utils::MemoryWriter; +use super::write_to_instance_mem; + +use crate::{ + errors::{InstructionError, InstructionErrorKind}, + interpreter::Instruction, + IValue, +}; + +pub(crate) fn array_lower_memory_impl( + instance: &mut Instance, + instruction: Instruction, + 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, +{ + if array_values.is_empty() { + return Ok((0, 0)); + } + + let size_to_allocate = value_size(&array_values[0]) * array_values.len(); + let offset = super::allocate(instance, instruction.clone(), size_to_allocate)?; + + 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 values_count = array_values.len(); + + // 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::String(value) => { + let string_pointer = + write_to_instance_mem(instance, instruction.clone(), value.as_bytes())?; + + writer.write_array(string_pointer.to_le_bytes()); + writer.write_array(value.len().to_le_bytes()); + } + IValue::ByteArray(values) => writer.write_slice(&values), + IValue::Array(values) => { + let (array_offset, array_size) = + array_lower_memory_impl(instance, instruction.clone(), values)?; + + writer.write_array(array_offset.to_le_bytes()); + writer.write_array(array_size.to_le_bytes()); + } + + IValue::Record(values) => { + let record_offset = + super::record_lower_memory_(instance, instruction.clone(), values)?; + writer.write_array(record_offset.to_le_bytes()); + } + } + } + + Ok((offset as _, values_count as _)) +} + +fn value_size(value: &IValue) -> usize { + match value { + IValue::Boolean(_) => 1, + IValue::S8(_) => 1, + IValue::S16(_) => 2, + IValue::S32(_) => 4, + IValue::S64(_) => 8, + IValue::U8(_) => 1, + IValue::U16(_) => 2, + IValue::U32(_) => 4, + IValue::U64(_) => 8, + IValue::F32(_) => 4, + IValue::F64(_) => 8, + IValue::String(_) => 4, + IValue::ByteArray(_) => 4, + IValue::Array(_) => 4, + IValue::I32(_) => 4, + IValue::I64(_) => 8, + IValue::Record(_) => 4, + } +} diff --git a/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs b/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs index dafd139..5870732 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs @@ -55,9 +55,9 @@ where MemoryView: wasm::structures::MemoryView + 'instance, Instance: wasm::structures::Instance, { - let memory_index: u32 = 0; + let memory_index = 0; let memory_view = instance - .memory(memory_index as usize) + .memory(memory_index) .ok_or_else(|| { InstructionError::new( instruction.clone(), @@ -112,7 +112,7 @@ 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_be_bytes([Cell::get(&memory_view[element_id])]); + let value = i8::from_le_bytes([Cell::get(&memory_view[element_id])]); result.push(IValue::S8(value)); } @@ -124,7 +124,7 @@ 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_be_bytes([ + let value = u16::from_le_bytes([ Cell::get(&memory_view[2 * element_id]), Cell::get(&memory_view[2 * element_id + 1]), ]); @@ -139,7 +139,7 @@ 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_be_bytes([ + let value = i16::from_le_bytes([ Cell::get(&memory_view[2 * element_id]), Cell::get(&memory_view[2 * element_id + 1]), ]); @@ -154,7 +154,7 @@ 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_be_bytes([ + let value = u32::from_le_bytes([ Cell::get(&memory_view[4 * element_id]), Cell::get(&memory_view[4 * element_id + 1]), Cell::get(&memory_view[4 * element_id + 2]), @@ -171,7 +171,7 @@ 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_be_bytes([ + let value = f32::from_le_bytes([ Cell::get(&memory_view[4 * element_id]), Cell::get(&memory_view[4 * element_id + 1]), Cell::get(&memory_view[4 * element_id + 2]), @@ -188,7 +188,7 @@ 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_be_bytes([ + let value = i32::from_le_bytes([ Cell::get(&memory_view[4 * element_id]), Cell::get(&memory_view[4 * element_id + 1]), Cell::get(&memory_view[4 * element_id + 2]), @@ -205,7 +205,7 @@ 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_be_bytes([ + let value = i32::from_le_bytes([ Cell::get(&memory_view[4 * element_id]), Cell::get(&memory_view[4 * element_id + 1]), Cell::get(&memory_view[4 * element_id + 2]), @@ -222,7 +222,7 @@ 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_be_bytes([ + let value = u64::from_le_bytes([ Cell::get(&memory_view[4 * element_id]), Cell::get(&memory_view[4 * element_id + 1]), Cell::get(&memory_view[4 * element_id + 2]), @@ -243,7 +243,7 @@ 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_be_bytes([ + let value = f64::from_le_bytes([ Cell::get(&memory_view[4 * element_id]), Cell::get(&memory_view[4 * element_id + 1]), Cell::get(&memory_view[4 * element_id + 2]), @@ -264,7 +264,7 @@ 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_be_bytes([ + let value = i64::from_le_bytes([ Cell::get(&memory_view[4 * element_id]), Cell::get(&memory_view[4 * element_id + 1]), Cell::get(&memory_view[4 * element_id + 2]), @@ -285,7 +285,7 @@ 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_be_bytes([ + let value = i64::from_le_bytes([ Cell::get(&memory_view[4 * element_id]), Cell::get(&memory_view[4 * element_id + 1]), Cell::get(&memory_view[4 * element_id + 2]), @@ -459,7 +459,7 @@ where )?; IValue::ByteArray(value) } - _ => super::array_lift_memory_( + _ => super::array_lift_memory_impl( instance, &*ty, *array_offset as _, diff --git a/wasmer-it/src/interpreter/instructions/arrays/utils.rs b/wasmer-it/src/interpreter/instructions/arrays/utils.rs new file mode 100644 index 0000000..015f97b --- /dev/null +++ b/wasmer-it/src/interpreter/instructions/arrays/utils.rs @@ -0,0 +1,47 @@ +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); + } + + 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/write_arrays.rs b/wasmer-it/src/interpreter/instructions/arrays/write_arrays.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/wasmer-it/src/interpreter/instructions/arrays/write_arrays.rs @@ -0,0 +1 @@ + diff --git a/wasmer-it/src/interpreter/instructions/records.rs b/wasmer-it/src/interpreter/instructions/records.rs index ede5fc0..27f7621 100644 --- a/wasmer-it/src/interpreter/instructions/records.rs +++ b/wasmer-it/src/interpreter/instructions/records.rs @@ -14,93 +14,6 @@ use crate::{ use std::convert::TryInto; -/* -/// Build an `IValue::Record` based on values on the stack. -/// -/// To fill a record, every field `field_1` to `field_n` must get its -/// value from the stack with `value_1` to `value_n`. It is not -/// possible to use `Stack::pop` because the one-pass algorithm does -/// not know exactly the number of values to read from the stack -/// ahead-of-time, so `Stack::pop1` is used. It implies that values -/// are read one after the other from the stack, in a natural reverse -/// order, from `value_n` to `value_1`. Thus, the `values` vector must -/// be filled from the end to the beginning. It is not safely possible -/// to fill the `values` vector with empty values though (so that it -/// is possible to access to last positions). So a `VecDeque` type is -/// used: it is a double-ended queue. -fn record_lift_( - stack: &mut Stack, - record_type: &RecordType, -) -> Result { - let length = record_type.fields.len(); - let mut values = VecDeque::with_capacity(length); - for field in record_type.fields.iter().rev() { - match field { - IType::Record(record_type) => { - values.push_front(record_lift_(stack, &record_type)?) - } - ty => { - let value = stack.pop1().unwrap(); - let value_type = (&value).into(); - if ty != &value_type { - return Err(InstructionErrorKind::InvalidValueOnTheStack { - expected_type: ty.clone(), - received_type: value_type, - }); - } - values.push_front(value) - } - } - } - Ok(IValue::Record( - NEVec::new(values.into_iter().collect()) - .expect("Record must have at least one field, zero given"), - )) -} - -pub(crate) fn record_lift( - type_index: u32, - instruction: Instruction, -) -> crate::interpreter::ExecutableInstruction -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, -{ - #[allow(unused_imports)] - use crate::interpreter::stack::Stackable; - Box::new({ - move |runtime| -> _ { - let instance = &runtime.wasm_instance; - let record_type = match instance.wit_type(type_index).ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::TypeIsMissing { type_index }, - ) - })? { - Type::Record(record_type) => record_type, - Type::Function { .. } => { - return Err(InstructionError::new( - instruction.clone(), - InstructionErrorKind::InvalidTypeKind { - expected_kind: TypeKind::Record, - received_kind: TypeKind::Function, - }, - )) - } - }; - let record = record_lift_(&mut runtime.stack, &record_type) - .map_err(|k| InstructionError::new(instruction.clone(), k))?; - runtime.stack.push(record); - Ok(()) - } - }) -} - */ - pub(super) fn record_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>( instance: &'instance Instance, record_type: &IRecordType, @@ -115,33 +28,18 @@ where Instance: crate::interpreter::wasm::structures::Instance + 'instance, { - fn record_size(record_type: &IRecordType) -> usize { - let mut record_size = 0; - - for field_type in record_type.fields.iter() { - let params_count = match field_type.ty { - IType::String | IType::Array(_) => 2, - _ => 1, - }; - - record_size += std::mem::size_of::() * params_count; - } - - record_size - } - let length = record_type.fields.len(); let mut values = Vec::with_capacity(length); let size = record_size(record_type); let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?; - // TODO: add error handling - let data = - safe_transmute::transmute_many::(&data).unwrap(); let mut field_id = 0; for field in (*record_type.fields).iter() { let value = data[field_id]; match &field.ty { + IType::Boolean => { + values.push(IValue::Boolean(value as _)); + } IType::S8 => { values.push(IValue::S8(value as _)); } @@ -202,7 +100,7 @@ where let array_size = data[field_id]; if array_size != 0 { - let array = super::array_lift_memory_( + let array = super::array_lift_memory_impl( instance, &**ty, array_offset as _, @@ -243,6 +141,29 @@ where )) } +/// Returns record size in bytes. +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 + | IType::String + | IType::ByteArray + | IType::Array(_) + | IType::Record(_) => 32, + IType::S64 | IType::U64 | IType::I64 | IType::F64 => 64, + }; + } + + record_size +} + pub(crate) fn record_lift_memory( record_type_id: u64, instruction: Instruction, @@ -310,53 +231,53 @@ where Instance: crate::interpreter::wasm::structures::Instance, { - let mut result: Vec = Vec::with_capacity(values.len()); + let mut result: Vec = Vec::with_capacity(values.len()); for value in values.into_vec() { match value { + IValue::Boolean(value) => result.push(value as _), IValue::S8(value) => result.push(value as _), - IValue::S16(value) => result.push(value as _), - IValue::S32(value) => result.push(value as _), - IValue::S64(value) => result.push(value as _), - IValue::U8(value) => result.push(value as _), - IValue::U16(value) => result.push(value as _), - IValue::U32(value) => result.push(value as _), - IValue::U64(value) => result.push(value as _), - IValue::I32(value) => result.push(value as _), - IValue::I64(value) => result.push(value as _), - IValue::F32(value) => result.push(value as _), - IValue::F64(value) => result.push(value.to_bits()), + IValue::S16(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::S32(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::S64(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::U8(value) => result.push(value), + IValue::U16(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::U32(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::U64(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::I32(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::I64(value) => result.extend_from_slice(&value.to_le_bytes()), + 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 string_pointer = if !value.is_empty() { - write_to_instance_mem(instance, instruction.clone(), value.as_bytes())? - } else { - 0 - }; + let string_pointer = + write_to_instance_mem(instance, instruction.clone(), value.as_bytes())?; - result.push(string_pointer as _); - result.push(value.len() as _); + result.extend_from_slice(&string_pointer.to_le_bytes()); + result.extend_from_slice(&value.len().to_le_bytes()); + } + IValue::ByteArray(value) => { + let array_pointer = write_to_instance_mem(instance, instruction.clone(), &value)?; + + result.extend_from_slice(&array_pointer.to_le_bytes()); + result.extend_from_slice(&value.len().to_le_bytes()); } IValue::Array(values) => { - let (offset, size) = if !values.is_empty() { - super::array_lower_memory_(instance, instruction.clone(), values)? - } else { - (0, 0) - }; + let (offset, size) = + super::array_lower_memory_impl(instance, instruction.clone(), values)?; - result.push(offset as _); - result.push(size as _); + result.extend_from_slice(&offset.to_le_bytes()); + result.extend_from_slice(&size.to_le_bytes()); } IValue::Record(values) => { let record_ptr = record_lower_memory_(instance, instruction.clone(), values)?; - result.push(record_ptr as _); + result.extend_from_slice(&record_ptr.to_le_bytes()); } } } - let result = safe_transmute::transmute_to_bytes::(&result); let result_pointer = write_to_instance_mem(instance, instruction, &result)?; Ok(result_pointer as _) @@ -414,65 +335,3 @@ where } }) } - -/* -pub(crate) fn record_lower( - type_index: u32, - instruction: Instruction, -) -> crate::interpreter::ExecutableInstruction -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, -{ - #[allow(unused_imports)] - use crate::interpreter::stack::Stackable; - Box::new({ - move |runtime| -> _ { - let instance = &runtime.wasm_instance; - let record_type = match instance.wit_type(type_index).ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::TypeIsMissing { type_index }, - ) - })? { - Type::Record(record_type) => record_type, - Type::Function { .. } => { - return Err(InstructionError::new( - instruction.clone(), - InstructionErrorKind::InvalidTypeKind { - expected_kind: TypeKind::Record, - received_kind: TypeKind::Function, - }, - )) - } - }; - match runtime.stack.pop1() { - Some(IValue::Record(record_values)) - if record_type == &(&*record_values).into() => - { - let values = FlattenIValueIterator::new(&record_values); - for value in values { - runtime.stack.push(value.clone()); - } - Ok(()) - } - Some(value) => Err(InstructionError::new( - instruction.clone(), - InstructionErrorKind::InvalidValueOnTheStack { - expected_type: IType::Record(record_type.clone()), - received_type: (&value).into(), - }, - )), - None => Err(InstructionError::new( - instruction.clone(), - InstructionErrorKind::StackIsTooSmall { needed: 1 }, - )), - } - } - }) -} - */ diff --git a/wasmer-it/src/interpreter/instructions/records/lift_record.rs b/wasmer-it/src/interpreter/instructions/records/lift_record.rs new file mode 100644 index 0000000..e69de29 diff --git a/wasmer-it/src/interpreter/instructions/records/lower_record.rs b/wasmer-it/src/interpreter/instructions/records/lower_record.rs new file mode 100644 index 0000000..e69de29 diff --git a/wasmer-it/src/interpreter/instructions/strings.rs b/wasmer-it/src/interpreter/instructions/strings.rs index b3c2ae2..e50367d 100644 --- a/wasmer-it/src/interpreter/instructions/strings.rs +++ b/wasmer-it/src/interpreter/instructions/strings.rs @@ -19,10 +19,10 @@ executable_instruction!( ) })?; - let memory_index: u32 = 0; + let memory_index = 0; let memory = runtime .wasm_instance - .memory(memory_index as usize) + .memory(memory_index) .ok_or_else(|| { InstructionError::new( instruction.clone(), @@ -96,9 +96,9 @@ executable_instruction!( })?; let instance = &mut runtime.wasm_instance; - let memory_index: u32 = 0; + let memory_index = 0; let memory_view = instance - .memory(memory_index as usize) + .memory(memory_index) .ok_or_else(|| { InstructionError::new( instruction.clone(), diff --git a/wasmer-it/src/interpreter/instructions/utils.rs b/wasmer-it/src/interpreter/instructions/utils.rs index 8a330f1..f743357 100644 --- a/wasmer-it/src/interpreter/instructions/utils.rs +++ b/wasmer-it/src/interpreter/instructions/utils.rs @@ -24,9 +24,9 @@ where MemoryView: wasm::structures::MemoryView, Instance: wasm::structures::Instance, { - let memory_index: u32 = 0; + let memory_index = 0; let memory_view = instance - .memory(memory_index as usize) + .memory(memory_index) .ok_or_else(|| { InstructionError::new( instruction.clone(), @@ -66,11 +66,15 @@ where 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: u32 = 0; + let memory_index = 0; let memory_view = instance - .memory(memory_index as usize) + .memory(memory_index) .ok_or_else(|| { InstructionError::new( instruction.clone(), From 532043a8843082352fb8fa9e9b4cebca4f9f357f Mon Sep 17 00:00:00 2001 From: vms Date: Mon, 19 Apr 2021 16:08:06 +0300 Subject: [PATCH 03/27] refactor reader --- .../src/interpreter/instructions/arrays.rs | 6 +- .../instructions/arrays/lower_array.rs | 4 +- .../arrays/{utils.rs => memory_writer.rs} | 0 .../instructions/arrays/read_arrays.rs | 2 +- .../src/interpreter/instructions/records.rs | 235 +----------------- .../instructions/records/lift_record.rs | 192 ++++++++++++++ .../instructions/records/lower_record.rs | 70 ++++++ .../instructions/records/value_reader.rs | 89 +++++++ .../src/interpreter/instructions/utils.rs | 4 + wasmer-it/src/lib.rs | 1 + 10 files changed, 374 insertions(+), 229 deletions(-) rename wasmer-it/src/interpreter/instructions/arrays/{utils.rs => memory_writer.rs} (100%) create mode 100644 wasmer-it/src/interpreter/instructions/records/value_reader.rs diff --git a/wasmer-it/src/interpreter/instructions/arrays.rs b/wasmer-it/src/interpreter/instructions/arrays.rs index 3c9834e..911d6f5 100644 --- a/wasmer-it/src/interpreter/instructions/arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays.rs @@ -1,7 +1,7 @@ mod lift_array; mod lower_array; +mod memory_writer; mod read_arrays; -mod utils; mod write_arrays; pub(crate) use lift_array::array_lift_memory_impl; @@ -9,8 +9,8 @@ pub(crate) use lower_array::array_lower_memory_impl; use super::allocate; use super::read_from_instance_mem; -use super::record_lift_memory_; -use super::record_lower_memory_; +use super::record_lift_memory_impl; +use super::record_lower_memory_impl; use super::write_to_instance_mem; use crate::instr_error; diff --git a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs index b539878..a5920e9 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs @@ -1,4 +1,4 @@ -use super::utils::MemoryWriter; +use super::memory_writer::MemoryWriter; use super::write_to_instance_mem; use crate::{ @@ -75,7 +75,7 @@ where IValue::Record(values) => { let record_offset = - super::record_lower_memory_(instance, instruction.clone(), values)?; + super::record_lower_memory_impl(instance, instruction.clone(), values)?; writer.write_array(record_offset.to_le_bytes()); } } diff --git a/wasmer-it/src/interpreter/instructions/arrays/utils.rs b/wasmer-it/src/interpreter/instructions/arrays/memory_writer.rs similarity index 100% rename from wasmer-it/src/interpreter/instructions/arrays/utils.rs rename to wasmer-it/src/interpreter/instructions/arrays/memory_writer.rs diff --git a/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs b/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs index 5870732..d4df139 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs @@ -397,7 +397,7 @@ where let mut result = Vec::with_capacity(data.len()); for record_offset in data { - result.push(super::record_lift_memory_( + result.push(super::record_lift_memory_impl( instance, record_type, *record_offset as _, diff --git a/wasmer-it/src/interpreter/instructions/records.rs b/wasmer-it/src/interpreter/instructions/records.rs index 27f7621..daf5eb1 100644 --- a/wasmer-it/src/interpreter/instructions/records.rs +++ b/wasmer-it/src/interpreter/instructions/records.rs @@ -1,169 +1,23 @@ +mod lift_record; +mod lower_record; +mod value_reader; + +pub(crate) use lift_record::record_lift_memory_impl; +pub(crate) use lower_record::record_lower_memory_impl; + +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 crate::instr_error; use crate::interpreter::instructions::{is_record_fields_compatible_to_type, to_native}; -use crate::IRecordType; use crate::IType; use crate::IValue; -use crate::NEVec; -use crate::{ - errors::{InstructionError, InstructionErrorKind}, - interpreter::Instruction, -}; +use crate::{errors::InstructionError, errors::InstructionErrorKind, interpreter::Instruction}; use std::convert::TryInto; -pub(super) fn record_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, - record_type: &IRecordType, - offset: 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, -{ - let length = record_type.fields.len(); - let mut values = Vec::with_capacity(length); - let size = record_size(record_type); - let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?; - - let mut field_id = 0; - for field in (*record_type.fields).iter() { - let value = data[field_id]; - match &field.ty { - IType::Boolean => { - values.push(IValue::Boolean(value as _)); - } - IType::S8 => { - values.push(IValue::S8(value as _)); - } - IType::S16 => { - values.push(IValue::S16(value as _)); - } - IType::S32 => { - values.push(IValue::S32(value as _)); - } - IType::S64 => { - values.push(IValue::S64(value as _)); - } - IType::I32 => { - values.push(IValue::I32(value as _)); - } - IType::I64 => { - values.push(IValue::I64(value as _)); - } - IType::U8 => { - values.push(IValue::U8(value as _)); - } - IType::U16 => { - values.push(IValue::U16(value as _)); - } - IType::U32 => { - values.push(IValue::U32(value as _)); - } - IType::U64 => { - values.push(IValue::U64(value as _)); - } - IType::F32 => { - values.push(IValue::F32(value as _)); - } - IType::F64 => values.push(IValue::F64(f64::from_bits(value))), - IType::String => { - let string_offset = value; - field_id += 1; - let string_size = data[field_id]; - - if string_size != 0 { - let string_mem = read_from_instance_mem( - instance, - instruction.clone(), - string_offset as _, - string_size as _, - )?; - - // TODO: check - let string = String::from_utf8(string_mem).unwrap(); - values.push(IValue::String(string)); - } else { - values.push(IValue::String(String::new())); - } - } - IType::Array(ty) => { - let array_offset = value; - field_id += 1; - let array_size = data[field_id]; - - if array_size != 0 { - let array = super::array_lift_memory_impl( - instance, - &**ty, - array_offset as _, - array_size as _, - instruction.clone(), - )?; - values.push(array); - } else { - values.push(IValue::Array(vec![])); - } - } - IType::Record(record_type_id) => { - let offset = value; - - let record_type = instance.wit_record_by_id(*record_type_id).ok_or_else(|| { - InstructionError::new( - instruction.clone(), - InstructionErrorKind::RecordTypeByNameIsMissing { - record_type_id: *record_type_id, - }, - ) - })?; - - values.push(record_lift_memory_( - instance, - record_type, - offset as _, - instruction.clone(), - )?) - } - } - field_id += 1; - } - - Ok(IValue::Record( - NEVec::new(values.into_iter().collect()) - .expect("Record must have at least one field, zero given"), - )) -} - -/// Returns record size in bytes. -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 - | IType::String - | IType::ByteArray - | IType::Array(_) - | IType::Record(_) => 32, - IType::S64 | IType::U64 | IType::I64 | IType::F64 => 64, - }; - } - - record_size -} - pub(crate) fn record_lift_memory( record_type_id: u64, instruction: Instruction, @@ -208,7 +62,7 @@ where ); let record = - record_lift_memory_(&**instance, record_type, offset, instruction.clone())?; + record_lift_memory_impl(&**instance, record_type, offset, instruction.clone())?; log::debug!("record.lift_memory: pushing {:?} on the stack", record); runtime.stack.push(record); @@ -218,71 +72,6 @@ where }) } -pub(super) fn record_lower_memory_( - instance: &mut Instance, - instruction: Instruction, - values: NEVec, -) -> 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, -{ - let mut result: Vec = Vec::with_capacity(values.len()); - - for value in values.into_vec() { - match value { - IValue::Boolean(value) => result.push(value as _), - IValue::S8(value) => result.push(value as _), - IValue::S16(value) => result.extend_from_slice(&value.to_le_bytes()), - IValue::S32(value) => result.extend_from_slice(&value.to_le_bytes()), - IValue::S64(value) => result.extend_from_slice(&value.to_le_bytes()), - IValue::U8(value) => result.push(value), - IValue::U16(value) => result.extend_from_slice(&value.to_le_bytes()), - IValue::U32(value) => result.extend_from_slice(&value.to_le_bytes()), - IValue::U64(value) => result.extend_from_slice(&value.to_le_bytes()), - IValue::I32(value) => result.extend_from_slice(&value.to_le_bytes()), - IValue::I64(value) => result.extend_from_slice(&value.to_le_bytes()), - 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 string_pointer = - write_to_instance_mem(instance, instruction.clone(), value.as_bytes())?; - - result.extend_from_slice(&string_pointer.to_le_bytes()); - result.extend_from_slice(&value.len().to_le_bytes()); - } - IValue::ByteArray(value) => { - let array_pointer = write_to_instance_mem(instance, instruction.clone(), &value)?; - - result.extend_from_slice(&array_pointer.to_le_bytes()); - result.extend_from_slice(&value.len().to_le_bytes()); - } - - IValue::Array(values) => { - let (offset, size) = - super::array_lower_memory_impl(instance, instruction.clone(), values)?; - - result.extend_from_slice(&offset.to_le_bytes()); - result.extend_from_slice(&size.to_le_bytes()); - } - - IValue::Record(values) => { - let record_ptr = record_lower_memory_(instance, instruction.clone(), values)?; - - result.extend_from_slice(&record_ptr.to_le_bytes()); - } - } - } - - let result_pointer = write_to_instance_mem(instance, instruction, &result)?; - - Ok(result_pointer as _) -} - pub(crate) fn record_lower_memory( record_type_id: u64, instruction: Instruction, @@ -313,7 +102,7 @@ where log::debug!("record.lower_memory: obtained {:?} values on the stack for record type = {}", record_fields, record_type_id); let offset = - record_lower_memory_(*instance, instruction.clone(), record_fields)?; + record_lower_memory_impl(*instance, instruction.clone(), record_fields)?; 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/lift_record.rs b/wasmer-it/src/interpreter/instructions/records/lift_record.rs index e69de29..1989067 100644 --- a/wasmer-it/src/interpreter/instructions/records/lift_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lift_record.rs @@ -0,0 +1,192 @@ +use super::read_from_instance_mem; + +use super::value_reader::ValueReader; +use crate::IRecordType; +use crate::IType; +use crate::IValue; +use crate::NEVec; +use crate::{ + errors::{InstructionError, InstructionErrorKind}, + interpreter::Instruction, +}; + +#[rustfmt::skip] +pub(crate) fn record_lift_memory_impl<'instance, Instance, Export, LocalImport, Memory, MemoryView>( + instance: &'instance Instance, + record_type: &IRecordType, + offset: 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, +{ + let mut values = Vec::with_capacity(record_type.fields.len()); + + let size = record_size(record_type); + let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?; + let reader = ValueReader::new(data); + + for field in (*record_type.fields).iter() { + match &field.ty { + IType::Boolean => values.push(IValue::Boolean(reader.read_u8() == 1)), + IType::S8 => values.push(IValue::S8(reader.read_i8())), + IType::S16 => values.push(IValue::S16(reader.read_i16())), + IType::S32 => values.push(IValue::S32(reader.read_i32())), + IType::S64 => values.push(IValue::S64(reader.read_i64())), + IType::I32 => values.push(IValue::I32(reader.read_i32())), + IType::I64 => values.push(IValue::I64(reader.read_i64())), + IType::U8 => values.push(IValue::U8(reader.read_u8())), + IType::U16 => values.push(IValue::U16(reader.read_u16())), + IType::U32 => values.push(IValue::U32(reader.read_u32())), + IType::U64 => values.push(IValue::U64(reader.read_u64())), + IType::F32 => values.push(IValue::F32(reader.read_f32())), + IType::F64 => values.push(IValue::F64(reader.read_f64())), + IType::String => values.push(IValue::String(read_string(instance, instruction.clone(), &reader)?)), + IType::ByteArray => values.push(read_byte_array(instance, instruction.clone(), &reader)?), + IType::Array(ty) => values.push(read_array(instance, instruction.clone(), &reader, &**ty)?), + IType::Record(record_type_id) => values.push(read_record(instance, instruction.clone(), &reader, *record_type_id)?), + } + } + + Ok(IValue::Record( + NEVec::new(values.into_iter().collect()) + .expect("Record must have at least one field, zero given"), + )) +} + +/// Returns record size in bytes. +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 + | IType::String + | IType::ByteArray + | IType::Array(_) + | IType::Record(_) => 32, + IType::S64 | IType::U64 | IType::I64 | IType::F64 => 64, + }; + } + + record_size +} + +fn read_string<'instance, Instance, Export, LocalImport, Memory, MemoryView>( + instance: &Instance, + instruction: Instruction, + reader: &ValueReader, +) -> 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 string_offset = reader.read_u32(); + let string_size = reader.read_u32(); + + let string_mem = read_from_instance_mem( + instance, + instruction.clone(), + string_offset as _, + string_size as _, + )?; + + // TODO: check + let string = String::from_utf8(string_mem).unwrap(); + + Ok(string) +} + +fn read_byte_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>( + instance: &Instance, + instruction: Instruction, + reader: &ValueReader, +) -> 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 offset = reader.read_u32(); + let elements_count = reader.read_u32(); + + let array = read_from_instance_mem( + instance, + instruction.clone(), + offset as _, + elements_count as _, + )?; + let byte_array = IValue::ByteArray(array); + + Ok(byte_array) +} + +fn read_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>( + instance: &Instance, + instruction: Instruction, + reader: &ValueReader, + ty: &IType, +) -> 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 array_offset = reader.read_u32(); + let elements_count = reader.read_u32(); + + super::array_lift_memory_impl( + instance, + ty, + array_offset as _, + elements_count as _, + instruction.clone(), + ) +} + +fn read_record<'instance, Instance, Export, LocalImport, Memory, MemoryView>( + instance: &Instance, + instruction: Instruction, + reader: &ValueReader, + record_type_id: u64, +) -> 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 offset = 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, + }, + ) + })?; + + record_lift_memory_impl(instance, record_type, offset as _, instruction.clone()) +} diff --git a/wasmer-it/src/interpreter/instructions/records/lower_record.rs b/wasmer-it/src/interpreter/instructions/records/lower_record.rs index e69de29..66b1f7e 100644 --- a/wasmer-it/src/interpreter/instructions/records/lower_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lower_record.rs @@ -0,0 +1,70 @@ +use super::write_to_instance_mem; + +use crate::IValue; +use crate::NEVec; +use crate::{errors::InstructionError, interpreter::Instruction}; + +pub(crate) fn record_lower_memory_impl( + instance: &mut Instance, + instruction: Instruction, + values: NEVec, +) -> 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, +{ + let mut result: Vec = Vec::with_capacity(values.len()); + + for value in values.into_vec() { + match value { + IValue::Boolean(value) => result.push(value as _), + IValue::S8(value) => result.push(value as _), + IValue::S16(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::S32(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::S64(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::U8(value) => result.push(value), + IValue::U16(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::U32(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::U64(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::I32(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::I64(value) => result.extend_from_slice(&value.to_le_bytes()), + 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 string_pointer = + write_to_instance_mem(instance, instruction.clone(), value.as_bytes())?; + + result.extend_from_slice(&string_pointer.to_le_bytes()); + result.extend_from_slice(&value.len().to_le_bytes()); + } + IValue::ByteArray(value) => { + let array_pointer = write_to_instance_mem(instance, instruction.clone(), &value)?; + + result.extend_from_slice(&array_pointer.to_le_bytes()); + result.extend_from_slice(&value.len().to_le_bytes()); + } + + IValue::Array(values) => { + let (offset, size) = + super::array_lower_memory_impl(instance, instruction.clone(), values)?; + + result.extend_from_slice(&offset.to_le_bytes()); + result.extend_from_slice(&size.to_le_bytes()); + } + + IValue::Record(values) => { + let record_ptr = record_lower_memory_impl(instance, instruction.clone(), values)?; + + result.extend_from_slice(&record_ptr.to_le_bytes()); + } + } + } + + let result_pointer = write_to_instance_mem(instance, instruction, &result)?; + + Ok(result_pointer as _) +} diff --git a/wasmer-it/src/interpreter/instructions/records/value_reader.rs b/wasmer-it/src/interpreter/instructions/records/value_reader.rs new file mode 100644 index 0000000..d74ec6b --- /dev/null +++ b/wasmer-it/src/interpreter/instructions/records/value_reader.rs @@ -0,0 +1,89 @@ +use std::cell::Cell; + +pub(super) struct ValueReader { + stream: Vec, + offset: Cell, +} + +macro_rules! value_der { + ($self:expr, $offset:expr, @seq_start $($ids:tt),* @seq_end) => { + [$($self.stream[$offset + $ids]),+] + }; + + ($self:expr, $offset:expr, 1) => { + value_der!($self, $offset, @seq_start 0 @seq_end); + }; + + ($self:expr, $offset:expr, 2) => { + value_der!($self, $offset, @seq_start 0, 1 @seq_end); + }; + + ($self:expr, $offset:expr, 4) => { + value_der!($self, $offset, @seq_start 0, 1, 2, 3 @seq_end); + }; + + ($self:expr, $offset:expr, 8) => { + value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7 @seq_end); + }; +} + +macro_rules! read_ty { + ($func_name:ident, $ty:ty, 1) => { + pub(super) fn $func_name(&self) -> $ty { + let offset = self.offset.get(); + let result = <$ty>::from_le_bytes(value_der!(self, offset, 1)); + + self.offset.set(offset + 1); + result + } + }; + + ($func_name:ident, $ty:ty, 2) => { + pub(super) fn $func_name(&self) -> $ty { + let offset = self.offset.get(); + let result = <$ty>::from_le_bytes(value_der!(self, offset, 2)); + + self.offset.set(offset + 2); + result + } + }; + + ($func_name:ident, $ty:ty, 4) => { + pub(super) fn $func_name(&self) -> $ty { + let offset = self.offset.get(); + let result = <$ty>::from_le_bytes(value_der!(self, offset, 4)); + + self.offset.set(offset + 4); + result + } + }; + + ($func_name:ident, $ty:ty, 8) => { + pub(super) fn $func_name(&self) -> $ty { + let offset = self.offset.get(); + let result = <$ty>::from_le_bytes(value_der!(self, offset, 8)); + + self.offset.set(offset + 8); + result + } + }; +} + +// TODO: rewrite this with macros +impl ValueReader { + pub(super) fn new(stream: Vec) -> Self { + let offset = Cell::new(0); + Self { stream, offset } + } + + read_ty!(read_u8, u8, 1); + read_ty!(read_i8, i8, 1); + read_ty!(read_u16, u16, 2); + read_ty!(read_i16, i16, 2); + read_ty!(read_u32, u32, 4); + read_ty!(read_i32, i32, 4); + read_ty!(read_f32, f32, 4); + read_ty!(read_u64, u64, 8); + read_ty!(read_i64, i64, 8); + read_ty!(read_f64, f64, 8); +} diff --git a/wasmer-it/src/interpreter/instructions/utils.rs b/wasmer-it/src/interpreter/instructions/utils.rs index f743357..0544b40 100644 --- a/wasmer-it/src/interpreter/instructions/utils.rs +++ b/wasmer-it/src/interpreter/instructions/utils.rs @@ -24,6 +24,10 @@ where 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) diff --git a/wasmer-it/src/lib.rs b/wasmer-it/src/lib.rs index c540a41..800c58a 100644 --- a/wasmer-it/src/lib.rs +++ b/wasmer-it/src/lib.rs @@ -52,6 +52,7 @@ // #![forbid(unsafe_code)] #![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")] #![doc(html_logo_url = "https://github.com/wasmerio.png")] +#![recursion_limit = "512"] pub mod ast; #[macro_use] From e9cdf5ecb2e978322bfff79a97440e9380d7a6b8 Mon Sep 17 00:00:00 2001 From: vms Date: Mon, 19 Apr 2021 16:31:16 +0300 Subject: [PATCH 04/27] getting rid of unwraps --- wasmer-it/src/errors.rs | 9 +++++ .../instructions/arrays/lift_array.rs | 36 +++++++++---------- .../instructions/arrays/read_arrays.rs | 8 +++-- .../instructions/records/lift_record.rs | 20 ++++------- wasmer-it/src/lib.rs | 3 +- wasmer-it/src/serde/de.rs | 6 ++-- 6 files changed, 44 insertions(+), 38 deletions(-) diff --git a/wasmer-it/src/errors.rs b/wasmer-it/src/errors.rs index aa5c267..91b9f4b 100644 --- a/wasmer-it/src/errors.rs +++ b/wasmer-it/src/errors.rs @@ -41,6 +41,7 @@ impl InstructionError { impl Error for InstructionError {} +/// Allows you to shorten the expression creates a new InstructionError. #[macro_export] macro_rules! instr_error { ($instruction:expr, $error_kind:expr) => { @@ -178,6 +179,9 @@ pub enum InstructionErrorKind { /// Errors related to Serialization/deserialization of record. SerdeError(String), + + /// Errors related to lifting incorrect UTF8 string from a Wasm module. + CorruptedUTF8String(std::string::FromUtf8Error), } impl Error for InstructionErrorKind {} @@ -288,6 +292,11 @@ impl Display for InstructionErrorKind { formatter, "serde error: {}", err, ), + + Self::CorruptedUTF8String(err) => write!( + formatter, + "corrupted utf8 string: {}", err + ) } } } diff --git a/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs index 4520d0f..05134cc 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs @@ -22,36 +22,34 @@ where } match value_type { - IType::Boolean => read_bool_array(instance, instruction.clone(), offset, elements_count), - IType::S8 => read_s8_array(instance, instruction.clone(), offset, elements_count), - IType::S16 => read_s16_array(instance, instruction.clone(), offset, elements_count), - IType::S32 => read_s32_array(instance, instruction.clone(), offset, elements_count), - IType::S64 => read_s64_array(instance, instruction.clone(), offset, elements_count), - IType::I32 => read_i32_array(instance, instruction.clone(), offset, elements_count), - IType::I64 => read_i64_array(instance, instruction.clone(), offset, elements_count), - IType::U8 => read_u8_array(instance, instruction.clone(), offset, elements_count), - IType::U16 => read_u16_array(instance, instruction.clone(), offset, elements_count), - IType::U32 => read_u32_array(instance, instruction.clone(), offset, elements_count), - IType::U64 => read_u64_array(instance, instruction.clone(), offset, elements_count), - IType::F32 => read_f32_array(instance, instruction.clone(), offset, elements_count), - IType::F64 => read_f64_array(instance, instruction.clone(), offset, elements_count), - IType::String => read_string_array(instance, instruction.clone(), offset, elements_count), + 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.clone(), + instruction, *record_type_id, offset, elements_count, ), IType::ByteArray => read_array_array( instance, - instruction.clone(), + instruction, &IType::ByteArray, offset, elements_count, ), - IType::Array(ty) => { - read_array_array(instance, instruction.clone(), &ty, offset, elements_count) - } + IType::Array(ty) => read_array_array(instance, instruction, &ty, offset, elements_count), } } diff --git a/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs b/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs index d4df139..37d69b5 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs @@ -354,8 +354,12 @@ where *string_size as _, )?; - // TODO: check - let string = String::from_utf8(string_mem).unwrap(); + let string = String::from_utf8(string_mem).map_err(|e| { + InstructionError::new( + instruction.clone(), + InstructionErrorKind::CorruptedUTF8String(e), + ) + })?; result.push(IValue::String(string)); } diff --git a/wasmer-it/src/interpreter/instructions/records/lift_record.rs b/wasmer-it/src/interpreter/instructions/records/lift_record.rs index 1989067..0837c98 100644 --- a/wasmer-it/src/interpreter/instructions/records/lift_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lift_record.rs @@ -104,8 +104,9 @@ where string_size as _, )?; - // TODO: check - let string = String::from_utf8(string_mem).unwrap(); + let string = String::from_utf8(string_mem).map_err(|e| { + InstructionError::new(instruction, InstructionErrorKind::CorruptedUTF8String(e)) + })?; Ok(string) } @@ -126,12 +127,7 @@ where let offset = reader.read_u32(); let elements_count = reader.read_u32(); - let array = read_from_instance_mem( - instance, - instruction.clone(), - offset as _, - elements_count as _, - )?; + let array = read_from_instance_mem(instance, instruction, offset as _, elements_count as _)?; let byte_array = IValue::ByteArray(array); Ok(byte_array) @@ -159,7 +155,7 @@ where ty, array_offset as _, elements_count as _, - instruction.clone(), + instruction, ) } @@ -182,11 +178,9 @@ where let record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| { InstructionError::new( instruction.clone(), - InstructionErrorKind::RecordTypeByNameIsMissing { - record_type_id, - }, + InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id }, ) })?; - record_lift_memory_impl(instance, record_type, offset as _, instruction.clone()) + record_lift_memory_impl(instance, record_type, offset as _, instruction) } diff --git a/wasmer-it/src/lib.rs b/wasmer-it/src/lib.rs index 800c58a..013fa6b 100644 --- a/wasmer-it/src/lib.rs +++ b/wasmer-it/src/lib.rs @@ -40,7 +40,7 @@ #![deny( dead_code, - broken_intra_doc_links, + rustdoc::broken_intra_doc_links, missing_docs, nonstandard_style, unreachable_patterns, @@ -52,7 +52,6 @@ // #![forbid(unsafe_code)] #![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")] #![doc(html_logo_url = "https://github.com/wasmerio.png")] -#![recursion_limit = "512"] pub mod ast; #[macro_use] diff --git a/wasmer-it/src/serde/de.rs b/wasmer-it/src/serde/de.rs index adc21c1..b31279d 100644 --- a/wasmer-it/src/serde/de.rs +++ b/wasmer-it/src/serde/de.rs @@ -206,6 +206,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { V: de::Visitor<'de>, { match self.iterator.peek() { + Some(IValue::Boolean(_)) => self.deserialize_bool(visitor), Some(IValue::S8(_)) => self.deserialize_i8(visitor), Some(IValue::S16(_)) => self.deserialize_i16(visitor), Some(IValue::S32(_)) => self.deserialize_i32(visitor), @@ -217,6 +218,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { Some(IValue::F32(_)) => self.deserialize_f32(visitor), Some(IValue::F64(_)) => self.deserialize_f64(visitor), Some(IValue::String(_)) => self.deserialize_string(visitor), + Some(IValue::ByteArray(_)) => self.deserialize_bytes(visitor), Some(IValue::Array(_)) => self.deserialize_bytes(visitor), Some(IValue::I32(_)) => self.deserialize_i32(visitor), Some(IValue::I64(_)) => self.deserialize_i64(visitor), @@ -225,11 +227,11 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { } } - fn deserialize_bool(self, _visitor: V) -> Result + fn deserialize_bool(self, visitor: V) -> Result where V: de::Visitor<'de>, { - unimplemented!("`bool` is not supported by WIT for the moment.") + visitor.visit_bool(self.next_u8()? == 1) } fn deserialize_i8(self, visitor: V) -> Result From 748cf3b0f6eb4dedaf3ea2c0e5adc4603e9bf66c Mon Sep 17 00:00:00 2001 From: vms Date: Mon, 19 Apr 2021 21:21:59 +0300 Subject: [PATCH 05/27] misc updates --- crates/it-types/Cargo.toml | 2 +- wasmer-it/Cargo.toml | 4 ++-- wasmer-it/src/interpreter/instructions/arrays.rs | 1 - .../interpreter/instructions/arrays/write_arrays.rs | 1 - .../interpreter/instructions/records/lift_record.rs | 11 +++-------- 5 files changed, 6 insertions(+), 13 deletions(-) delete mode 100644 wasmer-it/src/interpreter/instructions/arrays/write_arrays.rs diff --git a/crates/it-types/Cargo.toml b/crates/it-types/Cargo.toml index 1d868d6..3e7d605 100644 --- a/crates/it-types/Cargo.toml +++ b/crates/it-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fluence-it-types" -version = "0.1.1" +version = "0.2.0" description = "Definitions of IValue and IType" authors = ["Fluence Labs"] edition = "2018" diff --git a/wasmer-it/Cargo.toml b/wasmer-it/Cargo.toml index 9b1521b..af700e1 100644 --- a/wasmer-it/Cargo.toml +++ b/wasmer-it/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-interface-types-fl" -version = "0.19.0" +version = "0.20.0" description = "WebAssembly Interface Types library for Wasmer" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -8,7 +8,7 @@ repository = "https://github.com/wasmerio/wasmer" edition = "2018" [dependencies] -fluence-it-types = { path = "../crates/it-types", version = "0.1.0", features = ["impls"] } +fluence-it-types = { path = "../crates/it-types", version = "0.2.0", features = ["impls"] } it-to-bytes = { path = "../crates/to-bytes", version = "0.1.0" } nom = "5.1" diff --git a/wasmer-it/src/interpreter/instructions/arrays.rs b/wasmer-it/src/interpreter/instructions/arrays.rs index 911d6f5..bc82de9 100644 --- a/wasmer-it/src/interpreter/instructions/arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays.rs @@ -2,7 +2,6 @@ mod lift_array; mod lower_array; mod memory_writer; mod read_arrays; -mod write_arrays; pub(crate) use lift_array::array_lift_memory_impl; pub(crate) use lower_array::array_lower_memory_impl; diff --git a/wasmer-it/src/interpreter/instructions/arrays/write_arrays.rs b/wasmer-it/src/interpreter/instructions/arrays/write_arrays.rs deleted file mode 100644 index 8b13789..0000000 --- a/wasmer-it/src/interpreter/instructions/arrays/write_arrays.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/wasmer-it/src/interpreter/instructions/records/lift_record.rs b/wasmer-it/src/interpreter/instructions/records/lift_record.rs index 0837c98..448acbd 100644 --- a/wasmer-it/src/interpreter/instructions/records/lift_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lift_record.rs @@ -66,14 +66,9 @@ fn record_size(record_type: &IRecordType) -> usize { 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 - | IType::String - | IType::ByteArray - | IType::Array(_) - | IType::Record(_) => 32, + 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 => 64, }; } From 93bf5e153d168225e87e776297220a6d70ae24a3 Mon Sep 17 00:00:00 2001 From: vms Date: Tue, 20 Apr 2021 02:36:40 +0300 Subject: [PATCH 06/27] bunch of small fixes --- Cargo.lock | 4 +- .../instructions/arrays/lower_array.rs | 25 +++++--- .../instructions/arrays/memory_writer.rs | 16 +++++ .../instructions/arrays/read_arrays.rs | 64 +++++++++---------- wasmer-it/src/interpreter/instructions/mod.rs | 2 + .../src/interpreter/instructions/records.rs | 2 + .../instructions/records/lift_record.rs | 4 +- .../instructions/records/lower_record.rs | 16 +++-- .../instructions/records/value_reader.rs | 1 - wasmer-it/src/interpreter/mod.rs | 4 +- wasmer-it/src/lib.rs | 2 + 11 files changed, 85 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c1243f..bd7fcfb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,7 +28,7 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "fluence-it-types" -version = "0.1.1" +version = "0.2.0" dependencies = [ "it-to-bytes", "nom", @@ -225,7 +225,7 @@ checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" [[package]] name = "wasmer-interface-types-fl" -version = "0.19.0" +version = "0.20.0" dependencies = [ "fluence-it-types", "it-to-bytes", diff --git a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs index a5920e9..54465b8 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs @@ -39,8 +39,6 @@ where .view(); let writer = MemoryWriter::new(memory_view, offset); - let values_count = array_values.len(); - // here it's known that all interface values have the same type for value in array_values { match value { @@ -59,29 +57,38 @@ where IValue::F64(value) => writer.write_array(value.to_le_bytes()), IValue::String(value) => { let string_pointer = - write_to_instance_mem(instance, instruction.clone(), value.as_bytes())?; + write_to_instance_mem(instance, instruction.clone(), value.as_bytes())? as u32; + let string_size = value.len() as u32; writer.write_array(string_pointer.to_le_bytes()); - writer.write_array(value.len().to_le_bytes()); + writer.write_array(string_size.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; + + writer.write_array(array_pointer.to_le_bytes()); + writer.write_array(array_size.to_le_bytes()); } - IValue::ByteArray(values) => writer.write_slice(&values), IValue::Array(values) => { let (array_offset, array_size) = array_lower_memory_impl(instance, instruction.clone(), 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()); } IValue::Record(values) => { let record_offset = - super::record_lower_memory_impl(instance, instruction.clone(), values)?; + super::record_lower_memory_impl(instance, instruction.clone(), values)? as u32; writer.write_array(record_offset.to_le_bytes()); } } } - Ok((offset as _, values_count as _)) + Ok((offset as _, writer.written_values() as _)) } fn value_size(value: &IValue) -> usize { @@ -97,9 +104,7 @@ fn value_size(value: &IValue) -> usize { IValue::U64(_) => 8, IValue::F32(_) => 4, IValue::F64(_) => 8, - IValue::String(_) => 4, - IValue::ByteArray(_) => 4, - IValue::Array(_) => 4, + IValue::String(_) | IValue::ByteArray(_) | IValue::Array(_) => 2 * 4, IValue::I32(_) => 4, IValue::I64(_) => 8, 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 index 015f97b..028e0a0 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/memory_writer.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/memory_writer.rs @@ -3,15 +3,18 @@ use std::cell::Cell; pub(super) struct MemoryWriter<'m> { memory_view: &'m [Cell], offset: Cell, + written_values: Cell, } impl<'m> MemoryWriter<'m> { pub(crate) fn new(memory_view: &'m [Cell], offset: usize) -> Self { let offset = Cell::new(offset); + let written_values = Cell::new(0); Self { memory_view, offset, + written_values, } } @@ -19,8 +22,10 @@ impl<'m> MemoryWriter<'m> { let offset = self.offset.get(); self.memory_view[offset].set(value); self.offset.set(offset + 1); + self.update_counter(); } + #[allow(dead_code)] pub(crate) fn write_slice(&self, values: &[u8]) { let offset = self.offset.get(); @@ -31,6 +36,7 @@ impl<'m> MemoryWriter<'m> { } self.offset.set(offset + values.len()); + self.update_counter(); } pub(crate) fn write_array(&self, values: [u8; N]) { @@ -43,5 +49,15 @@ impl<'m> MemoryWriter<'m> { } self.offset.set(offset + values.len()); + self.update_counter(); + } + + fn update_counter(&self) { + let written_values_count = self.written_values.get(); + self.written_values.set(written_values_count + 1); + } + + pub(crate) fn written_values(&self) -> usize { + self.written_values.get() } } diff --git a/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs b/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs index 37d69b5..a38341b 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs @@ -223,14 +223,14 @@ def_read_func!(read_u64_array, (u64, elements_count), { let mut result = Vec::with_capacity(elements_count); for element_id in 0..elements_count { let value = u64::from_le_bytes([ - Cell::get(&memory_view[4 * element_id]), - Cell::get(&memory_view[4 * element_id + 1]), - Cell::get(&memory_view[4 * element_id + 2]), - Cell::get(&memory_view[4 * element_id + 3]), - Cell::get(&memory_view[4 * element_id + 4]), - Cell::get(&memory_view[4 * element_id + 5]), - Cell::get(&memory_view[4 * element_id + 6]), - Cell::get(&memory_view[4 * element_id + 7]), + Cell::get(&memory_view[8 * element_id]), + Cell::get(&memory_view[8 * element_id + 1]), + Cell::get(&memory_view[8 * element_id + 2]), + Cell::get(&memory_view[8 * element_id + 3]), + Cell::get(&memory_view[8 * element_id + 4]), + Cell::get(&memory_view[8 * element_id + 5]), + Cell::get(&memory_view[8 * element_id + 6]), + Cell::get(&memory_view[8 * element_id + 7]), ]); result.push(IValue::U64(value)); } @@ -244,14 +244,14 @@ def_read_func!(read_f64_array, (f64, elements_count), { let mut result = Vec::with_capacity(elements_count); for element_id in 0..elements_count { let value = f64::from_le_bytes([ - Cell::get(&memory_view[4 * element_id]), - Cell::get(&memory_view[4 * element_id + 1]), - Cell::get(&memory_view[4 * element_id + 2]), - Cell::get(&memory_view[4 * element_id + 3]), - Cell::get(&memory_view[4 * element_id + 4]), - Cell::get(&memory_view[4 * element_id + 5]), - Cell::get(&memory_view[4 * element_id + 6]), - Cell::get(&memory_view[4 * element_id + 7]), + Cell::get(&memory_view[8 * element_id]), + Cell::get(&memory_view[8 * element_id + 1]), + Cell::get(&memory_view[8 * element_id + 2]), + Cell::get(&memory_view[8 * element_id + 3]), + Cell::get(&memory_view[8 * element_id + 4]), + Cell::get(&memory_view[8 * element_id + 5]), + Cell::get(&memory_view[8 * element_id + 6]), + Cell::get(&memory_view[8 * element_id + 7]), ]); result.push(IValue::F64(value)); } @@ -265,14 +265,14 @@ def_read_func!(read_s64_array, (i64, elements_count), { let mut result = Vec::with_capacity(elements_count); for element_id in 0..elements_count { let value = i64::from_le_bytes([ - Cell::get(&memory_view[4 * element_id]), - Cell::get(&memory_view[4 * element_id + 1]), - Cell::get(&memory_view[4 * element_id + 2]), - Cell::get(&memory_view[4 * element_id + 3]), - Cell::get(&memory_view[4 * element_id + 4]), - Cell::get(&memory_view[4 * element_id + 5]), - Cell::get(&memory_view[4 * element_id + 6]), - Cell::get(&memory_view[4 * element_id + 7]), + Cell::get(&memory_view[8 * element_id]), + Cell::get(&memory_view[8 * element_id + 1]), + Cell::get(&memory_view[8 * element_id + 2]), + Cell::get(&memory_view[8 * element_id + 3]), + Cell::get(&memory_view[8 * element_id + 4]), + Cell::get(&memory_view[8 * element_id + 5]), + Cell::get(&memory_view[8 * element_id + 6]), + Cell::get(&memory_view[8 * element_id + 7]), ]); result.push(IValue::S64(value)); } @@ -286,14 +286,14 @@ def_read_func!(read_i64_array, (i64, elements_count), { let mut result = Vec::with_capacity(elements_count); for element_id in 0..elements_count { let value = i64::from_le_bytes([ - Cell::get(&memory_view[4 * element_id]), - Cell::get(&memory_view[4 * element_id + 1]), - Cell::get(&memory_view[4 * element_id + 2]), - Cell::get(&memory_view[4 * element_id + 3]), - Cell::get(&memory_view[4 * element_id + 4]), - Cell::get(&memory_view[4 * element_id + 5]), - Cell::get(&memory_view[4 * element_id + 6]), - Cell::get(&memory_view[4 * element_id + 7]), + Cell::get(&memory_view[8 * element_id]), + Cell::get(&memory_view[8 * element_id + 1]), + Cell::get(&memory_view[8 * element_id + 2]), + Cell::get(&memory_view[8 * element_id + 3]), + Cell::get(&memory_view[8 * element_id + 4]), + Cell::get(&memory_view[8 * element_id + 5]), + Cell::get(&memory_view[8 * element_id + 6]), + Cell::get(&memory_view[8 * element_id + 7]), ]); result.push(IValue::I64(value)); } diff --git a/wasmer-it/src/interpreter/instructions/mod.rs b/wasmer-it/src/interpreter/instructions/mod.rs index 6f70ef4..f7f555d 100644 --- a/wasmer-it/src/interpreter/instructions/mod.rs +++ b/wasmer-it/src/interpreter/instructions/mod.rs @@ -17,6 +17,8 @@ use crate::IType; use crate::IValue; use crate::NEVec; +pub use records::record_size; + pub(crate) use argument_get::argument_get; pub(crate) use arrays::*; pub(crate) use call_core::call_core; diff --git a/wasmer-it/src/interpreter/instructions/records.rs b/wasmer-it/src/interpreter/instructions/records.rs index daf5eb1..dd47876 100644 --- a/wasmer-it/src/interpreter/instructions/records.rs +++ b/wasmer-it/src/interpreter/instructions/records.rs @@ -2,6 +2,8 @@ mod lift_record; mod lower_record; mod value_reader; +pub use lift_record::record_size; + pub(crate) use lift_record::record_lift_memory_impl; pub(crate) use lower_record::record_lower_memory_impl; diff --git a/wasmer-it/src/interpreter/instructions/records/lift_record.rs b/wasmer-it/src/interpreter/instructions/records/lift_record.rs index 448acbd..0ff3d92 100644 --- a/wasmer-it/src/interpreter/instructions/records/lift_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lift_record.rs @@ -58,8 +58,8 @@ where )) } -/// Returns record size in bytes. -fn record_size(record_type: &IRecordType) -> usize { +/// 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() { diff --git a/wasmer-it/src/interpreter/instructions/records/lower_record.rs b/wasmer-it/src/interpreter/instructions/records/lower_record.rs index 66b1f7e..e5a61ad 100644 --- a/wasmer-it/src/interpreter/instructions/records/lower_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lower_record.rs @@ -36,28 +36,30 @@ where IValue::F64(value) => result.extend_from_slice(&value.to_le_bytes()), IValue::String(value) => { let string_pointer = - write_to_instance_mem(instance, instruction.clone(), value.as_bytes())?; + write_to_instance_mem(instance, instruction.clone(), value.as_bytes())? as u32; result.extend_from_slice(&string_pointer.to_le_bytes()); - result.extend_from_slice(&value.len().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)?; + let array_pointer = + write_to_instance_mem(instance, instruction.clone(), &value)? as u32; result.extend_from_slice(&array_pointer.to_le_bytes()); - result.extend_from_slice(&value.len().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)?; - result.extend_from_slice(&offset.to_le_bytes()); - result.extend_from_slice(&size.to_le_bytes()); + 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)?; + let record_ptr = + record_lower_memory_impl(instance, instruction.clone(), values)? as u32; result.extend_from_slice(&record_ptr.to_le_bytes()); } diff --git a/wasmer-it/src/interpreter/instructions/records/value_reader.rs b/wasmer-it/src/interpreter/instructions/records/value_reader.rs index d74ec6b..6a67467 100644 --- a/wasmer-it/src/interpreter/instructions/records/value_reader.rs +++ b/wasmer-it/src/interpreter/instructions/records/value_reader.rs @@ -69,7 +69,6 @@ macro_rules! read_ty { }; } -// TODO: rewrite this with macros impl ValueReader { pub(super) fn new(stream: Vec) -> Self { let offset = Cell::new(0); diff --git a/wasmer-it/src/interpreter/mod.rs b/wasmer-it/src/interpreter/mod.rs index 8aada2e..32befdd 100644 --- a/wasmer-it/src/interpreter/mod.rs +++ b/wasmer-it/src/interpreter/mod.rs @@ -4,9 +4,11 @@ mod instructions; pub mod stack; pub mod wasm; +pub use instructions::record_size; +pub use instructions::Instruction; + use crate::errors::{InstructionResult, InterpreterResult}; use crate::IValue; -pub use instructions::Instruction; use stack::Stack; use std::{convert::TryFrom, marker::PhantomData}; diff --git a/wasmer-it/src/lib.rs b/wasmer-it/src/lib.rs index 013fa6b..9295128 100644 --- a/wasmer-it/src/lib.rs +++ b/wasmer-it/src/lib.rs @@ -73,6 +73,8 @@ pub use fluence_it_types::IValue; pub use it_to_bytes::ToBytes; +pub use crate::interpreter::record_size; + #[cfg(feature = "serde")] pub use crate::serde::de::from_interface_values; From 6e75b8a5cbbdc525b654c30873bbaf2df1eadd8e Mon Sep 17 00:00:00 2001 From: vms Date: Tue, 20 Apr 2021 03:37:38 +0300 Subject: [PATCH 07/27] update --- crates/it-types/src/types.rs | 2 +- wasmer-it/src/decoders/binary.rs | 3 ++ wasmer-it/src/decoders/wat.rs | 2 + wasmer-it/src/encoders/binary.rs | 2 + wasmer-it/src/encoders/wat.rs | 2 + wasmer-it/src/interpreter/instructions/mod.rs | 20 +++------- .../src/interpreter/instructions/numbers.rs | 39 +++++++++++++++++++ wasmer-it/src/interpreter/mod.rs | 2 + 8 files changed, 57 insertions(+), 15 deletions(-) diff --git a/crates/it-types/src/types.rs b/crates/it-types/src/types.rs index c3caced..362cd6f 100644 --- a/crates/it-types/src/types.rs +++ b/crates/it-types/src/types.rs @@ -101,7 +101,7 @@ impl Default for RecordType { impl ToString for &IType { fn to_string(&self) -> String { match &self { - IType::Boolean => "boolean".to_string(), + IType::Boolean => "bool".to_string(), IType::S8 => "s8".to_string(), IType::S16 => "s16".to_string(), IType::S32 => "s32".to_string(), diff --git a/wasmer-it/src/decoders/binary.rs b/wasmer-it/src/decoders/binary.rs index 9868d65..ef69dc8 100644 --- a/wasmer-it/src/decoders/binary.rs +++ b/wasmer-it/src/decoders/binary.rs @@ -357,6 +357,9 @@ fn instruction<'input, E: ParseError<&'input [u8]>>( 0x35 => (input, Instruction::Swap2), + 0x3E => (input, Instruction::BoolFromI32), + 0x3F => (input, Instruction::I32FromBool), + _ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))), }) } diff --git a/wasmer-it/src/decoders/wat.rs b/wasmer-it/src/decoders/wat.rs index b1fb492..9cbb8b1 100644 --- a/wasmer-it/src/decoders/wat.rs +++ b/wasmer-it/src/decoders/wat.rs @@ -39,6 +39,7 @@ mod keyword { // Instructions. custom_keyword!(argument_get = "arg.get"); custom_keyword!(call_core = "call-core"); + custom_keyword!(bool_from_i32 = "bool.from_i32"); custom_keyword!(s8_from_i32 = "s8.from_i32"); custom_keyword!(s8_from_i64 = "s8.from_i64"); custom_keyword!(s16_from_i32 = "s16.from_i32"); @@ -47,6 +48,7 @@ mod keyword { custom_keyword!(s32_from_i64 = "s32.from_i64"); custom_keyword!(s64_from_i32 = "s64.from_i32"); custom_keyword!(s64_from_i64 = "s64.from_i64"); + custom_keyword!(i32_from_bool = "i32.from_bool"); custom_keyword!(i32_from_s8 = "i32.from_s8"); custom_keyword!(i32_from_s16 = "i32.from_s16"); custom_keyword!(i32_from_s32 = "i32.from_s32"); diff --git a/wasmer-it/src/encoders/binary.rs b/wasmer-it/src/encoders/binary.rs index 7857dc6..4ca3a83 100644 --- a/wasmer-it/src/encoders/binary.rs +++ b/wasmer-it/src/encoders/binary.rs @@ -196,6 +196,7 @@ where (*function_index as u64).to_bytes(writer)?; } + Instruction::BoolFromI32 => 0x3E_u8.to_bytes(writer)?, Instruction::S8FromI32 => 0x02_u8.to_bytes(writer)?, Instruction::S8FromI64 => 0x03_u8.to_bytes(writer)?, Instruction::S16FromI32 => 0x04_u8.to_bytes(writer)?, @@ -204,6 +205,7 @@ where Instruction::S32FromI64 => 0x07_u8.to_bytes(writer)?, Instruction::S64FromI32 => 0x08_u8.to_bytes(writer)?, Instruction::S64FromI64 => 0x09_u8.to_bytes(writer)?, + Instruction::I32FromBool => 0x3F_u8.to_bytes(writer)?, Instruction::I32FromS8 => 0x0a_u8.to_bytes(writer)?, Instruction::I32FromS16 => 0x0b_u8.to_bytes(writer)?, Instruction::I32FromS32 => 0x0c_u8.to_bytes(writer)?, diff --git a/wasmer-it/src/encoders/wat.rs b/wasmer-it/src/encoders/wat.rs index ca71739..6a0f1eb 100644 --- a/wasmer-it/src/encoders/wat.rs +++ b/wasmer-it/src/encoders/wat.rs @@ -65,6 +65,7 @@ impl ToString for &Instruction { match self { Instruction::ArgumentGet { index } => format!("arg.get {}", index), Instruction::CallCore { function_index } => format!("call-core {}", function_index), + Instruction::BoolFromI32 => "bool.from_i32".into(), Instruction::S8FromI32 => "s8.from_i32".into(), Instruction::S8FromI64 => "s8.from_i64".into(), Instruction::S16FromI32 => "s16.from_i32".into(), @@ -73,6 +74,7 @@ impl ToString for &Instruction { Instruction::S32FromI64 => "s32.from_i64".into(), Instruction::S64FromI32 => "s64.from_i32".into(), Instruction::S64FromI64 => "s64.from_i64".into(), + Instruction::I32FromBool => "i32.from_bool".into(), Instruction::I32FromS8 => "i32.from_s8".into(), Instruction::I32FromS16 => "i32.from_s16".into(), Instruction::I32FromS32 => "i32.from_s32".into(), diff --git a/wasmer-it/src/interpreter/instructions/mod.rs b/wasmer-it/src/interpreter/instructions/mod.rs index f7f555d..b31193f 100644 --- a/wasmer-it/src/interpreter/instructions/mod.rs +++ b/wasmer-it/src/interpreter/instructions/mod.rs @@ -52,6 +52,9 @@ pub enum Instruction { function_index: u32, }, + /// The bool.from_i32` instruction. + BoolFromI32, + /// The `s8.from_i32` instruction. S8FromI32, @@ -76,6 +79,9 @@ pub enum Instruction { /// The `s64.from_i64` instruction. S64FromI64, + /// The i32.from_bool instruction. + I32FromBool, + /// The `i32.from_s8` instruction. I32FromS8, @@ -169,20 +175,6 @@ pub enum Instruction { value_type: IType, }, - /* - /// The `record.lift` instruction. - RecordLift { - /// The type index of the record. - type_index: u32, - }, - - /// The `record.lower` instruction. - RecordLower { - /// The type index of the record. - type_index: u32, - }, - - */ /// The `record.lift_memory` instruction. RecordLiftMemory { /// The type index of the record. diff --git a/wasmer-it/src/interpreter/instructions/numbers.rs b/wasmer-it/src/interpreter/instructions/numbers.rs index 30de571..b1dcc10 100644 --- a/wasmer-it/src/interpreter/instructions/numbers.rs +++ b/wasmer-it/src/interpreter/instructions/numbers.rs @@ -68,6 +68,7 @@ lowering_lifting!(s32_from_i32, "s32.from_i32", S32, I32); lowering_lifting!(s32_from_i64, "s32.from_i64", S32, I64); lowering_lifting!(s64_from_i32, "s64.from_i32", S64, I32); lowering_lifting!(s64_from_i64, "s64.from_i64", S64, I64); +lowering_lifting!(i32_from_bool, "i32.from_bool", I32, Boolean); lowering_lifting!(i32_from_s8, "i32.from_s8", I32, S8); lowering_lifting!(i32_from_s16, "i32.from_s16", I32, S16); lowering_lifting!(i32_from_s32, "i32.from_s32", I32, S32); @@ -93,6 +94,44 @@ lowering_lifting!(i64_from_u16, "i64.from_u16", I64, U16); lowering_lifting!(i64_from_u32, "i64.from_u32", I64, U32); lowering_lifting!(i64_from_u64, "i64.from_u64", I64, U64); +executable_instruction!( + bool_from_i32(instruction: Instruction) -> _ { + move |runtime| -> _ { + match runtime.stack.pop1() { + Some(IValue::I32(value)) => { + runtime + .stack + .push({ + let converted_value = IValue::Boolean(value == 1); + + log::trace!("bool.from_i32: converting {:?} to {:?}" , value, converted_value); + + converted_value + }) + } + Some(wrong_value) => { + return instr_error!( + instruction.clone(), + InstructionErrorKind::InvalidValueOnTheStack { + expected_type: IType::I32, + received_value: wrong_value, + } + ) + }, + + None => { + return instr_error!( + instruction.clone(), + InstructionErrorKind::StackIsTooSmall { needed: 1 } + ) + } + } + + Ok(()) + } + } +); + #[cfg(test)] mod tests { test_executable_instruction!( diff --git a/wasmer-it/src/interpreter/mod.rs b/wasmer-it/src/interpreter/mod.rs index 32befdd..b88fa20 100644 --- a/wasmer-it/src/interpreter/mod.rs +++ b/wasmer-it/src/interpreter/mod.rs @@ -200,6 +200,7 @@ where instructions::call_core(function_index, instruction) } + Instruction::BoolFromI32 => instructions::bool_from_i32(instruction), Instruction::S8FromI32 => instructions::s8_from_i32(instruction), Instruction::S8FromI64 => instructions::s8_from_i64(instruction), Instruction::S16FromI32 => instructions::s16_from_i32(instruction), @@ -208,6 +209,7 @@ where Instruction::S32FromI64 => instructions::s32_from_i64(instruction), Instruction::S64FromI32 => instructions::s64_from_i32(instruction), Instruction::S64FromI64 => instructions::s64_from_i64(instruction), + Instruction::I32FromBool => instructions::i32_from_bool(instruction), Instruction::I32FromS8 => instructions::i32_from_s8(instruction), Instruction::I32FromS16 => instructions::i32_from_s16(instruction), Instruction::I32FromS32 => instructions::i32_from_s32(instruction), From 2c40ced55d714aa29e3466b4ca875ecdab5a265c Mon Sep 17 00:00:00 2001 From: vms Date: Tue, 20 Apr 2021 15:26:58 +0300 Subject: [PATCH 08/27] update --- .../src/interpreter/instructions/arrays.rs | 2 + .../instructions/arrays/lower_array.rs | 22 ++-- .../instructions/arrays/read_arrays.rs | 106 ++++++------------ wasmer-it/src/interpreter/instructions/mod.rs | 23 ++++ .../src/interpreter/instructions/numbers.rs | 42 ++++++- .../instructions/records/lift_record.rs | 4 +- wasmer-it/src/interpreter/mod.rs | 1 + wasmer-it/src/lib.rs | 1 + wasmer-it/src/serde/de.rs | 2 +- 9 files changed, 110 insertions(+), 93 deletions(-) diff --git a/wasmer-it/src/interpreter/instructions/arrays.rs b/wasmer-it/src/interpreter/instructions/arrays.rs index bc82de9..4f90ef7 100644 --- a/wasmer-it/src/interpreter/instructions/arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays.rs @@ -3,6 +3,8 @@ 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; diff --git a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs index 54465b8..f7152af 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs @@ -24,7 +24,7 @@ where return Ok((0, 0)); } - let size_to_allocate = value_size(&array_values[0]) * array_values.len(); + let size_to_allocate = ser_value_size(&array_values[0]) * array_values.len(); let offset = super::allocate(instance, instruction.clone(), size_to_allocate)?; let memory_index = 0; @@ -91,22 +91,14 @@ where Ok((offset as _, writer.written_values() as _)) } -fn value_size(value: &IValue) -> usize { +/// Size of a value in a serialized view. +pub fn ser_value_size(value: &IValue) -> usize { match value { - IValue::Boolean(_) => 1, - IValue::S8(_) => 1, - IValue::S16(_) => 2, - IValue::S32(_) => 4, - IValue::S64(_) => 8, - IValue::U8(_) => 1, - IValue::U16(_) => 2, - IValue::U32(_) => 4, - IValue::U64(_) => 8, - IValue::F32(_) => 4, - IValue::F64(_) => 8, + 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::I32(_) => 4, - IValue::I64(_) => 8, IValue::Record(_) => 4, } } diff --git a/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs b/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs index a38341b..d41842e 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/read_arrays.rs @@ -41,6 +41,28 @@ macro_rules! def_read_func { }; } +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, @@ -89,7 +111,7 @@ def_read_func!(read_bool_array, (bool, elements_count), { 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 == 1)); + result.push(IValue::Boolean(value != 0)); } result @@ -124,10 +146,7 @@ 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([ - Cell::get(&memory_view[2 * element_id]), - Cell::get(&memory_view[2 * element_id + 1]), - ]); + let value = u16::from_le_bytes(value_der!(memory_view, element_id, 2)); result.push(IValue::U16(value)); } @@ -139,10 +158,7 @@ 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([ - Cell::get(&memory_view[2 * element_id]), - Cell::get(&memory_view[2 * element_id + 1]), - ]); + let value = i16::from_le_bytes(value_der!(memory_view, element_id, 2)); result.push(IValue::S16(value)); } @@ -154,12 +170,7 @@ 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([ - Cell::get(&memory_view[4 * element_id]), - Cell::get(&memory_view[4 * element_id + 1]), - Cell::get(&memory_view[4 * element_id + 2]), - Cell::get(&memory_view[4 * element_id + 3]), - ]); + let value = u32::from_le_bytes(value_der!(memory_view, element_id, 4)); result.push(IValue::U32(value)); } @@ -171,12 +182,7 @@ 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([ - Cell::get(&memory_view[4 * element_id]), - Cell::get(&memory_view[4 * element_id + 1]), - Cell::get(&memory_view[4 * element_id + 2]), - Cell::get(&memory_view[4 * element_id + 3]), - ]); + let value = f32::from_le_bytes(value_der!(memory_view, element_id, 4)); result.push(IValue::F32(value)); } @@ -188,12 +194,7 @@ 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([ - Cell::get(&memory_view[4 * element_id]), - Cell::get(&memory_view[4 * element_id + 1]), - Cell::get(&memory_view[4 * element_id + 2]), - Cell::get(&memory_view[4 * element_id + 3]), - ]); + let value = i32::from_le_bytes(value_der!(memory_view, element_id, 4)); result.push(IValue::S32(value)); } @@ -205,12 +206,7 @@ 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([ - Cell::get(&memory_view[4 * element_id]), - Cell::get(&memory_view[4 * element_id + 1]), - Cell::get(&memory_view[4 * element_id + 2]), - Cell::get(&memory_view[4 * element_id + 3]), - ]); + let value = i32::from_le_bytes(value_der!(memory_view, element_id, 4)); result.push(IValue::I32(value)); } @@ -222,16 +218,7 @@ 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([ - Cell::get(&memory_view[8 * element_id]), - Cell::get(&memory_view[8 * element_id + 1]), - Cell::get(&memory_view[8 * element_id + 2]), - Cell::get(&memory_view[8 * element_id + 3]), - Cell::get(&memory_view[8 * element_id + 4]), - Cell::get(&memory_view[8 * element_id + 5]), - Cell::get(&memory_view[8 * element_id + 6]), - Cell::get(&memory_view[8 * element_id + 7]), - ]); + let value = u64::from_le_bytes(value_der!(memory_view, element_id, 8)); result.push(IValue::U64(value)); } @@ -243,16 +230,7 @@ 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([ - Cell::get(&memory_view[8 * element_id]), - Cell::get(&memory_view[8 * element_id + 1]), - Cell::get(&memory_view[8 * element_id + 2]), - Cell::get(&memory_view[8 * element_id + 3]), - Cell::get(&memory_view[8 * element_id + 4]), - Cell::get(&memory_view[8 * element_id + 5]), - Cell::get(&memory_view[8 * element_id + 6]), - Cell::get(&memory_view[8 * element_id + 7]), - ]); + let value = f64::from_le_bytes(value_der!(memory_view, element_id, 8)); result.push(IValue::F64(value)); } @@ -264,16 +242,7 @@ 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([ - Cell::get(&memory_view[8 * element_id]), - Cell::get(&memory_view[8 * element_id + 1]), - Cell::get(&memory_view[8 * element_id + 2]), - Cell::get(&memory_view[8 * element_id + 3]), - Cell::get(&memory_view[8 * element_id + 4]), - Cell::get(&memory_view[8 * element_id + 5]), - Cell::get(&memory_view[8 * element_id + 6]), - Cell::get(&memory_view[8 * element_id + 7]), - ]); + let value = i64::from_le_bytes(value_der!(memory_view, element_id, 8)); result.push(IValue::S64(value)); } @@ -285,16 +254,7 @@ 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([ - Cell::get(&memory_view[8 * element_id]), - Cell::get(&memory_view[8 * element_id + 1]), - Cell::get(&memory_view[8 * element_id + 2]), - Cell::get(&memory_view[8 * element_id + 3]), - Cell::get(&memory_view[8 * element_id + 4]), - Cell::get(&memory_view[8 * element_id + 5]), - Cell::get(&memory_view[8 * element_id + 6]), - Cell::get(&memory_view[8 * element_id + 7]), - ]); + let value = i64::from_le_bytes(value_der!(memory_view, element_id, 8)); result.push(IValue::I64(value)); } diff --git a/wasmer-it/src/interpreter/instructions/mod.rs b/wasmer-it/src/interpreter/instructions/mod.rs index b31193f..9ff83ff 100644 --- a/wasmer-it/src/interpreter/instructions/mod.rs +++ b/wasmer-it/src/interpreter/instructions/mod.rs @@ -17,6 +17,7 @@ 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; @@ -258,6 +259,7 @@ where Instance: wasm::structures::Instance, { match (&interface_type, interface_value) { + (IType::Boolean, IValue::Boolean(_)) => Ok(()), (IType::S8, IValue::S8(_)) => Ok(()), (IType::S16, IValue::S16(_)) => Ok(()), (IType::S32, IValue::S32(_)) => Ok(()), @@ -271,6 +273,7 @@ where (IType::F32, IValue::F32(_)) => Ok(()), (IType::F64, IValue::F64(_)) => Ok(()), (IType::String, IValue::String(_)) => Ok(()), + (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())? @@ -278,6 +281,26 @@ where Ok(()) } + (IType::ByteArray, IValue::Array(values)) => { + for value in values { + is_value_compatible_to_type(instance, &IType::U8, value, instruction.clone())? + } + + Ok(()) + } + (IType::Array(ty), IValue::ByteArray(_)) => { + if ty.as_ref() == &IType::U8 { + return Ok(()); + } + + instr_error!( + instruction, + 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, diff --git a/wasmer-it/src/interpreter/instructions/numbers.rs b/wasmer-it/src/interpreter/instructions/numbers.rs index b1dcc10..d1ecbab 100644 --- a/wasmer-it/src/interpreter/instructions/numbers.rs +++ b/wasmer-it/src/interpreter/instructions/numbers.rs @@ -68,7 +68,7 @@ lowering_lifting!(s32_from_i32, "s32.from_i32", S32, I32); lowering_lifting!(s32_from_i64, "s32.from_i64", S32, I64); lowering_lifting!(s64_from_i32, "s64.from_i32", S64, I32); lowering_lifting!(s64_from_i64, "s64.from_i64", S64, I64); -lowering_lifting!(i32_from_bool, "i32.from_bool", I32, Boolean); +//lowering_lifting!(i32_from_bool, "i32.from_bool", I32, Boolean); lowering_lifting!(i32_from_s8, "i32.from_s8", I32, S8); lowering_lifting!(i32_from_s16, "i32.from_s16", I32, S16); lowering_lifting!(i32_from_s32, "i32.from_s32", I32, S32); @@ -102,7 +102,7 @@ executable_instruction!( runtime .stack .push({ - let converted_value = IValue::Boolean(value == 1); + let converted_value = IValue::Boolean(value != 0); log::trace!("bool.from_i32: converting {:?} to {:?}" , value, converted_value); @@ -132,6 +132,44 @@ executable_instruction!( } ); +executable_instruction!( + i32_from_bool(instruction: Instruction) -> _ { + move |runtime| -> _ { + match runtime.stack.pop1() { + Some(IValue::Boolean(value)) => { + runtime + .stack + .push({ + let converted_value = IValue::I32(value as _); + + log::trace!("i32.from_bool: converting {:?} to {:?}" , value, converted_value); + + converted_value + }) + } + Some(wrong_value) => { + return instr_error!( + instruction.clone(), + InstructionErrorKind::InvalidValueOnTheStack { + expected_type: IType::I32, + received_value: wrong_value, + } + ) + }, + + None => { + return instr_error!( + instruction.clone(), + InstructionErrorKind::StackIsTooSmall { needed: 1 } + ) + } + } + + Ok(()) + } + } +); + #[cfg(test)] mod tests { test_executable_instruction!( diff --git a/wasmer-it/src/interpreter/instructions/records/lift_record.rs b/wasmer-it/src/interpreter/instructions/records/lift_record.rs index 0ff3d92..77ea6f9 100644 --- a/wasmer-it/src/interpreter/instructions/records/lift_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lift_record.rs @@ -32,7 +32,7 @@ where for field in (*record_type.fields).iter() { match &field.ty { - IType::Boolean => values.push(IValue::Boolean(reader.read_u8() == 1)), + IType::Boolean => values.push(IValue::Boolean(reader.read_u8() != 0)), IType::S8 => values.push(IValue::S8(reader.read_i8())), IType::S16 => values.push(IValue::S16(reader.read_i16())), IType::S32 => values.push(IValue::S32(reader.read_i32())), @@ -69,7 +69,7 @@ pub fn record_size(record_type: &IRecordType) -> usize { 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 => 64, + IType::S64 | IType::U64 | IType::I64 | IType::F64 => 8, }; } diff --git a/wasmer-it/src/interpreter/mod.rs b/wasmer-it/src/interpreter/mod.rs index b88fa20..246d0e8 100644 --- a/wasmer-it/src/interpreter/mod.rs +++ b/wasmer-it/src/interpreter/mod.rs @@ -5,6 +5,7 @@ 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 9295128..9ed2e65 100644 --- a/wasmer-it/src/lib.rs +++ b/wasmer-it/src/lib.rs @@ -74,6 +74,7 @@ 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; diff --git a/wasmer-it/src/serde/de.rs b/wasmer-it/src/serde/de.rs index b31279d..0527523 100644 --- a/wasmer-it/src/serde/de.rs +++ b/wasmer-it/src/serde/de.rs @@ -231,7 +231,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: de::Visitor<'de>, { - visitor.visit_bool(self.next_u8()? == 1) + visitor.visit_bool(self.next_u8()? != 0) } fn deserialize_i8(self, visitor: V) -> Result From 5d219e963b110b7ee7e6fb10a189a5a5eb788552 Mon Sep 17 00:00:00 2001 From: vms Date: Tue, 20 Apr 2021 23:39:16 +0300 Subject: [PATCH 09/27] to save it --- Cargo.lock | 36 +++ Cargo.toml | 1 + crates/it-lilo-utils/Cargo.toml | 17 ++ crates/it-lilo-utils/src/error.rs | 29 +++ crates/it-lilo-utils/src/lib.rs | 7 + crates/it-lilo-utils/src/memory_reader.rs | 213 ++++++++++++++++++ crates/it-lilo-utils/src/memory_writer.rs | 149 ++++++++++++ crates/it-types/Cargo.toml | 4 + crates/to-bytes/Cargo.toml | 4 + wasmer-it/Cargo.toml | 2 + .../instructions/arrays/lower_array.rs | 5 +- .../instructions/arrays/memory_writer.rs | 15 -- .../src/interpreter/instructions/records.rs | 5 +- .../interpreter/instructions/records/error.rs | 17 ++ .../instructions/records/lift_record.rs | 166 +++++--------- .../instructions/records/lower_record.rs | 28 +-- .../instructions/records/value_reader.rs | 88 -------- wasmer-it/src/lib.rs | 1 + 18 files changed, 551 insertions(+), 236 deletions(-) create mode 100644 crates/it-lilo-utils/Cargo.toml create mode 100644 crates/it-lilo-utils/src/error.rs create mode 100644 crates/it-lilo-utils/src/lib.rs create mode 100644 crates/it-lilo-utils/src/memory_reader.rs create mode 100644 crates/it-lilo-utils/src/memory_writer.rs create mode 100644 wasmer-it/src/interpreter/instructions/records/error.rs delete mode 100644 wasmer-it/src/interpreter/instructions/records/value_reader.rs diff --git a/Cargo.lock b/Cargo.lock index bd7fcfb..92da332 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,6 +36,15 @@ dependencies = [ "wast", ] +[[package]] +name = "it-lilo-utils" +version = "0.1.0" +dependencies = [ + "fluence-it-types", + "paste", + "thiserror", +] + [[package]] name = "it-to-bytes" version = "0.1.0" @@ -100,6 +109,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "paste" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" + [[package]] name = "pest" version = "2.1.3" @@ -205,6 +220,26 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "thiserror" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ucd-trie" version = "0.1.3" @@ -228,6 +263,7 @@ name = "wasmer-interface-types-fl" version = "0.20.0" dependencies = [ "fluence-it-types", + "it-lilo-utils", "it-to-bytes", "itertools", "log", diff --git a/Cargo.toml b/Cargo.toml index 1190f48..726f79a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "crates/it-lilo-utils", "crates/to-bytes", "crates/it-types", "wasmer-it", diff --git a/crates/it-lilo-utils/Cargo.toml b/crates/it-lilo-utils/Cargo.toml new file mode 100644 index 0000000..32da557 --- /dev/null +++ b/crates/it-lilo-utils/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "it-lilo-utils" +version = "0.1.0" +authors = ["Fluence Labs"] +description = "Defines some helper utils for lifting/lowering IT" +edition = "2018" +license = "Apache-2.0" + +[lib] +name = "it_lilo_utils" +path = "src/lib.rs" + +[dependencies] +fluence-it-types = { path = "../it-types/", version = "0.2.0" } + +paste = "1.0.5" +thiserror = "1.0.24" diff --git a/crates/it-lilo-utils/src/error.rs b/crates/it-lilo-utils/src/error.rs new file mode 100644 index 0000000..881fb57 --- /dev/null +++ b/crates/it-lilo-utils/src/error.rs @@ -0,0 +1,29 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use thiserror::Error as ThisError; + +#[derive(Debug, ThisError)] +pub enum MemoryAccessError { + #[error( + "Out-of-bound Wasm memory access: offset {offset}, size {size}, while memory_size {memory_size}" + )] + InvalidAccess { + offset: usize, + size: usize, + memory_size: usize, + }, +} diff --git a/crates/it-lilo-utils/src/lib.rs b/crates/it-lilo-utils/src/lib.rs new file mode 100644 index 0000000..d3a518b --- /dev/null +++ b/crates/it-lilo-utils/src/lib.rs @@ -0,0 +1,7 @@ +pub mod error; +pub mod memory_reader; +pub mod memory_writer; + +pub use fluence_it_types::IValue; + +pub type MResult = std::result::Result; diff --git a/crates/it-lilo-utils/src/memory_reader.rs b/crates/it-lilo-utils/src/memory_reader.rs new file mode 100644 index 0000000..70e1956 --- /dev/null +++ b/crates/it-lilo-utils/src/memory_reader.rs @@ -0,0 +1,213 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::error::MemoryAccessError; +use crate::IValue; +use crate::MResult; + +use std::cell::Cell; + +pub struct MemoryReader<'m> { + pub(self) memory: &'m [Cell], +} + +/// Reads values of basic types sequentially from the provided reader. +/// It don't check memory limits for the optimization purposes, +/// so it could created by the MemoryReader::sequential_reader method. +pub struct SequentialReader<'r, 'm> { + reader: &'r MemoryReader<'m>, + offset: Cell, +} + +macro_rules! value_der { + ($self:expr, $offset:expr, @seq_start $($ids:tt),* @seq_end) => { + [$($self.reader.memory[$offset + $ids].get()),+] + }; + + ($self:expr, $offset:expr, 1) => { + value_der!($self, $offset, @seq_start 0 @seq_end); + }; + + ($self:expr, $offset:expr, 2) => { + value_der!($self, $offset, @seq_start 0, 1 @seq_end); + }; + + ($self:expr, $offset:expr, 4) => { + value_der!($self, $offset, @seq_start 0, 1, 2, 3 @seq_end); + }; + + ($self:expr, $offset:expr, 8) => { + value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7 @seq_end); + }; +} + +macro_rules! read_ty { + ($func_name:ident, $ty:ty, 1) => { + pub fn $func_name(&self) -> $ty { + let offset = self.offset.get(); + let result = <$ty>::from_le_bytes(value_der!(self, offset, 1)); + + self.offset.set(offset + 1); + result + } + }; + + ($func_name:ident, $ty:ty, 2) => { + pub fn $func_name(&self) -> $ty { + let offset = self.offset.get(); + let result = <$ty>::from_le_bytes(value_der!(self, offset, 2)); + + self.offset.set(offset + 2); + result + } + }; + + ($func_name:ident, $ty:ty, 4) => { + pub fn $func_name(&self) -> $ty { + let offset = self.offset.get(); + let result = <$ty>::from_le_bytes(value_der!(self, offset, 4)); + + self.offset.set(offset + 4); + result + } + }; + + ($func_name:ident, $ty:ty, 8) => { + pub fn $func_name(&self) -> $ty { + let offset = self.offset.get(); + let result = <$ty>::from_le_bytes(value_der!(self, offset, 8)); + + self.offset.set(offset + 8); + result + } + }; +} + +macro_rules! read_array_ty { + ($func_name:ident, $ty:ident, $ity:ident) => { + pub fn $func_name( + &self, + offset: usize, + elements_count: usize, + ) -> crate::MResult> { + let reader = + self.sequential_reader(offset, std::mem::size_of::<$ty>() * elements_count)?; + let mut result = Vec::with_capacity(elements_count); + + for _ in 0..elements_count { + let value = paste::paste! { reader.[]()}; + result.push(IValue::$ity(value)); + } + + Ok(result) + } + }; +} + +impl<'m> MemoryReader<'m> { + pub fn new(memory: &'m [Cell]) -> Self { + Self { memory } + } + + /// Returns reader that allows read sequentially. It's important that memory limit is checked + /// only inside this function. All others functions of the returned reader don't have any + /// checks assuming that reader is well-formed. + pub fn sequential_reader( + &self, + offset: usize, + size: usize, + ) -> MResult> { + self.check_access(offset, size)?; + + Ok(SequentialReader::new(&self, offset)) + } + + pub fn read_raw_u8_array(&self, offset: usize, elements_count: usize) -> MResult> { + let reader = self.sequential_reader(offset, elements_count)?; + let mut result = Vec::with_capacity(elements_count); + + for _ in 0..elements_count { + let value = reader.read_u8(); + result.push(value); + } + + Ok(result) + } + + pub fn read_bool_array(&self, offset: usize, elements_count: usize) -> MResult> { + let reader = self.sequential_reader(offset, elements_count)?; + let mut result = Vec::with_capacity(elements_count); + + for _ in 0..elements_count { + let value = reader.read_u8(); + result.push(IValue::Boolean(value != 0)); + } + + Ok(result) + } + + pub fn check_access(&self, offset: usize, size: usize) -> MResult<()> { + let right = offset + size; + if right < offset || right >= self.memory.len() { + return Err(MemoryAccessError::InvalidAccess { + offset, + size, + memory_size: self.memory.len(), + }); + } + + Ok(()) + } + + read_array_ty!(read_u8_array, u8, U8); + read_array_ty!(read_s8_array, i8, S8); + read_array_ty!(read_u16_array, u16, U16); + read_array_ty!(read_s16_array, i16, S16); + read_array_ty!(read_u32_array, u32, U32); + read_array_ty!(read_s32_array, i32, S32); + read_array_ty!(read_i32_array, i32, I32); + read_array_ty!(read_f32_array, f32, F32); + read_array_ty!(read_u64_array, u64, U64); + read_array_ty!(read_s64_array, i64, S64); + read_array_ty!(read_i64_array, i64, I64); + read_array_ty!(read_f64_array, f64, F64); +} + +impl<'r, 'm> SequentialReader<'r, 'm> { + pub(self) fn new(reader: &'r MemoryReader<'m>, offset: usize) -> Self { + let offset = Cell::new(offset); + Self { reader, offset } + } + + pub fn read_bool(&self) -> bool { + let offset = self.offset.get(); + let result = self.reader.memory[offset].get() != 0; + + self.offset.set(offset + 1); + result + } + + read_ty!(read_u8, u8, 1); + read_ty!(read_i8, i8, 1); + read_ty!(read_u16, u16, 2); + read_ty!(read_i16, i16, 2); + read_ty!(read_u32, u32, 4); + read_ty!(read_i32, i32, 4); + read_ty!(read_f32, f32, 4); + read_ty!(read_u64, u64, 8); + read_ty!(read_i64, i64, 8); + read_ty!(read_f64, f64, 8); +} diff --git a/crates/it-lilo-utils/src/memory_writer.rs b/crates/it-lilo-utils/src/memory_writer.rs new file mode 100644 index 0000000..885a7f6 --- /dev/null +++ b/crates/it-lilo-utils/src/memory_writer.rs @@ -0,0 +1,149 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::MResult; +use crate::error::MemoryAccessError; + +use std::cell::Cell; + +pub struct MemoryWriter<'m> { + memory: &'m [Cell], +} + +/// Writes values of basic types sequentially to the provided writer. +/// It don't check memory limits for the optimization purposes, +/// so it could created by the MemoryReader::sequential_reader method. +pub struct SequentialWriter<'w, 'm> { + writer: &'w MemoryWriter<'m>, + offset: Cell, +} + +impl<'m> MemoryWriter<'m> { + pub fn new(memory: &'m [Cell]) -> Self { + Self { memory } + } + + pub fn write_array(&self, offset: usize, values: [u8; N]) -> MResult<()> { + self.check_access(offset, values.len())?; + + self.memory[offset..offset + N] + .iter() + .zip(values.iter()) + .for_each(|(cell, &byte)| cell.set(byte)); + + Ok(()) + } + + // specialization of write_array for u8 + pub fn write_u8(&self, offset: usize, value: u8) -> MResult<()> { + self.check_access(offset, 1)?; + self.memory[offset].set(value); + + Ok(()) + } + + // specialization of write_array for u32 + pub fn write_u32(&self, offset: usize, value: u32) -> MResult<()> { + self.check_access(offset, 4)?; + + let value = value.to_le_bytes(); + self.memory[offset].set(value[0]); + self.memory[offset + 1].set(value[1]); + self.memory[offset + 2].set(value[2]); + self.memory[offset + 3].set(value[3]); + + Ok(()) + } + + pub fn write_bytes(&self, offset: usize, bytes: &[u8]) -> MResult<()> { + let writer = self.sequential_writer(offset, bytes.len())?; + writer.write_bytes(bytes); + + Ok(()) + } + + pub fn sequential_writer(&self, offset: usize, size: usize) -> MResult> { + self.check_access(offset, size)?; + + Ok(SequentialWriter::new(&self, offset)) + } + + pub fn check_access(&self, offset: usize, size: usize) -> MResult<()> { + let right = offset + size; + if right < offset || right >= self.memory.len() { + return Err(MemoryAccessError::InvalidAccess { + offset, + size, + memory_size: self.memory.len(), + }); + } + + Ok(()) + } +} + +impl<'w, 'm> SequentialWriter<'w, 'm> { + pub(super) fn new(writer: &'w MemoryWriter<'m>, offset: usize) -> Self { + let offset = Cell::new(offset); + + Self { writer, offset } + } + + pub fn write_array(&self, values: [u8; N]) { + let offset = self.offset.get(); + + self.writer.memory[offset..offset + N] + .iter() + .zip(values.iter()) + .for_each(|(cell, &byte)| cell.set(byte)); + + self.offset.set(offset + N); + } + + // specialization of write_array for u8 + pub fn write_u8(&self, value: u8) { + let offset = self.offset.get(); + + self.writer.memory[offset].set(value); + + self.offset.set(offset + 1); + } + + // specialization of write_array for u32 + pub fn write_u32(&self, value: u32) { + let offset = self.offset.get(); + + let value = value.to_le_bytes(); + self.writer.memory[offset].set(value[0]); + self.writer.memory[offset + 1].set(value[1]); + self.writer.memory[offset + 2].set(value[2]); + self.writer.memory[offset + 3].set(value[3]); + + self.offset.set(offset + 4); + } + + #[allow(dead_code)] + pub fn write_bytes(&self, bytes: &[u8]) { + let offset = self.offset.get(); + + self.writer.memory[offset..offset + bytes.len()] + .iter() + .zip(bytes) + .for_each(|(cell, &byte)| cell.set(byte)); + + self.offset.set(offset + bytes.len()); + } +} diff --git a/crates/it-types/Cargo.toml b/crates/it-types/Cargo.toml index 3e7d605..99a0a83 100644 --- a/crates/it-types/Cargo.toml +++ b/crates/it-types/Cargo.toml @@ -6,6 +6,10 @@ authors = ["Fluence Labs"] edition = "2018" license = "Apache-2.0" +[lib] +name = "fluence_it_types" +path = "src/lib.rs" + [dependencies] it-to-bytes = { path = "../to-bytes/", version = "0.1.0" } diff --git a/crates/to-bytes/Cargo.toml b/crates/to-bytes/Cargo.toml index 4b03d7a..0530b38 100644 --- a/crates/to-bytes/Cargo.toml +++ b/crates/to-bytes/Cargo.toml @@ -5,3 +5,7 @@ authors = ["Fluence Labs"] description = "Defines trait ToBytes used for IT serialization" edition = "2018" license = "Apache-2.0" + +[lib] +name = "it_to_bytes" +path = "src/lib.rs" diff --git a/wasmer-it/Cargo.toml b/wasmer-it/Cargo.toml index af700e1..ef8b07d 100644 --- a/wasmer-it/Cargo.toml +++ b/wasmer-it/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" [dependencies] fluence-it-types = { path = "../crates/it-types", version = "0.2.0", features = ["impls"] } it-to-bytes = { path = "../crates/to-bytes", version = "0.1.0" } +it-lilo-utils = { path = "../crates/it-lilo-utils", version = "0.1.0" } nom = "5.1" wast = "8.0" @@ -23,6 +24,7 @@ safe-transmute = "0.11.0" log = "0.4.11" itertools = "0.10.0" +thiserror = "1.0.24" semver = "0.11.0" [features] diff --git a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs index f7152af..2c1909f 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs @@ -24,7 +24,8 @@ where return Ok((0, 0)); } - let size_to_allocate = ser_value_size(&array_values[0]) * array_values.len(); + 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 memory_index = 0; @@ -88,7 +89,7 @@ where } } - Ok((offset as _, writer.written_values() as _)) + Ok((offset as _, elements_count as _)) } /// Size of a value in a serialized view. diff --git a/wasmer-it/src/interpreter/instructions/arrays/memory_writer.rs b/wasmer-it/src/interpreter/instructions/arrays/memory_writer.rs index 028e0a0..41d066e 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/memory_writer.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/memory_writer.rs @@ -3,18 +3,15 @@ use std::cell::Cell; pub(super) struct MemoryWriter<'m> { memory_view: &'m [Cell], offset: Cell, - written_values: Cell, } impl<'m> MemoryWriter<'m> { pub(crate) fn new(memory_view: &'m [Cell], offset: usize) -> Self { let offset = Cell::new(offset); - let written_values = Cell::new(0); Self { memory_view, offset, - written_values, } } @@ -22,7 +19,6 @@ impl<'m> MemoryWriter<'m> { let offset = self.offset.get(); self.memory_view[offset].set(value); self.offset.set(offset + 1); - self.update_counter(); } #[allow(dead_code)] @@ -36,7 +32,6 @@ impl<'m> MemoryWriter<'m> { } self.offset.set(offset + values.len()); - self.update_counter(); } pub(crate) fn write_array(&self, values: [u8; N]) { @@ -49,15 +44,5 @@ impl<'m> MemoryWriter<'m> { } self.offset.set(offset + values.len()); - self.update_counter(); - } - - fn update_counter(&self) { - let written_values_count = self.written_values.get(); - self.written_values.set(written_values_count + 1); - } - - pub(crate) fn written_values(&self) -> usize { - self.written_values.get() } } diff --git a/wasmer-it/src/interpreter/instructions/records.rs b/wasmer-it/src/interpreter/instructions/records.rs index dd47876..1ac952e 100644 --- a/wasmer-it/src/interpreter/instructions/records.rs +++ b/wasmer-it/src/interpreter/instructions/records.rs @@ -1,12 +1,15 @@ +mod error; mod lift_record; mod lower_record; -mod value_reader; 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; diff --git a/wasmer-it/src/interpreter/instructions/records/error.rs b/wasmer-it/src/interpreter/instructions/records/error.rs new file mode 100644 index 0000000..15ce57a --- /dev/null +++ b/wasmer-it/src/interpreter/instructions/records/error.rs @@ -0,0 +1,17 @@ +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 77ea6f9..5793696 100644 --- a/wasmer-it/src/interpreter/instructions/records/lift_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lift_record.rs @@ -1,6 +1,6 @@ -use super::read_from_instance_mem; +use super::LiLoRecordError; +use super::LiLoResult; -use super::value_reader::ValueReader; use crate::IRecordType; use crate::IType; use crate::IValue; @@ -10,52 +10,46 @@ use crate::{ interpreter::Instruction, }; +use it_lilo_utils::memory_reader::MemoryReader; +use it_lilo_utils::memory_reader::SequentialReader; + #[rustfmt::skip] -pub(crate) fn record_lift_memory_impl<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, +pub(crate) fn record_lift_memory_impl( + reader: &MemoryReader<'_>, record_type: &IRecordType, offset: 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 { let mut values = Vec::with_capacity(record_type.fields.len()); let size = record_size(record_type); - let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?; - let reader = ValueReader::new(data); + let seq_reader = reader.sequential_reader(offset, size)?; for field in (*record_type.fields).iter() { match &field.ty { - IType::Boolean => values.push(IValue::Boolean(reader.read_u8() != 0)), - IType::S8 => values.push(IValue::S8(reader.read_i8())), - IType::S16 => values.push(IValue::S16(reader.read_i16())), - IType::S32 => values.push(IValue::S32(reader.read_i32())), - IType::S64 => values.push(IValue::S64(reader.read_i64())), - IType::I32 => values.push(IValue::I32(reader.read_i32())), - IType::I64 => values.push(IValue::I64(reader.read_i64())), - IType::U8 => values.push(IValue::U8(reader.read_u8())), - IType::U16 => values.push(IValue::U16(reader.read_u16())), - IType::U32 => values.push(IValue::U32(reader.read_u32())), - IType::U64 => values.push(IValue::U64(reader.read_u64())), - IType::F32 => values.push(IValue::F32(reader.read_f32())), - IType::F64 => values.push(IValue::F64(reader.read_f64())), - IType::String => values.push(IValue::String(read_string(instance, instruction.clone(), &reader)?)), - IType::ByteArray => values.push(read_byte_array(instance, instruction.clone(), &reader)?), - IType::Array(ty) => values.push(read_array(instance, instruction.clone(), &reader, &**ty)?), - IType::Record(record_type_id) => values.push(read_record(instance, instruction.clone(), &reader, *record_type_id)?), + IType::Boolean => values.push(IValue::Boolean(seq_reader.read_u8() != 0)), + IType::S8 => values.push(IValue::S8(seq_reader.read_i8())), + IType::S16 => values.push(IValue::S16(seq_reader.read_i16())), + IType::S32 => values.push(IValue::S32(seq_reader.read_i32())), + IType::S64 => values.push(IValue::S64(seq_reader.read_i64())), + IType::I32 => values.push(IValue::I32(seq_reader.read_i32())), + IType::I64 => values.push(IValue::I64(seq_reader.read_i64())), + IType::U8 => values.push(IValue::U8(seq_reader.read_u8())), + IType::U16 => values.push(IValue::U16(seq_reader.read_u16())), + IType::U32 => values.push(IValue::U32(seq_reader.read_u32())), + IType::U64 => values.push(IValue::U64(seq_reader.read_u64())), + IType::F32 => values.push(IValue::F32(seq_reader.read_f32())), + 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)?), } } - Ok(IValue::Record( - NEVec::new(values.into_iter().collect()) - .expect("Record must have at least one field, zero given"), - )) + let record = NEVec::new(values.into_iter().collect()) + .map_err(|_| LiLoRecordError::EmptyRecord(record_type.name.clone()))?; + + Ok(IValue::Record(record)) } /// Returns the record size in bytes. @@ -76,28 +70,11 @@ pub fn record_size(record_type: &IRecordType) -> usize { record_size } -fn read_string<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &Instance, - instruction: Instruction, - reader: &ValueReader, -) -> 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 string_offset = reader.read_u32(); - let string_size = reader.read_u32(); +fn read_string(reader: &MemoryReader, seq_reader: &SequentialReader) -> LiLoResult { + let offset = seq_reader.read_u32(); + let size = seq_reader.read_u32(); - let string_mem = read_from_instance_mem( - instance, - instruction.clone(), - string_offset as _, - string_size as _, - )?; + 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)) @@ -106,69 +83,32 @@ where Ok(string) } -fn read_byte_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &Instance, - instruction: Instruction, - reader: &ValueReader, -) -> 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 offset = reader.read_u32(); - let elements_count = reader.read_u32(); +fn read_byte_array(reader: &MemoryReader, seq_reader: &SequentialReader) -> LiLoResult { + let offset = seq_reader.read_u32(); + let size = seq_reader.read_u32(); - let array = read_from_instance_mem(instance, instruction, offset as _, elements_count as _)?; - let byte_array = IValue::ByteArray(array); + let array = reader.read_raw_u8_array(offset as _, size as _)?; - Ok(byte_array) + Ok(IValue::ByteArray(array)) } -fn read_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &Instance, - instruction: Instruction, - reader: &ValueReader, - ty: &IType, -) -> 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 array_offset = reader.read_u32(); - let elements_count = reader.read_u32(); +fn read_array( + reader: &MemoryReader, + seq_reader: &SequentialReader, + value_type: &IType, +) -> LiLoResult { + let offset = seq_reader.read_u32(); + let size = seq_reader.read_u32(); - super::array_lift_memory_impl( - instance, - ty, - array_offset as _, - elements_count as _, - instruction, - ) + super::array_lift_memory_impl(reader, value_type, offset as _, size as _) } -fn read_record<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &Instance, - instruction: Instruction, - reader: &ValueReader, +fn read_record( + reader: &MemoryReader, + seq_reader: &SequentialReader, record_type_id: u64, -) -> 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 offset = reader.read_u32(); +) -> LiLoResult { + let offset = seq_reader.read_u32(); let record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| { InstructionError::new( @@ -177,5 +117,5 @@ where ) })?; - record_lift_memory_impl(instance, record_type, offset as _, instruction) + record_lift_memory_impl(reader, 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 e5a61ad..258f744 100644 --- a/wasmer-it/src/interpreter/instructions/records/lower_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lower_record.rs @@ -1,23 +1,17 @@ use super::write_to_instance_mem; - +use super::LiLoResult; +use super::LiLoRecordError; use crate::IValue; use crate::NEVec; -use crate::{errors::InstructionError, interpreter::Instruction}; -pub(crate) fn record_lower_memory_impl( - instance: &mut Instance, - instruction: Instruction, +use it_lilo_utils::memory_writer::MemoryWriter; + +pub(crate) fn record_lower_memory_impl( + writer: &MemoryWriter, values: NEVec, -) -> 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, -{ - let mut result: Vec = Vec::with_capacity(values.len()); +) -> LiLoResult { + let average_field_size = 4; + let mut result: Vec = Vec::with_capacity(average_field_size * values.len()); for value in values.into_vec() { match value { @@ -35,10 +29,10 @@ where 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 string_pointer = + let offset = write_to_instance_mem(instance, instruction.clone(), value.as_bytes())? as u32; - result.extend_from_slice(&string_pointer.to_le_bytes()); + result.extend_from_slice(&offset.to_le_bytes()); result.extend_from_slice(&(value.len() as u32).to_le_bytes()); } IValue::ByteArray(value) => { diff --git a/wasmer-it/src/interpreter/instructions/records/value_reader.rs b/wasmer-it/src/interpreter/instructions/records/value_reader.rs deleted file mode 100644 index 6a67467..0000000 --- a/wasmer-it/src/interpreter/instructions/records/value_reader.rs +++ /dev/null @@ -1,88 +0,0 @@ -use std::cell::Cell; - -pub(super) struct ValueReader { - stream: Vec, - offset: Cell, -} - -macro_rules! value_der { - ($self:expr, $offset:expr, @seq_start $($ids:tt),* @seq_end) => { - [$($self.stream[$offset + $ids]),+] - }; - - ($self:expr, $offset:expr, 1) => { - value_der!($self, $offset, @seq_start 0 @seq_end); - }; - - ($self:expr, $offset:expr, 2) => { - value_der!($self, $offset, @seq_start 0, 1 @seq_end); - }; - - ($self:expr, $offset:expr, 4) => { - value_der!($self, $offset, @seq_start 0, 1, 2, 3 @seq_end); - }; - - ($self:expr, $offset:expr, 8) => { - value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7 @seq_end); - }; -} - -macro_rules! read_ty { - ($func_name:ident, $ty:ty, 1) => { - pub(super) fn $func_name(&self) -> $ty { - let offset = self.offset.get(); - let result = <$ty>::from_le_bytes(value_der!(self, offset, 1)); - - self.offset.set(offset + 1); - result - } - }; - - ($func_name:ident, $ty:ty, 2) => { - pub(super) fn $func_name(&self) -> $ty { - let offset = self.offset.get(); - let result = <$ty>::from_le_bytes(value_der!(self, offset, 2)); - - self.offset.set(offset + 2); - result - } - }; - - ($func_name:ident, $ty:ty, 4) => { - pub(super) fn $func_name(&self) -> $ty { - let offset = self.offset.get(); - let result = <$ty>::from_le_bytes(value_der!(self, offset, 4)); - - self.offset.set(offset + 4); - result - } - }; - - ($func_name:ident, $ty:ty, 8) => { - pub(super) fn $func_name(&self) -> $ty { - let offset = self.offset.get(); - let result = <$ty>::from_le_bytes(value_der!(self, offset, 8)); - - self.offset.set(offset + 8); - result - } - }; -} - -impl ValueReader { - pub(super) fn new(stream: Vec) -> Self { - let offset = Cell::new(0); - Self { stream, offset } - } - - read_ty!(read_u8, u8, 1); - read_ty!(read_i8, i8, 1); - read_ty!(read_u16, u16, 2); - read_ty!(read_i16, i16, 2); - read_ty!(read_u32, u32, 4); - read_ty!(read_i32, i32, 4); - read_ty!(read_f32, f32, 4); - read_ty!(read_u64, u64, 8); - read_ty!(read_i64, i64, 8); - read_ty!(read_f64, f64, 8); -} diff --git a/wasmer-it/src/lib.rs b/wasmer-it/src/lib.rs index 9ed2e65..5b55510 100644 --- a/wasmer-it/src/lib.rs +++ b/wasmer-it/src/lib.rs @@ -65,6 +65,7 @@ mod serde; mod values; // re-exports +pub use fluence_it_types::ne_vec; pub use fluence_it_types::ne_vec::NEVec; pub use fluence_it_types::IRecordFieldType; pub use fluence_it_types::IRecordType; From aa8ab1b1e3b4cdd13315f896af1f938947d88e93 Mon Sep 17 00:00:00 2001 From: vms Date: Wed, 21 Apr 2021 00:43:17 +0300 Subject: [PATCH 10/27] 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; From a48662d48cffdb2a989d72d106b5e0fdc2863e27 Mon Sep 17 00:00:00 2001 From: vms Date: Wed, 21 Apr 2021 04:17:18 +0300 Subject: [PATCH 11/27] rename type_code to type_tag --- crates/it-lilo-utils/src/lib.rs | 4 ++-- .../src/interpreter/instructions/arrays/lower_array.rs | 4 ++-- wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/it-lilo-utils/src/lib.rs b/crates/it-lilo-utils/src/lib.rs index 8b5934b..dd94ae1 100644 --- a/crates/it-lilo-utils/src/lib.rs +++ b/crates/it-lilo-utils/src/lib.rs @@ -44,7 +44,7 @@ pub fn record_size(record_type: &IRecordType) -> usize { .sum() } -pub fn type_code_form_itype(itype: &IType) -> u32 { +pub fn type_tag_form_itype(itype: &IType) -> u32 { const POINTER_CODE: u32 = 3; // u32 on the sdk match itype { @@ -63,7 +63,7 @@ pub fn type_code_form_itype(itype: &IType) -> u32 { } } -pub fn type_code_form_ivalue(itype: &IValue) -> u32 { +pub fn type_tag_form_ivalue(itype: &IValue) -> u32 { const POINTER_CODE: u32 = 3; // u32 on the sdk match itype { diff --git a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs index 1a6d727..a27d867 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs @@ -3,7 +3,7 @@ use super::lilo::*; use crate::IValue; use it_lilo_utils::ser_value_size; -use it_lilo_utils::type_code_form_ivalue; +use it_lilo_utils::type_tag_form_ivalue; pub(crate) fn array_lower_memory_impl( lo_helper: &LoHelper, @@ -17,7 +17,7 @@ pub(crate) fn array_lower_memory_impl( let size_to_allocate = ser_value_size(&array_values[0]) * elements_count; let offset = (lo_helper.allocate)( size_to_allocate as _, - type_code_form_ivalue(&array_values[0]) as _, + type_tag_form_ivalue(&array_values[0]) as _, )?; let seq_writer = lo_helper diff --git a/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs b/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs index 2bbd62a..b2e1b5d 100644 --- a/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs +++ b/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs @@ -5,7 +5,7 @@ use crate::interpreter::wasm; use crate::IType; use it_lilo_utils::memory_writer::MemoryWriter; -use it_lilo_utils::type_code_form_itype; +use it_lilo_utils::type_tag_form_itype; use std::cell::Cell; @@ -35,8 +35,8 @@ impl<'instance> LoHelper<'instance> { } 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 _)?; + let alloc_type_tag = type_tag_form_itype(&IType::U8); + let offset = (self.allocate)(bytes.len() as _, alloc_type_tag as _)?; self.writer.write_bytes(offset, bytes)?; From 8de882c159eef7b53d8a7fc290a0c6aa011722a7 Mon Sep 17 00:00:00 2001 From: vms Date: Wed, 21 Apr 2021 19:18:45 +0300 Subject: [PATCH 12/27] housekeeping, pr fixes --- crates/it-lilo-utils/src/lib.rs | 21 +++- crates/it-lilo-utils/src/macros.rs | 103 ++++++++++++++++++ crates/it-lilo-utils/src/memory_reader.rs | 93 +--------------- crates/it-lilo-utils/src/memory_writer.rs | 4 +- wasmer-it/src/decoders/binary.rs | 46 ++++---- wasmer-it/src/decoders/wat.rs | 16 +++ wasmer-it/src/encoders/binary.rs | 19 ++-- wasmer-it/src/encoders/wat.rs | 7 +- wasmer-it/src/interpreter/instructions/mod.rs | 14 +++ .../src/interpreter/instructions/numbers.rs | 40 +------ .../src/interpreter/instructions/push.rs | 25 +++++ .../instructions/records/lift_record.rs | 7 +- wasmer-it/src/interpreter/mod.rs | 2 + 13 files changed, 225 insertions(+), 172 deletions(-) create mode 100644 crates/it-lilo-utils/src/macros.rs create mode 100644 wasmer-it/src/interpreter/instructions/push.rs diff --git a/crates/it-lilo-utils/src/lib.rs b/crates/it-lilo-utils/src/lib.rs index dd94ae1..170b727 100644 --- a/crates/it-lilo-utils/src/lib.rs +++ b/crates/it-lilo-utils/src/lib.rs @@ -1,4 +1,21 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + pub mod error; +mod macros; pub mod memory_reader; pub mod memory_writer; @@ -45,7 +62,7 @@ pub fn record_size(record_type: &IRecordType) -> usize { } pub fn type_tag_form_itype(itype: &IType) -> u32 { - const POINTER_CODE: u32 = 3; // u32 on the sdk + const POINTER_CODE: u32 = 3; // u32 in the sdk match itype { IType::Boolean => 0, // u8 @@ -64,7 +81,7 @@ pub fn type_tag_form_itype(itype: &IType) -> u32 { } pub fn type_tag_form_ivalue(itype: &IValue) -> u32 { - const POINTER_CODE: u32 = 3; // u32 on the sdk + const POINTER_CODE: u32 = 3; // u32 in the sdk match itype { IValue::Boolean(_) => 0, // u8 diff --git a/crates/it-lilo-utils/src/macros.rs b/crates/it-lilo-utils/src/macros.rs new file mode 100644 index 0000000..dfb0d14 --- /dev/null +++ b/crates/it-lilo-utils/src/macros.rs @@ -0,0 +1,103 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#[macro_export] +macro_rules! value_der { + ($self:expr, $offset:expr, @seq_start $($ids:tt),* @seq_end) => { + [$($self.reader.memory[$offset + $ids].get()),+] + }; + + ($self:expr, $offset:expr, 1) => { + crate::value_der!($self, $offset, @seq_start 0 @seq_end); + }; + + ($self:expr, $offset:expr, 2) => { + crate::value_der!($self, $offset, @seq_start 0, 1 @seq_end); + }; + + ($self:expr, $offset:expr, 4) => { + crate::value_der!($self, $offset, @seq_start 0, 1, 2, 3 @seq_end); + }; + + ($self:expr, $offset:expr, 8) => { + crate::value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7 @seq_end); + }; +} + +#[macro_export] +macro_rules! read_ty { + ($func_name:ident, $ty:ty, 1) => { + pub fn $func_name(&self) -> $ty { + let offset = self.offset.get(); + let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 1)); + + self.offset.set(offset + 1); + result + } + }; + + ($func_name:ident, $ty:ty, 2) => { + pub fn $func_name(&self) -> $ty { + let offset = self.offset.get(); + let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 2)); + + self.offset.set(offset + 2); + result + } + }; + + ($func_name:ident, $ty:ty, 4) => { + pub fn $func_name(&self) -> $ty { + let offset = self.offset.get(); + let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 4)); + + self.offset.set(offset + 4); + result + } + }; + + ($func_name:ident, $ty:ty, 8) => { + pub fn $func_name(&self) -> $ty { + let offset = self.offset.get(); + let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 8)); + + self.offset.set(offset + 8); + result + } + }; +} + +#[macro_export] +macro_rules! read_array_ty { + ($func_name:ident, $ty:ident, $ity:ident) => { + pub fn $func_name( + &self, + offset: usize, + elements_count: usize, + ) -> crate::MResult> { + let reader = + self.sequential_reader(offset, std::mem::size_of::<$ty>() * elements_count)?; + let mut result = Vec::with_capacity(elements_count); + + for _ in 0..elements_count { + let value = paste::paste! { reader.[]()}; + result.push(IValue::$ity(value)); + } + + Ok(result) + } + }; +} diff --git a/crates/it-lilo-utils/src/memory_reader.rs b/crates/it-lilo-utils/src/memory_reader.rs index 70e1956..5065ee2 100644 --- a/crates/it-lilo-utils/src/memory_reader.rs +++ b/crates/it-lilo-utils/src/memory_reader.rs @@ -15,6 +15,8 @@ */ use crate::error::MemoryAccessError; +use crate::read_array_ty; +use crate::read_ty; use crate::IValue; use crate::MResult; @@ -25,98 +27,13 @@ pub struct MemoryReader<'m> { } /// Reads values of basic types sequentially from the provided reader. -/// It don't check memory limits for the optimization purposes, -/// so it could created by the MemoryReader::sequential_reader method. +/// It doesn't check memory limits for the optimization purposes, +/// so it could be created only by the MemoryReader::sequential_reader method. pub struct SequentialReader<'r, 'm> { reader: &'r MemoryReader<'m>, offset: Cell, } -macro_rules! value_der { - ($self:expr, $offset:expr, @seq_start $($ids:tt),* @seq_end) => { - [$($self.reader.memory[$offset + $ids].get()),+] - }; - - ($self:expr, $offset:expr, 1) => { - value_der!($self, $offset, @seq_start 0 @seq_end); - }; - - ($self:expr, $offset:expr, 2) => { - value_der!($self, $offset, @seq_start 0, 1 @seq_end); - }; - - ($self:expr, $offset:expr, 4) => { - value_der!($self, $offset, @seq_start 0, 1, 2, 3 @seq_end); - }; - - ($self:expr, $offset:expr, 8) => { - value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7 @seq_end); - }; -} - -macro_rules! read_ty { - ($func_name:ident, $ty:ty, 1) => { - pub fn $func_name(&self) -> $ty { - let offset = self.offset.get(); - let result = <$ty>::from_le_bytes(value_der!(self, offset, 1)); - - self.offset.set(offset + 1); - result - } - }; - - ($func_name:ident, $ty:ty, 2) => { - pub fn $func_name(&self) -> $ty { - let offset = self.offset.get(); - let result = <$ty>::from_le_bytes(value_der!(self, offset, 2)); - - self.offset.set(offset + 2); - result - } - }; - - ($func_name:ident, $ty:ty, 4) => { - pub fn $func_name(&self) -> $ty { - let offset = self.offset.get(); - let result = <$ty>::from_le_bytes(value_der!(self, offset, 4)); - - self.offset.set(offset + 4); - result - } - }; - - ($func_name:ident, $ty:ty, 8) => { - pub fn $func_name(&self) -> $ty { - let offset = self.offset.get(); - let result = <$ty>::from_le_bytes(value_der!(self, offset, 8)); - - self.offset.set(offset + 8); - result - } - }; -} - -macro_rules! read_array_ty { - ($func_name:ident, $ty:ident, $ity:ident) => { - pub fn $func_name( - &self, - offset: usize, - elements_count: usize, - ) -> crate::MResult> { - let reader = - self.sequential_reader(offset, std::mem::size_of::<$ty>() * elements_count)?; - let mut result = Vec::with_capacity(elements_count); - - for _ in 0..elements_count { - let value = paste::paste! { reader.[]()}; - result.push(IValue::$ity(value)); - } - - Ok(result) - } - }; -} - impl<'m> MemoryReader<'m> { pub fn new(memory: &'m [Cell]) -> Self { Self { memory } @@ -161,6 +78,8 @@ impl<'m> MemoryReader<'m> { pub fn check_access(&self, offset: usize, size: usize) -> MResult<()> { let right = offset + size; + + // the first condition is a check for overflow if right < offset || right >= self.memory.len() { return Err(MemoryAccessError::InvalidAccess { offset, diff --git a/crates/it-lilo-utils/src/memory_writer.rs b/crates/it-lilo-utils/src/memory_writer.rs index f75cd65..a616d1f 100644 --- a/crates/it-lilo-utils/src/memory_writer.rs +++ b/crates/it-lilo-utils/src/memory_writer.rs @@ -25,7 +25,7 @@ pub struct MemoryWriter<'m> { /// Writes values of basic types sequentially to the provided writer. /// It don't check memory limits for the optimization purposes, -/// so it could created by the MemoryReader::sequential_reader method. +/// so it could be created only by the MemoryReader::sequential_reader method. pub struct SequentialWriter<'w, 'm> { writer: &'w MemoryWriter<'m>, offset: Cell, @@ -87,6 +87,8 @@ impl<'m> MemoryWriter<'m> { pub fn check_access(&self, offset: usize, size: usize) -> MResult<()> { let right = offset + size; + + // the first condition is a check for overflow if right < offset || right >= self.memory.len() { return Err(MemoryAccessError::InvalidAccess { offset, diff --git a/wasmer-it/src/decoders/binary.rs b/wasmer-it/src/decoders/binary.rs index ef69dc8..ea24b01 100644 --- a/wasmer-it/src/decoders/binary.rs +++ b/wasmer-it/src/decoders/binary.rs @@ -308,30 +308,6 @@ fn instruction<'input, E: ParseError<&'input [u8]>>( (input, Instruction::ArrayLowerMemory { value_type }) } - /* - 0x39 => (input, Instruction::ArraySize), - - 0x25 => { - consume!((input, argument_0) = uleb(input)?); - - ( - input, - Instruction::RecordLift { - type_index: argument_0 as u32, - }, - ) - } - 0x26 => { - consume!((input, argument_0) = uleb(input)?); - - ( - input, - Instruction::RecordLower { - type_index: argument_0 as u32, - }, - ) - } - */ 0x3A => { consume!((input, record_type_id) = uleb(input)?); @@ -360,6 +336,28 @@ fn instruction<'input, E: ParseError<&'input [u8]>>( 0x3E => (input, Instruction::BoolFromI32), 0x3F => (input, Instruction::I32FromBool), + 0x40 => { + consume!((input, value) = uleb(input)?); + + ( + input, + Instruction::PushI32 { + value: value as i32, + }, + ) + } + + 0x41 => { + consume!((input, value) = uleb(input)?); + + ( + input, + Instruction::PushI64 { + value: value as i64, + }, + ) + } + _ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))), }) } diff --git a/wasmer-it/src/decoders/wat.rs b/wasmer-it/src/decoders/wat.rs index 9cbb8b1..577ffa4 100644 --- a/wasmer-it/src/decoders/wat.rs +++ b/wasmer-it/src/decoders/wat.rs @@ -53,10 +53,12 @@ mod keyword { custom_keyword!(i32_from_s16 = "i32.from_s16"); custom_keyword!(i32_from_s32 = "i32.from_s32"); custom_keyword!(i32_from_s64 = "i32.from_s64"); + custom_keyword!(i32_push = "i32.push"); custom_keyword!(i64_from_s8 = "i64.from_s8"); custom_keyword!(i64_from_s16 = "i64.from_s16"); custom_keyword!(i64_from_s32 = "i64.from_s32"); custom_keyword!(i64_from_s64 = "i64.from_s64"); + custom_keyword!(i64_push = "i64.push"); custom_keyword!(u8_from_i32 = "u8.from_i32"); custom_keyword!(u8_from_i64 = "u8.from_i64"); custom_keyword!(u16_from_i32 = "u16.from_i32"); @@ -73,6 +75,8 @@ mod keyword { custom_keyword!(i64_from_u16 = "i64.from_u16"); custom_keyword!(i64_from_u32 = "i64.from_u32"); custom_keyword!(i64_from_u64 = "i64.from_u64"); + custom_keyword!(f32_push = "f32.push"); + custom_keyword!(f64_push = "f64.push"); custom_keyword!(string_lift_memory = "string.lift_memory"); custom_keyword!(string_lower_memory = "string.lower_memory"); custom_keyword!(string_size = "string.size"); @@ -153,6 +157,12 @@ impl<'a> Parse<'a> for Instruction { parser.parse::()?; Ok(Instruction::I32FromS64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::PushI32 { + value: parser.parse()?, + }) } else if lookahead.peek::() { parser.parse::()?; @@ -169,6 +179,12 @@ impl<'a> Parse<'a> for Instruction { parser.parse::()?; Ok(Instruction::I64FromS64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::PushI64 { + value: parser.parse()?, + }) } else if lookahead.peek::() { parser.parse::()?; diff --git a/wasmer-it/src/encoders/binary.rs b/wasmer-it/src/encoders/binary.rs index 4ca3a83..ae64052 100644 --- a/wasmer-it/src/encoders/binary.rs +++ b/wasmer-it/src/encoders/binary.rs @@ -243,17 +243,6 @@ where 0x38_u8.to_bytes(writer)?; value_type.to_bytes(writer)? } - /* - Instruction::ArraySize => 0x39_u8.to_bytes(writer)?, - Instruction::RecordLift { type_index } => { - 0x25_u8.to_bytes(writer)?; - (*type_index as u64).to_bytes(writer)? - } - Instruction::RecordLower { type_index } => { - 0x26_u8.to_bytes(writer)?; - (*type_index as u64).to_bytes(writer)? - } - */ Instruction::RecordLiftMemory { record_type_id: type_index, } => { @@ -268,6 +257,14 @@ where } Instruction::Dup => 0x34_u8.to_bytes(writer)?, Instruction::Swap2 => 0x35_u8.to_bytes(writer)?, + Instruction::PushI32 { value } => { + 0x40_u8.to_bytes(writer)?; + (*value as u64).to_bytes(writer)? + } + Instruction::PushI64 { value } => { + 0x41_u8.to_bytes(writer)?; + (*value as u64).to_bytes(writer)? + } } Ok(()) diff --git a/wasmer-it/src/encoders/wat.rs b/wasmer-it/src/encoders/wat.rs index 6a0f1eb..a11c6de 100644 --- a/wasmer-it/src/encoders/wat.rs +++ b/wasmer-it/src/encoders/wat.rs @@ -108,11 +108,6 @@ impl ToString for &Instruction { Instruction::ArrayLowerMemory { value_type } => { format!("array.lower_memory {}", value_type.to_string()) } - /* - Instruction::ArraySize => "byte_array.size".into(), - Instruction::RecordLift { type_index } => format!("record.lift {}", type_index), - Instruction::RecordLower { type_index } => format!("record.lower {}", type_index), - */ Instruction::RecordLiftMemory { record_type_id: type_index, } => format!("record.lift_memory {}", type_index), @@ -121,6 +116,8 @@ impl ToString for &Instruction { } => format!("record.lower_memory {}", type_index), Instruction::Dup => "dup".into(), Instruction::Swap2 => "swap2".into(), + Instruction::PushI32 { value } => format!("i32.push {}", value), + Instruction::PushI64 { value } => format!("i64.push {}", value), } } } diff --git a/wasmer-it/src/interpreter/instructions/mod.rs b/wasmer-it/src/interpreter/instructions/mod.rs index b2c31a5..fdf64da 100644 --- a/wasmer-it/src/interpreter/instructions/mod.rs +++ b/wasmer-it/src/interpreter/instructions/mod.rs @@ -4,6 +4,7 @@ mod call_core; mod dup; pub(self) mod lilo; mod numbers; +mod push; mod records; mod strings; mod swap2; @@ -21,6 +22,7 @@ pub(crate) use arrays::*; pub(crate) use call_core::call_core; pub(crate) use dup::dup; pub(crate) use numbers::*; +pub(crate) use push::*; pub(crate) use records::*; pub(crate) use strings::*; pub(crate) use swap2::swap2; @@ -183,6 +185,18 @@ pub enum Instruction { record_type_id: u32, }, + /// The `i32.push` instruction. + PushI32 { + /// The value that should be pushed on the stack. + value: i32, + }, + + /// The `i64.push` instruction. + PushI64 { + /// The value that should be pushed on the stack. + value: i64, + }, + /// The `dup` instructions. Dup, diff --git a/wasmer-it/src/interpreter/instructions/numbers.rs b/wasmer-it/src/interpreter/instructions/numbers.rs index 6eab229..e6edb2b 100644 --- a/wasmer-it/src/interpreter/instructions/numbers.rs +++ b/wasmer-it/src/interpreter/instructions/numbers.rs @@ -68,7 +68,7 @@ lowering_lifting!(s32_from_i32, "s32.from_i32", S32, I32); lowering_lifting!(s32_from_i64, "s32.from_i64", S32, I64); lowering_lifting!(s64_from_i32, "s64.from_i32", S64, I32); lowering_lifting!(s64_from_i64, "s64.from_i64", S64, I64); -//lowering_lifting!(i32_from_bool, "i32.from_bool", I32, Boolean); +lowering_lifting!(i32_from_bool, "i32.from_bool", I32, Boolean); lowering_lifting!(i32_from_s8, "i32.from_s8", I32, S8); lowering_lifting!(i32_from_s16, "i32.from_s16", I32, S16); lowering_lifting!(i32_from_s32, "i32.from_s32", I32, S32); @@ -132,44 +132,6 @@ executable_instruction!( } ); -executable_instruction!( - i32_from_bool(instruction: Instruction) -> _ { - move |runtime| -> _ { - match runtime.stack.pop1() { - Some(IValue::Boolean(value)) => { - runtime - .stack - .push({ - let converted_value = IValue::I32(value as _); - - log::trace!("i32.from_bool: converting {:?} to {:?}" , value, converted_value); - - converted_value - }) - } - Some(wrong_value) => { - return instr_error!( - instruction.clone(), - InstructionErrorKind::InvalidValueOnTheStack { - expected_type: IType::I32, - received_value: wrong_value, - } - ) - }, - - None => { - return instr_error!( - instruction.clone(), - InstructionErrorKind::StackIsTooSmall { needed: 1 } - ) - } - } - - Ok(()) - } - } -); - #[cfg(test)] mod tests { test_executable_instruction!( diff --git a/wasmer-it/src/interpreter/instructions/push.rs b/wasmer-it/src/interpreter/instructions/push.rs new file mode 100644 index 0000000..0281335 --- /dev/null +++ b/wasmer-it/src/interpreter/instructions/push.rs @@ -0,0 +1,25 @@ +use crate::IValue; + +executable_instruction!( + push_i32(value: i32) -> _ { + move |runtime| -> _ { + + log::trace!("push_i32: push {} on the stack", value); + runtime.stack.push(IValue::I32(value)); + + Ok(()) + } + } +); + +executable_instruction!( + push_i64(value: i64) -> _ { + move |runtime| -> _ { + + log::trace!("push_i32: push {} on the stack", value); + runtime.stack.push(IValue::I64(value)); + + Ok(()) + } + } +); diff --git a/wasmer-it/src/interpreter/instructions/records/lift_record.rs b/wasmer-it/src/interpreter/instructions/records/lift_record.rs index 0ecc24b..b52ab43 100644 --- a/wasmer-it/src/interpreter/instructions/records/lift_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lift_record.rs @@ -9,7 +9,6 @@ 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( li_helper: &LiHelper<'_>, record_type: &IRecordType, @@ -38,8 +37,10 @@ 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(&li_helper, &seq_reader, &**ty)?), - IType::Record(record_type_id) => values.push(read_record(li_helper, &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)?) + } } } diff --git a/wasmer-it/src/interpreter/mod.rs b/wasmer-it/src/interpreter/mod.rs index 868f76f..659c71a 100644 --- a/wasmer-it/src/interpreter/mod.rs +++ b/wasmer-it/src/interpreter/mod.rs @@ -233,6 +233,8 @@ where Instruction::I64FromU16 => instructions::i64_from_u16(instruction), Instruction::I64FromU32 => instructions::i64_from_u32(instruction), Instruction::I64FromU64 => instructions::i64_from_u64(instruction), + Instruction::PushI32 { value } => instructions::push_i32(value), + Instruction::PushI64 { value } => instructions::push_i64(value), Instruction::StringLiftMemory => instructions::string_lift_memory(instruction), Instruction::StringLowerMemory => instructions::string_lower_memory(instruction), From d7d91a263e8dc356e3faed45f5b301b1b1063024 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 22 Apr 2021 20:31:14 +0300 Subject: [PATCH 13/27] add some logs --- Cargo.lock | 1 + crates/it-lilo-utils/Cargo.toml | 1 + crates/it-lilo-utils/src/memory_writer.rs | 1 + wasmer-it/src/interpreter/instructions/arrays.rs | 3 +++ wasmer-it/src/interpreter/instructions/arrays/lift_array.rs | 1 + wasmer-it/src/interpreter/instructions/arrays/lower_array.rs | 4 ++++ 6 files changed, 11 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index f43133d..4d73acc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,7 @@ name = "it-lilo-utils" version = "0.1.0" dependencies = [ "fluence-it-types", + "log", "paste", "thiserror", ] diff --git a/crates/it-lilo-utils/Cargo.toml b/crates/it-lilo-utils/Cargo.toml index 32da557..05fe25e 100644 --- a/crates/it-lilo-utils/Cargo.toml +++ b/crates/it-lilo-utils/Cargo.toml @@ -15,3 +15,4 @@ fluence-it-types = { path = "../it-types/", version = "0.2.0" } paste = "1.0.5" thiserror = "1.0.24" +log = "0.4.14" diff --git a/crates/it-lilo-utils/src/memory_writer.rs b/crates/it-lilo-utils/src/memory_writer.rs index a616d1f..ceda3d4 100644 --- a/crates/it-lilo-utils/src/memory_writer.rs +++ b/crates/it-lilo-utils/src/memory_writer.rs @@ -122,6 +122,7 @@ impl<'w, 'm> SequentialWriter<'w, 'm> { // specialization of write_array for u8 pub fn write_u8(&self, value: u8) { let offset = self.offset.get(); + log::trace!("write_u8: write {} to {}", value, offset); self.writer.memory[offset].set(value); diff --git a/wasmer-it/src/interpreter/instructions/arrays.rs b/wasmer-it/src/interpreter/instructions/arrays.rs index 513f2a9..61e2589 100644 --- a/wasmer-it/src/interpreter/instructions/arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays.rs @@ -119,6 +119,7 @@ where })?; } + log::trace!("array.lower_memory: 1"); let memory_index = 0; let memory_view = instance .memory(memory_index) @@ -129,10 +130,12 @@ where ) })? .view(); + log::trace!("array.lower_memory: 1"); let memory = memory_view.deref(); let lo_helper = lilo::LoHelper::new(&**instance, memory) .map_err(|e| InstructionError::from_lilo(instruction.clone(), e))?; + log::trace!("array.lower_memory: 3"); let (offset, size) = array_lower_memory_impl(&lo_helper, values) .map_err(|e| InstructionError::from_lilo(instruction.clone(), e))?; diff --git a/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs index 23f513d..88239a8 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs @@ -43,6 +43,7 @@ pub(crate) fn array_lift_memory_impl( Ok(IValue::Array(ivalues)) } +// Vec => Vec (2 * len of prev) fn read_string_array( li_helper: &LiHelper, offset: usize, diff --git a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs index a27d867..db2a78d 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs @@ -9,6 +9,7 @@ pub(crate) fn array_lower_memory_impl( lo_helper: &LoHelper, array_values: Vec, ) -> LiLoResult<(usize, usize)> { + log::trace!("array_lower_memory_impl: 1"); if array_values.is_empty() { return Ok((0, 0)); } @@ -19,13 +20,16 @@ pub(crate) fn array_lower_memory_impl( size_to_allocate as _, type_tag_form_ivalue(&array_values[0]) as _, )?; + log::trace!("array_lower_memory_impl: 2"); let seq_writer = lo_helper .writer .sequential_writer(offset, size_to_allocate)?; + log::trace!("array_lower_memory_impl: 3"); // here it's known that all interface values have the same type for value in array_values { + log::trace!("array_lower_memory_impl: write {:?}", value); match value { IValue::Boolean(value) => seq_writer.write_u8(value as _), IValue::S8(value) => seq_writer.write_u8(value as _), From c4c1e449d37429f1114e8cdf478ca5f59283b4bc Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 22 Apr 2021 20:35:11 +0300 Subject: [PATCH 14/27] add log --- crates/it-lilo-utils/src/memory_writer.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/it-lilo-utils/src/memory_writer.rs b/crates/it-lilo-utils/src/memory_writer.rs index ceda3d4..7f36978 100644 --- a/crates/it-lilo-utils/src/memory_writer.rs +++ b/crates/it-lilo-utils/src/memory_writer.rs @@ -111,6 +111,8 @@ impl<'w, 'm> SequentialWriter<'w, 'm> { pub fn write_array(&self, values: [u8; N]) { let offset = self.offset.get(); + log::trace!("write array: offset {} {:?}", offset, values); + self.writer.memory[offset..offset + N] .iter() .zip(values.iter()) From 9095389a5af6e5e334be898437cee5b13f5b4909 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 22 Apr 2021 20:43:27 +0300 Subject: [PATCH 15/27] more logs --- wasmer-it/src/interpreter/instructions/lilo/utils.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/wasmer-it/src/interpreter/instructions/lilo/utils.rs b/wasmer-it/src/interpreter/instructions/lilo/utils.rs index 0065aeb..7ac8fce 100644 --- a/wasmer-it/src/interpreter/instructions/lilo/utils.rs +++ b/wasmer-it/src/interpreter/instructions/lilo/utils.rs @@ -23,6 +23,7 @@ where Instance: wasm::structures::Instance, { let closure = move |size: usize, ty: usize| { + log::trace!("call allocate closure 1: {} {}", size, ty); let index = FunctionIndex::new(ALLOCATE_FUNC_INDEX as usize); let local_or_import = instance @@ -31,6 +32,8 @@ where function_index: ALLOCATE_FUNC_INDEX, })?; + log::trace!("call allocate closure 2"); + 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( @@ -40,14 +43,20 @@ where ) .map_err(|_| LiLoError::AllocateFuncIncompatibleSignature)?; + log::trace!("call allocate closure 3: {:?}", inputs); + let outcome = local_or_import .call(&inputs) .map_err(|_| LiLoError::AllocateCallFailed)?; + log::trace!("call allocate closure 4: {:?}", outcome); + if outcome.len() != 1 { return Err(LiLoError::AllocateFuncIncompatibleOutput); } + log::trace!("call allocate closure 5"); + match outcome[0] { IValue::I32(offset) => Ok(offset as _), _ => Err(LiLoError::AllocateFuncIncompatibleOutput), From 34bf8a196addf2e53b1edd4d7bdcc1139c08d5e6 Mon Sep 17 00:00:00 2001 From: vms Date: Fri, 23 Apr 2021 10:13:11 +0300 Subject: [PATCH 16/27] support u128 --- crates/it-lilo-utils/src/lib.rs | 28 ++-- crates/it-lilo-utils/src/macros.rs | 14 ++ crates/it-lilo-utils/src/memory_reader.rs | 2 + crates/it-types/src/impls/types.rs | 6 + crates/it-types/src/impls/values.rs | 10 +- crates/it-types/src/types.rs | 4 + crates/it-types/src/values.rs | 3 + wasmer-it/src/decoders/binary.rs | 4 + wasmer-it/src/decoders/wat.rs | 15 ++ wasmer-it/src/encoders/binary.rs | 4 + wasmer-it/src/encoders/wat.rs | 5 + .../src/interpreter/instructions/arrays.rs | 6 +- .../instructions/arrays/lift_array.rs | 1 + .../instructions/arrays/lower_array.rs | 1 + .../interpreter/instructions/byte_arrays.rs | 147 ++++++++++++++++++ wasmer-it/src/interpreter/instructions/mod.rs | 18 ++- .../src/interpreter/instructions/records.rs | 4 +- .../instructions/records/lift_record.rs | 1 + .../instructions/records/lower_record.rs | 1 + .../src/interpreter/instructions/strings.rs | 12 +- wasmer-it/src/interpreter/mod.rs | 9 ++ wasmer-it/src/serde/de.rs | 1 + 22 files changed, 264 insertions(+), 32 deletions(-) create mode 100644 wasmer-it/src/interpreter/instructions/byte_arrays.rs diff --git a/crates/it-lilo-utils/src/lib.rs b/crates/it-lilo-utils/src/lib.rs index 170b727..dc1801f 100644 --- a/crates/it-lilo-utils/src/lib.rs +++ b/crates/it-lilo-utils/src/lib.rs @@ -37,6 +37,7 @@ pub fn ser_type_size(ty: &IType) -> usize { // 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, + IType::U128 => 16, } } @@ -47,6 +48,7 @@ pub fn ser_value_size(value: &IValue) -> usize { IValue::S16(_) | IValue::U16(_) => 2, IValue::S32(_) | IValue::U32(_) | IValue::F32(_) | IValue::I32(_) => 4, IValue::S64(_) | IValue::U64(_) | IValue::F64(_) | IValue::I64(_) => 8, + IValue::U128(_) => 16, IValue::String(_) | IValue::ByteArray(_) | IValue::Array(_) => 2 * 4, IValue::Record(_) => 4, } @@ -70,12 +72,13 @@ pub fn type_tag_form_itype(itype: &IType) -> u32 { 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::U128 => 5, // u128 + IType::S8 => 6, // i8 + IType::S16 => 7, // i16 + IType::S32 | IType::I32 => 8, // i32 + IType::S64 | IType::I64 => 9, // i64 + IType::F32 => 10, // f32 + IType::F64 => 11, // f64 IType::ByteArray | IType::Array(_) | IType::Record(_) | IType::String => POINTER_CODE, } } @@ -89,12 +92,13 @@ pub fn type_tag_form_ivalue(itype: &IValue) -> u32 { 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::U128(_) => 5, // u128 + IValue::S8(_) => 6, // i8 + IValue::S16(_) => 7, // i16 + IValue::S32(_) | IValue::I32(_) => 8, // i32 + IValue::S64(_) | IValue::I64(_) => 9, // i64 + IValue::F32(_) => 10, // f32 + IValue::F64(_) => 11, // f64 IValue::ByteArray(_) | IValue::Array(_) | IValue::Record(_) | IValue::String(_) => { POINTER_CODE } diff --git a/crates/it-lilo-utils/src/macros.rs b/crates/it-lilo-utils/src/macros.rs index dfb0d14..41889db 100644 --- a/crates/it-lilo-utils/src/macros.rs +++ b/crates/it-lilo-utils/src/macros.rs @@ -35,6 +35,10 @@ macro_rules! value_der { ($self:expr, $offset:expr, 8) => { crate::value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7 @seq_end); }; + + ($self:expr, $offset:expr, 16) => { + crate::value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 @seq_end); + }; } #[macro_export] @@ -78,6 +82,16 @@ macro_rules! read_ty { result } }; + + ($func_name:ident, $ty:ty, 16) => { + pub fn $func_name(&self) -> $ty { + let offset = self.offset.get(); + let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 16)); + + self.offset.set(offset + 16); + result + } + }; } #[macro_export] diff --git a/crates/it-lilo-utils/src/memory_reader.rs b/crates/it-lilo-utils/src/memory_reader.rs index 5065ee2..d567137 100644 --- a/crates/it-lilo-utils/src/memory_reader.rs +++ b/crates/it-lilo-utils/src/memory_reader.rs @@ -103,6 +103,7 @@ impl<'m> MemoryReader<'m> { read_array_ty!(read_s64_array, i64, S64); read_array_ty!(read_i64_array, i64, I64); read_array_ty!(read_f64_array, f64, F64); + read_array_ty!(read_u128_array, u128, U128); } impl<'r, 'm> SequentialReader<'r, 'm> { @@ -129,4 +130,5 @@ impl<'r, 'm> SequentialReader<'r, 'm> { read_ty!(read_u64, u64, 8); read_ty!(read_i64, i64, 8); read_ty!(read_f64, f64, 8); + read_ty!(read_u128, u128, 16); } diff --git a/crates/it-types/src/impls/types.rs b/crates/it-types/src/impls/types.rs index afc9b86..310bf8a 100644 --- a/crates/it-types/src/impls/types.rs +++ b/crates/it-types/src/impls/types.rs @@ -29,6 +29,7 @@ where IType::U64 => 0x07_u8.to_bytes(writer), IType::F32 => 0x08_u8.to_bytes(writer), IType::F64 => 0x09_u8.to_bytes(writer), + IType::U128 => 0x46_u8.to_bytes(writer), IType::String => 0x0a_u8.to_bytes(writer), IType::ByteArray => 0x3C_u8.to_bytes(writer), IType::Array(ty) => { @@ -87,6 +88,7 @@ mod keyword { custom_keyword!(u16); custom_keyword!(u32); custom_keyword!(u64); + custom_keyword!(u128); custom_keyword!(string); custom_keyword!(array); } @@ -138,6 +140,10 @@ impl Parse<'_> for IType { parser.parse::()?; Ok(IType::F64) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(IType::U128) } else if lookahead.peek::() { parser.parse::()?; diff --git a/crates/it-types/src/impls/values.rs b/crates/it-types/src/impls/values.rs index 3d99b2e..3d2c12e 100644 --- a/crates/it-types/src/impls/values.rs +++ b/crates/it-types/src/impls/values.rs @@ -22,14 +22,14 @@ macro_rules! native { } } - impl TryFrom<&IValue> for $native_type { + impl TryFrom for $native_type { type Error = WasmValueNativeCastError; - fn try_from(w: &IValue) -> Result { + fn try_from(w: IValue) -> Result { match w { - IValue::$variant(n) => Ok(n.clone()), + IValue::$variant(n) => Ok(n), _ => Err(WasmValueNativeCastError { - from: w.clone(), + from: w, to: <$native_type>::INTERFACE_TYPE, }), } @@ -48,4 +48,6 @@ native!(u32, U32); native!(u64, U64); native!(f32, F32); native!(f64, F64); +native!(u128, U128); native!(String, String); +native!(Vec, ByteArray); diff --git a/crates/it-types/src/types.rs b/crates/it-types/src/types.rs index 362cd6f..a6ceae0 100644 --- a/crates/it-types/src/types.rs +++ b/crates/it-types/src/types.rs @@ -41,6 +41,9 @@ pub enum IType { /// A 64-bits float. F64, + /// A 128-bit unsigned integer. + U128, + /// A string. String, @@ -112,6 +115,7 @@ impl ToString for &IType { IType::U64 => "u64".to_string(), IType::F32 => "f32".to_string(), IType::F64 => "f64".to_string(), + IType::U128 => "u128".to_string(), IType::String => "string".to_string(), IType::ByteArray => "array (u8)".to_string(), IType::Array(ty) => format!("array ({})", ty.as_ref().to_string()), diff --git a/crates/it-types/src/values.rs b/crates/it-types/src/values.rs index 2e0a237..de743bd 100644 --- a/crates/it-types/src/values.rs +++ b/crates/it-types/src/values.rs @@ -38,6 +38,9 @@ pub enum IValue { /// A 64-bits float. F64(f64), + /// A 128-bits integer. + U128(u128), + /// A string. String(String), diff --git a/wasmer-it/src/decoders/binary.rs b/wasmer-it/src/decoders/binary.rs index ea24b01..fd42b4d 100644 --- a/wasmer-it/src/decoders/binary.rs +++ b/wasmer-it/src/decoders/binary.rs @@ -298,6 +298,10 @@ fn instruction<'input, E: ParseError<&'input [u8]>>( 0x23 => (input, Instruction::StringLowerMemory), 0x24 => (input, Instruction::StringSize), + 0x43 => (input, Instruction::ByteArrayLiftMemory), + 0x44 => (input, Instruction::ByteArrayLowerMemory), + 0x45 => (input, Instruction::ByteArraySize), + 0x37 => { consume!((input, value_type) = ty(input)?); diff --git a/wasmer-it/src/decoders/wat.rs b/wasmer-it/src/decoders/wat.rs index 577ffa4..b8efa3f 100644 --- a/wasmer-it/src/decoders/wat.rs +++ b/wasmer-it/src/decoders/wat.rs @@ -80,6 +80,9 @@ mod keyword { custom_keyword!(string_lift_memory = "string.lift_memory"); custom_keyword!(string_lower_memory = "string.lower_memory"); custom_keyword!(string_size = "string.size"); + custom_keyword!(byte_array_lift_memory = "byte_array.lift_memory"); + custom_keyword!(byte_array_lower_memory = "byte_array.lower_memory"); + custom_keyword!(byte_array_size = "byte_array.size"); custom_keyword!(array_lift_memory = "array.lift_memory"); custom_keyword!(array_lower_memory = "array.lower_memory"); custom_keyword!(array_size = "array.size"); @@ -260,6 +263,18 @@ impl<'a> Parse<'a> for Instruction { } else if lookahead.peek::() { parser.parse::()?; + Ok(Instruction::StringSize) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::StringLiftMemory) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::StringLowerMemory) + } else if lookahead.peek::() { + parser.parse::()?; + Ok(Instruction::StringSize) } else if lookahead.peek::() { parser.parse::()?; diff --git a/wasmer-it/src/encoders/binary.rs b/wasmer-it/src/encoders/binary.rs index ae64052..f86e9c8 100644 --- a/wasmer-it/src/encoders/binary.rs +++ b/wasmer-it/src/encoders/binary.rs @@ -235,6 +235,10 @@ where Instruction::StringLowerMemory => 0x23_u8.to_bytes(writer)?, Instruction::StringSize => 0x24_u8.to_bytes(writer)?, + Instruction::ByteArrayLiftMemory => 0x43_u8.to_bytes(writer)?, + Instruction::ByteArrayLowerMemory => 0x44_u8.to_bytes(writer)?, + Instruction::ByteArraySize => 0x45_u8.to_bytes(writer)?, + Instruction::ArrayLiftMemory { value_type } => { 0x37_u8.to_bytes(writer)?; value_type.to_bytes(writer)? diff --git a/wasmer-it/src/encoders/wat.rs b/wasmer-it/src/encoders/wat.rs index a11c6de..647a3e9 100644 --- a/wasmer-it/src/encoders/wat.rs +++ b/wasmer-it/src/encoders/wat.rs @@ -102,6 +102,11 @@ impl ToString for &Instruction { Instruction::StringLiftMemory => "string.lift_memory".into(), Instruction::StringLowerMemory => "string.lower_memory".into(), Instruction::StringSize => "string.size".into(), + + Instruction::ByteArrayLiftMemory => "byte_array.lift_memory".into(), + Instruction::ByteArrayLowerMemory => "byte_array.lower_memory".into(), + Instruction::ByteArraySize => "byte_array.size".into(), + Instruction::ArrayLiftMemory { value_type } => { format!("array.lift_memory {}", value_type.to_string()) } diff --git a/wasmer-it/src/interpreter/instructions/arrays.rs b/wasmer-it/src/interpreter/instructions/arrays.rs index 61e2589..ea885e9 100644 --- a/wasmer-it/src/interpreter/instructions/arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays.rs @@ -33,19 +33,19 @@ where use crate::interpreter::stack::Stackable; Box::new({ move |runtime| -> _ { - let inputs = runtime.stack.pop(2).ok_or_else(|| { + let mut inputs = runtime.stack.pop(2).ok_or_else(|| { InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, ) })?; - let offset: usize = to_native::(&inputs[0], instruction.clone())? + let offset: usize = to_native::(inputs.remove(0), instruction.clone())? .try_into() .map_err(|e| (e, "offset").into()) .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; - let size: usize = to_native::(&inputs[1], instruction.clone())? + let size: usize = to_native::(inputs.remove(0), instruction.clone())? .try_into() .map_err(|e| (e, "size").into()) .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; diff --git a/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs index 88239a8..15db5d4 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs @@ -30,6 +30,7 @@ pub(crate) fn array_lift_memory_impl( 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::U128 => reader.read_u128_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)?, diff --git a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs index db2a78d..2f07af4 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs @@ -40,6 +40,7 @@ pub(crate) fn array_lower_memory_impl( 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::U128(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()), diff --git a/wasmer-it/src/interpreter/instructions/byte_arrays.rs b/wasmer-it/src/interpreter/instructions/byte_arrays.rs new file mode 100644 index 0000000..fc0566d --- /dev/null +++ b/wasmer-it/src/interpreter/instructions/byte_arrays.rs @@ -0,0 +1,147 @@ +use super::to_native; +use crate::instr_error; +use crate::IType; +use crate::IValue; +use crate::{ + errors::{InstructionError, InstructionErrorKind}, + interpreter::Instruction, +}; + +use std::{cell::Cell, convert::TryInto}; + +executable_instruction!( + byte_array_lift_memory(instruction: Instruction) -> _ { + move |runtime| -> _ { + let mut inputs = runtime.stack.pop(2).ok_or_else(|| { + InstructionError::from_error_kind( + instruction.clone(), + InstructionErrorKind::StackIsTooSmall { needed: 2 }, + ) + })?; + + let memory_index = 0; + let memory = runtime + .wasm_instance + .memory(memory_index) + .ok_or_else(|| { + InstructionError::from_error_kind( + instruction.clone(), + InstructionErrorKind::MemoryIsMissing { memory_index }, + ) + })?; + + let pointer: usize = to_native::(inputs.remove(0), instruction.clone())? + .try_into() + .map_err(|e| (e, "pointer").into()) + .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; + let length: usize = to_native::(inputs.remove(0), instruction.clone())? + .try_into() + .map_err(|e| (e, "length").into()) + .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; + let memory_view = memory.view(); + + if length == 0 { + runtime.stack.push(IValue::String("".into())); + + return Ok(()) + } + + if memory_view.len() < pointer + length { + return instr_error!( + instruction.clone(), + InstructionErrorKind::MemoryOutOfBoundsAccess { + index: pointer + length, + length: memory_view.len(), + } + ); + } + + let data: Vec = (&memory_view[pointer..pointer + length]) + .iter() + .map(Cell::get) + .collect(); + + log::debug!("byte_array.lift_memory: pushing {:?} on the stack", data); + runtime.stack.push(IValue::ByteArray(data)); + + Ok(()) + } + } +); + +executable_instruction!( + byte_array_lower_memory(instruction: Instruction) -> _ { + move |runtime| -> _ { + let mut inputs = runtime.stack.pop(2).ok_or_else(|| { + InstructionError::from_error_kind( + instruction.clone(), + InstructionErrorKind::StackIsTooSmall { needed: 2 }, + ) + })?; + + let array_pointer: usize = to_native::(inputs.remove(0), instruction.clone())? + .try_into() + .map_err(|e| (e, "pointer").into()) + .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; + let array: Vec = to_native(inputs.remove(0), instruction.clone())?; + let length: i32 = array.len().try_into().map_err(|_| { + InstructionError::from_error_kind( + instruction.clone(), + InstructionErrorKind::NegativeValue { subject: "array_length" }, + ) + })?; + + let instance = &mut runtime.wasm_instance; + 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(); + + for (nth, byte) in array.iter().enumerate() { + memory_view[array_pointer as usize + nth].set(*byte); + } + + log::debug!("string.lower_memory: pushing {}, {} on the stack", array_pointer, length); + runtime.stack.push(IValue::I32(array_pointer as i32)); + runtime.stack.push(IValue::I32(length)); + + Ok(()) + } + } +); + +executable_instruction!( + byte_array_size(instruction: Instruction) -> _ { + move |runtime| -> _ { + match runtime.stack.pop1() { + Some(IValue::ByteArray(array)) => { + let length = array.len() as i32; + + log::debug!("byte_array.size: pushing {} on the stack", length); + runtime.stack.push(IValue::I32(length)); + + Ok(()) + }, + + Some(value) => instr_error!( + instruction.clone(), + InstructionErrorKind::InvalidValueOnTheStack { + expected_type: IType::String, + received_value: (&value).clone(), + } + ), + + None => instr_error!( + instruction.clone(), + InstructionErrorKind::StackIsTooSmall { needed: 1 } + ), + } + } + } +); diff --git a/wasmer-it/src/interpreter/instructions/mod.rs b/wasmer-it/src/interpreter/instructions/mod.rs index fdf64da..b396f7f 100644 --- a/wasmer-it/src/interpreter/instructions/mod.rs +++ b/wasmer-it/src/interpreter/instructions/mod.rs @@ -1,5 +1,6 @@ mod argument_get; mod arrays; +mod byte_arrays; mod call_core; mod dup; pub(self) mod lilo; @@ -19,6 +20,7 @@ use crate::NEVec; pub(crate) use argument_get::argument_get; pub(crate) use arrays::*; +pub(crate) use byte_arrays::*; pub(crate) use call_core::call_core; pub(crate) use dup::dup; pub(crate) use numbers::*; @@ -158,6 +160,15 @@ pub enum Instruction { /// The `string.lower_memory` instruction. StringLowerMemory, + /// The `byte_array.size` instruction. + ByteArraySize, + + /// The `byte_array.lift_memory` instruction. + ByteArrayLiftMemory, + + /// The `byte_array.lower_memory` instruction. + ByteArrayLowerMemory, + /// The `string.size` instruction. StringSize, @@ -206,12 +217,9 @@ pub enum Instruction { /// Just a short helper to map the error of a cast from an /// `IValue` to a native value. -pub(crate) fn to_native<'a, T>( - wit_value: &'a IValue, - instruction: Instruction, -) -> InstructionResult +pub(crate) fn to_native<'a, T>(wit_value: IValue, instruction: Instruction) -> InstructionResult where - T: NativeType + TryFrom<&'a IValue, Error = WasmValueNativeCastError>, + T: NativeType + TryFrom, { T::try_from(wit_value).map_err(|error| { InstructionError::from_error_kind(instruction, InstructionErrorKind::ToNative(error)) diff --git a/wasmer-it/src/interpreter/instructions/records.rs b/wasmer-it/src/interpreter/instructions/records.rs index a0a3c00..dfc68bb 100644 --- a/wasmer-it/src/interpreter/instructions/records.rs +++ b/wasmer-it/src/interpreter/instructions/records.rs @@ -32,14 +32,14 @@ where use crate::interpreter::stack::Stackable; Box::new({ move |runtime| -> _ { - let inputs = runtime.stack.pop(1).ok_or_else(|| { + let mut inputs = runtime.stack.pop(1).ok_or_else(|| { InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, ) })?; - let offset: usize = to_native::(&inputs[0], instruction.clone())? + let offset: usize = to_native::(inputs.remove(0), instruction.clone())? .try_into() .map_err(|e| (e, "offset").into()) .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; diff --git a/wasmer-it/src/interpreter/instructions/records/lift_record.rs b/wasmer-it/src/interpreter/instructions/records/lift_record.rs index b52ab43..6e6429e 100644 --- a/wasmer-it/src/interpreter/instructions/records/lift_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lift_record.rs @@ -33,6 +33,7 @@ pub(crate) fn record_lift_memory_impl( IType::U16 => values.push(IValue::U16(seq_reader.read_u16())), IType::U32 => values.push(IValue::U32(seq_reader.read_u32())), IType::U64 => values.push(IValue::U64(seq_reader.read_u64())), + IType::U128 => values.push(IValue::U128(seq_reader.read_u128())), IType::F32 => values.push(IValue::F32(seq_reader.read_f32())), IType::F64 => values.push(IValue::F64(seq_reader.read_f64())), IType::String => values.push(IValue::String(read_string(reader, &seq_reader)?)), diff --git a/wasmer-it/src/interpreter/instructions/records/lower_record.rs b/wasmer-it/src/interpreter/instructions/records/lower_record.rs index f32e1d6..616e777 100644 --- a/wasmer-it/src/interpreter/instructions/records/lower_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lower_record.rs @@ -21,6 +21,7 @@ pub(crate) fn record_lower_memory_impl( IValue::U16(value) => result.extend_from_slice(&value.to_le_bytes()), IValue::U32(value) => result.extend_from_slice(&value.to_le_bytes()), IValue::U64(value) => result.extend_from_slice(&value.to_le_bytes()), + IValue::U128(value) => result.extend_from_slice(&value.to_le_bytes()), IValue::I32(value) => result.extend_from_slice(&value.to_le_bytes()), IValue::I64(value) => result.extend_from_slice(&value.to_le_bytes()), IValue::F32(value) => result.extend_from_slice(&value.to_le_bytes()), diff --git a/wasmer-it/src/interpreter/instructions/strings.rs b/wasmer-it/src/interpreter/instructions/strings.rs index 1805be0..5d395ad 100644 --- a/wasmer-it/src/interpreter/instructions/strings.rs +++ b/wasmer-it/src/interpreter/instructions/strings.rs @@ -12,7 +12,7 @@ use std::{cell::Cell, convert::TryInto}; executable_instruction!( string_lift_memory(instruction: Instruction) -> _ { move |runtime| -> _ { - let inputs = runtime.stack.pop(2).ok_or_else(|| { + let mut inputs = runtime.stack.pop(2).ok_or_else(|| { InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 2 }, @@ -30,11 +30,11 @@ executable_instruction!( ) })?; - let pointer: usize = to_native::(&inputs[0], instruction.clone())? + let pointer: usize = to_native::(inputs.remove(0), instruction.clone())? .try_into() .map_err(|e| (e, "pointer").into()) .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; - let length: usize = to_native::(&inputs[1], instruction.clone())? + let length: usize = to_native::(inputs.remove(0), instruction.clone())? .try_into() .map_err(|e| (e, "length").into()) .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; @@ -75,18 +75,18 @@ executable_instruction!( executable_instruction!( string_lower_memory(instruction: Instruction) -> _ { move |runtime| -> _ { - let inputs = runtime.stack.pop(2).ok_or_else(|| { + let mut inputs = runtime.stack.pop(2).ok_or_else(|| { InstructionError::from_error_kind( instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 2 }, ) })?; - let string_pointer: usize = to_native::(&inputs[0], instruction.clone())? + let string_pointer: usize = to_native::(inputs.remove(0), instruction.clone())? .try_into() .map_err(|e| (e, "pointer").into()) .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; - let string: String = to_native(&inputs[1], instruction.clone())?; + let string: String = to_native(inputs.remove(0), instruction.clone())?; let string_bytes = string.as_bytes(); let string_length: i32 = string_bytes.len().try_into().map_err(|_| { InstructionError::from_error_kind( diff --git a/wasmer-it/src/interpreter/mod.rs b/wasmer-it/src/interpreter/mod.rs index 659c71a..4fbcbdb 100644 --- a/wasmer-it/src/interpreter/mod.rs +++ b/wasmer-it/src/interpreter/mod.rs @@ -239,6 +239,15 @@ where Instruction::StringLiftMemory => instructions::string_lift_memory(instruction), Instruction::StringLowerMemory => instructions::string_lower_memory(instruction), Instruction::StringSize => instructions::string_size(instruction), + + Instruction::ByteArrayLiftMemory => { + instructions::byte_array_lift_memory(instruction) + } + Instruction::ByteArrayLowerMemory => { + instructions::byte_array_lower_memory(instruction) + } + Instruction::ByteArraySize => instructions::byte_array_size(instruction), + Instruction::ArrayLiftMemory { ref value_type } => { let value_type = value_type.clone(); instructions::array_lift_memory(instruction, value_type) diff --git a/wasmer-it/src/serde/de.rs b/wasmer-it/src/serde/de.rs index 0527523..ff23894 100644 --- a/wasmer-it/src/serde/de.rs +++ b/wasmer-it/src/serde/de.rs @@ -215,6 +215,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { Some(IValue::U16(_)) => self.deserialize_u16(visitor), Some(IValue::U32(_)) => self.deserialize_u32(visitor), Some(IValue::U64(_)) => self.deserialize_u64(visitor), + Some(IValue::U128(_)) => self.deserialize_u64(visitor), Some(IValue::F32(_)) => self.deserialize_f32(visitor), Some(IValue::F64(_)) => self.deserialize_f64(visitor), Some(IValue::String(_)) => self.deserialize_string(visitor), From 5df263876fb5645674228cbbdd6288b33d361d8e Mon Sep 17 00:00:00 2001 From: folex <0xdxdy@gmail.com> Date: Fri, 23 Apr 2021 18:04:08 +0300 Subject: [PATCH 17/27] remove u128 (#11) --- crates/it-lilo-utils/src/lib.rs | 4 ---- crates/it-lilo-utils/src/memory_reader.rs | 2 -- crates/it-types/src/impls/types.rs | 6 ------ crates/it-types/src/impls/values.rs | 1 - crates/it-types/src/types.rs | 4 ---- crates/it-types/src/values.rs | 5 +---- wasmer-it/src/interpreter/instructions/arrays/lift_array.rs | 1 - .../src/interpreter/instructions/arrays/lower_array.rs | 1 - .../src/interpreter/instructions/records/lift_record.rs | 1 - .../src/interpreter/instructions/records/lower_record.rs | 1 - wasmer-it/src/serde/de.rs | 1 - 11 files changed, 1 insertion(+), 26 deletions(-) diff --git a/crates/it-lilo-utils/src/lib.rs b/crates/it-lilo-utils/src/lib.rs index dc1801f..c52d71a 100644 --- a/crates/it-lilo-utils/src/lib.rs +++ b/crates/it-lilo-utils/src/lib.rs @@ -37,7 +37,6 @@ pub fn ser_type_size(ty: &IType) -> usize { // 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, - IType::U128 => 16, } } @@ -48,7 +47,6 @@ pub fn ser_value_size(value: &IValue) -> usize { IValue::S16(_) | IValue::U16(_) => 2, IValue::S32(_) | IValue::U32(_) | IValue::F32(_) | IValue::I32(_) => 4, IValue::S64(_) | IValue::U64(_) | IValue::F64(_) | IValue::I64(_) => 8, - IValue::U128(_) => 16, IValue::String(_) | IValue::ByteArray(_) | IValue::Array(_) => 2 * 4, IValue::Record(_) => 4, } @@ -72,7 +70,6 @@ pub fn type_tag_form_itype(itype: &IType) -> u32 { IType::U16 => 2, // u16 IType::U32 => 3, // u32 IType::U64 => 4, // u64 - IType::U128 => 5, // u128 IType::S8 => 6, // i8 IType::S16 => 7, // i16 IType::S32 | IType::I32 => 8, // i32 @@ -92,7 +89,6 @@ pub fn type_tag_form_ivalue(itype: &IValue) -> u32 { IValue::U16(_) => 2, // u16 IValue::U32(_) => 3, // u32 IValue::U64(_) => 4, // u64 - IValue::U128(_) => 5, // u128 IValue::S8(_) => 6, // i8 IValue::S16(_) => 7, // i16 IValue::S32(_) | IValue::I32(_) => 8, // i32 diff --git a/crates/it-lilo-utils/src/memory_reader.rs b/crates/it-lilo-utils/src/memory_reader.rs index d567137..5065ee2 100644 --- a/crates/it-lilo-utils/src/memory_reader.rs +++ b/crates/it-lilo-utils/src/memory_reader.rs @@ -103,7 +103,6 @@ impl<'m> MemoryReader<'m> { read_array_ty!(read_s64_array, i64, S64); read_array_ty!(read_i64_array, i64, I64); read_array_ty!(read_f64_array, f64, F64); - read_array_ty!(read_u128_array, u128, U128); } impl<'r, 'm> SequentialReader<'r, 'm> { @@ -130,5 +129,4 @@ impl<'r, 'm> SequentialReader<'r, 'm> { read_ty!(read_u64, u64, 8); read_ty!(read_i64, i64, 8); read_ty!(read_f64, f64, 8); - read_ty!(read_u128, u128, 16); } diff --git a/crates/it-types/src/impls/types.rs b/crates/it-types/src/impls/types.rs index 310bf8a..afc9b86 100644 --- a/crates/it-types/src/impls/types.rs +++ b/crates/it-types/src/impls/types.rs @@ -29,7 +29,6 @@ where IType::U64 => 0x07_u8.to_bytes(writer), IType::F32 => 0x08_u8.to_bytes(writer), IType::F64 => 0x09_u8.to_bytes(writer), - IType::U128 => 0x46_u8.to_bytes(writer), IType::String => 0x0a_u8.to_bytes(writer), IType::ByteArray => 0x3C_u8.to_bytes(writer), IType::Array(ty) => { @@ -88,7 +87,6 @@ mod keyword { custom_keyword!(u16); custom_keyword!(u32); custom_keyword!(u64); - custom_keyword!(u128); custom_keyword!(string); custom_keyword!(array); } @@ -140,10 +138,6 @@ impl Parse<'_> for IType { parser.parse::()?; Ok(IType::F64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(IType::U128) } else if lookahead.peek::() { parser.parse::()?; diff --git a/crates/it-types/src/impls/values.rs b/crates/it-types/src/impls/values.rs index 3d2c12e..b872fa2 100644 --- a/crates/it-types/src/impls/values.rs +++ b/crates/it-types/src/impls/values.rs @@ -48,6 +48,5 @@ native!(u32, U32); native!(u64, U64); native!(f32, F32); native!(f64, F64); -native!(u128, U128); native!(String, String); native!(Vec, ByteArray); diff --git a/crates/it-types/src/types.rs b/crates/it-types/src/types.rs index a6ceae0..362cd6f 100644 --- a/crates/it-types/src/types.rs +++ b/crates/it-types/src/types.rs @@ -41,9 +41,6 @@ pub enum IType { /// A 64-bits float. F64, - /// A 128-bit unsigned integer. - U128, - /// A string. String, @@ -115,7 +112,6 @@ impl ToString for &IType { IType::U64 => "u64".to_string(), IType::F32 => "f32".to_string(), IType::F64 => "f64".to_string(), - IType::U128 => "u128".to_string(), IType::String => "string".to_string(), IType::ByteArray => "array (u8)".to_string(), IType::Array(ty) => format!("array ({})", ty.as_ref().to_string()), diff --git a/crates/it-types/src/values.rs b/crates/it-types/src/values.rs index de743bd..b3a8f3a 100644 --- a/crates/it-types/src/values.rs +++ b/crates/it-types/src/values.rs @@ -37,10 +37,7 @@ pub enum IValue { /// A 64-bits float. F64(f64), - - /// A 128-bits integer. - U128(u128), - + /// A string. String(String), diff --git a/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs index 15db5d4..88239a8 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs @@ -30,7 +30,6 @@ pub(crate) fn array_lift_memory_impl( 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::U128 => reader.read_u128_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)?, diff --git a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs index 2f07af4..db2a78d 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs @@ -40,7 +40,6 @@ pub(crate) fn array_lower_memory_impl( 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::U128(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()), diff --git a/wasmer-it/src/interpreter/instructions/records/lift_record.rs b/wasmer-it/src/interpreter/instructions/records/lift_record.rs index 6e6429e..b52ab43 100644 --- a/wasmer-it/src/interpreter/instructions/records/lift_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lift_record.rs @@ -33,7 +33,6 @@ pub(crate) fn record_lift_memory_impl( IType::U16 => values.push(IValue::U16(seq_reader.read_u16())), IType::U32 => values.push(IValue::U32(seq_reader.read_u32())), IType::U64 => values.push(IValue::U64(seq_reader.read_u64())), - IType::U128 => values.push(IValue::U128(seq_reader.read_u128())), IType::F32 => values.push(IValue::F32(seq_reader.read_f32())), IType::F64 => values.push(IValue::F64(seq_reader.read_f64())), IType::String => values.push(IValue::String(read_string(reader, &seq_reader)?)), diff --git a/wasmer-it/src/interpreter/instructions/records/lower_record.rs b/wasmer-it/src/interpreter/instructions/records/lower_record.rs index 616e777..f32e1d6 100644 --- a/wasmer-it/src/interpreter/instructions/records/lower_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lower_record.rs @@ -21,7 +21,6 @@ pub(crate) fn record_lower_memory_impl( IValue::U16(value) => result.extend_from_slice(&value.to_le_bytes()), IValue::U32(value) => result.extend_from_slice(&value.to_le_bytes()), IValue::U64(value) => result.extend_from_slice(&value.to_le_bytes()), - IValue::U128(value) => result.extend_from_slice(&value.to_le_bytes()), IValue::I32(value) => result.extend_from_slice(&value.to_le_bytes()), IValue::I64(value) => result.extend_from_slice(&value.to_le_bytes()), IValue::F32(value) => result.extend_from_slice(&value.to_le_bytes()), diff --git a/wasmer-it/src/serde/de.rs b/wasmer-it/src/serde/de.rs index ff23894..0527523 100644 --- a/wasmer-it/src/serde/de.rs +++ b/wasmer-it/src/serde/de.rs @@ -215,7 +215,6 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { Some(IValue::U16(_)) => self.deserialize_u16(visitor), Some(IValue::U32(_)) => self.deserialize_u32(visitor), Some(IValue::U64(_)) => self.deserialize_u64(visitor), - Some(IValue::U128(_)) => self.deserialize_u64(visitor), Some(IValue::F32(_)) => self.deserialize_f32(visitor), Some(IValue::F64(_)) => self.deserialize_f64(visitor), Some(IValue::String(_)) => self.deserialize_string(visitor), From 6bf0eedec7d40d21884eb7a5b9c9d20f3812d531 Mon Sep 17 00:00:00 2001 From: vms Date: Fri, 23 Apr 2021 23:56:41 +0300 Subject: [PATCH 18/27] first attempt to fix --- crates/it-lilo-utils/src/error.rs | 35 ++++ crates/it-lilo-utils/src/lib.rs | 5 +- crates/it-lilo-utils/src/macros.rs | 2 +- crates/it-lilo-utils/src/memory_reader.rs | 10 +- crates/it-lilo-utils/src/memory_writer.rs | 154 ++++++++---------- crates/it-types/src/impls/values.rs | 44 ++++- wasmer-it/src/errors.rs | 13 ++ .../src/interpreter/instructions/arrays.rs | 24 +-- .../instructions/arrays/lower_array.rs | 81 ++++----- .../interpreter/instructions/byte_arrays.rs | 33 +++- .../instructions/lilo/li_helper.rs | 29 +++- .../instructions/lilo/lo_helper.rs | 122 ++++++++++---- .../src/interpreter/instructions/lilo/mod.rs | 5 - .../interpreter/instructions/lilo/utils.rs | 88 ---------- .../src/interpreter/instructions/records.rs | 23 +-- .../instructions/records/lower_record.rs | 21 +-- wasmer-it/src/interpreter/wasm/structures.rs | 5 + 17 files changed, 373 insertions(+), 321 deletions(-) delete mode 100644 wasmer-it/src/interpreter/instructions/lilo/utils.rs diff --git a/crates/it-lilo-utils/src/error.rs b/crates/it-lilo-utils/src/error.rs index 881fb57..fb7660f 100644 --- a/crates/it-lilo-utils/src/error.rs +++ b/crates/it-lilo-utils/src/error.rs @@ -27,3 +27,38 @@ pub enum MemoryAccessError { memory_size: usize, }, } + +#[derive(Debug, ThisError)] +pub enum MemoryWriteError { + /// The memory doesn't exist. + #[error("memory `{memory_index}` does not exist")] + MemoryIsMissing { + /// The memory index. + memory_index: usize, + }, + + /// The local or import function doesn't exist. + #[error("the allocate function with index `{function_index}` doesn't exist in Wasm module")] + AllocateFuncIsMissing { + /// The local or import function index. + function_index: u32, + }, + + /// Failed to call a allocate function. + #[error("call to allocated was failed")] + AllocateCallFailed, + + /// Allocate input types doesn't match with needed. + #[error( + "allocate func doesn't receive two i32 values,\ + probably a Wasm module's built with unsupported sdk version" + )] + AllocateFuncIncompatibleSignature, + + /// Allocate output types doesn't match with needed. + #[error( + "allocate func doesn't return a one value of I32 type,\ + probably a Wasm module's built with unsupported sdk version" + )] + AllocateFuncIncompatibleOutput, +} diff --git a/crates/it-lilo-utils/src/lib.rs b/crates/it-lilo-utils/src/lib.rs index dc1801f..6bb5d47 100644 --- a/crates/it-lilo-utils/src/lib.rs +++ b/crates/it-lilo-utils/src/lib.rs @@ -23,7 +23,8 @@ pub use fluence_it_types::IRecordType; pub use fluence_it_types::IType; pub use fluence_it_types::IValue; -pub type MResult = std::result::Result; +pub type ReadResult = std::result::Result; +pub type WriteResult = std::result::Result; /// Size of a value in a serialized view. pub fn ser_type_size(ty: &IType) -> usize { @@ -42,7 +43,7 @@ pub fn ser_type_size(ty: &IType) -> usize { } /// Size of a value in a serialized view. -pub fn ser_value_size(value: &IValue) -> usize { +pub fn ser_value_size(value: &IValue) -> u32 { match value { IValue::Boolean(_) | IValue::S8(_) | IValue::U8(_) => 1, IValue::S16(_) | IValue::U16(_) => 2, diff --git a/crates/it-lilo-utils/src/macros.rs b/crates/it-lilo-utils/src/macros.rs index 41889db..edd8c0e 100644 --- a/crates/it-lilo-utils/src/macros.rs +++ b/crates/it-lilo-utils/src/macros.rs @@ -101,7 +101,7 @@ macro_rules! read_array_ty { &self, offset: usize, elements_count: usize, - ) -> crate::MResult> { + ) -> crate::ReadResult> { let reader = self.sequential_reader(offset, std::mem::size_of::<$ty>() * elements_count)?; let mut result = Vec::with_capacity(elements_count); diff --git a/crates/it-lilo-utils/src/memory_reader.rs b/crates/it-lilo-utils/src/memory_reader.rs index d567137..3420b8c 100644 --- a/crates/it-lilo-utils/src/memory_reader.rs +++ b/crates/it-lilo-utils/src/memory_reader.rs @@ -18,7 +18,7 @@ use crate::error::MemoryAccessError; use crate::read_array_ty; use crate::read_ty; use crate::IValue; -use crate::MResult; +use crate::ReadResult; use std::cell::Cell; @@ -46,13 +46,13 @@ impl<'m> MemoryReader<'m> { &self, offset: usize, size: usize, - ) -> MResult> { + ) -> ReadResult> { self.check_access(offset, size)?; Ok(SequentialReader::new(&self, offset)) } - pub fn read_raw_u8_array(&self, offset: usize, elements_count: usize) -> MResult> { + pub fn read_raw_u8_array(&self, offset: usize, elements_count: usize) -> ReadResult> { let reader = self.sequential_reader(offset, elements_count)?; let mut result = Vec::with_capacity(elements_count); @@ -64,7 +64,7 @@ impl<'m> MemoryReader<'m> { Ok(result) } - pub fn read_bool_array(&self, offset: usize, elements_count: usize) -> MResult> { + pub fn read_bool_array(&self, offset: usize, elements_count: usize) -> ReadResult> { let reader = self.sequential_reader(offset, elements_count)?; let mut result = Vec::with_capacity(elements_count); @@ -76,7 +76,7 @@ impl<'m> MemoryReader<'m> { Ok(result) } - pub fn check_access(&self, offset: usize, size: usize) -> MResult<()> { + pub fn check_access(&self, offset: usize, size: usize) -> ReadResult<()> { let right = offset + size; // the first condition is a check for overflow diff --git a/crates/it-lilo-utils/src/memory_writer.rs b/crates/it-lilo-utils/src/memory_writer.rs index 7f36978..a3d6ff3 100644 --- a/crates/it-lilo-utils/src/memory_writer.rs +++ b/crates/it-lilo-utils/src/memory_writer.rs @@ -14,106 +14,78 @@ * limitations under the License. */ -use crate::error::MemoryAccessError; -use crate::MResult; - +use crate::WriteResult; use std::cell::Cell; -pub struct MemoryWriter<'m> { - memory: &'m [Cell], +pub type MemSlice<'m> = &'m [Cell]; + +const MEMORY_INDEX: usize = 0; + +pub trait Heapable { + fn allocate(&self, size: u32, type_tag: u32) -> WriteResult; + + fn memory_slice(&self, memory_index: usize) -> WriteResult>; } -/// Writes values of basic types sequentially to the provided writer. -/// It don't check memory limits for the optimization purposes, -/// so it could be created only by the MemoryReader::sequential_reader method. -pub struct SequentialWriter<'w, 'm> { - writer: &'w MemoryWriter<'m>, +pub struct MemoryWriter<'i, T: Heapable> { + heap_manager: &'i T, + pub(self) memory: Cell>, +} + +pub struct SequentialWriter { + start_offset: usize, offset: Cell, } -impl<'m> MemoryWriter<'m> { - pub fn new(memory: &'m [Cell]) -> Self { - Self { memory } +impl<'i, T: Heapable> MemoryWriter<'i, T> { + pub fn new(heap_manager: &'i T) -> WriteResult { + let mem_slice = heap_manager.memory_slice(MEMORY_INDEX)?; + let memory = Cell::new(mem_slice); + + let writer = Self { + heap_manager, + memory, + }; + Ok(writer) } - pub fn write_array(&self, offset: usize, values: [u8; N]) -> MResult<()> { - self.check_access(offset, values.len())?; + pub fn write_bytes(&self, bytes: &[u8]) -> WriteResult { + let byte_type_tag = crate::type_tag_form_itype(&crate::IType::U8); + let seq_writer = self.sequential_writer(bytes.len() as _, byte_type_tag)?; + seq_writer.write_bytes(self, bytes); - self.memory[offset..offset + N] - .iter() - .zip(values.iter()) - .for_each(|(cell, &byte)| cell.set(byte)); - - Ok(()) + Ok(seq_writer.start_offset()) } - // specialization of write_array for u8 - pub fn write_u8(&self, offset: usize, value: u8) -> MResult<()> { - self.check_access(offset, 1)?; - self.memory[offset].set(value); + pub fn sequential_writer(&self, size: u32, type_tag: u32) -> WriteResult { + let offset = self.heap_manager.allocate(size, type_tag)?; + let new_mem_slice = self.heap_manager.memory_slice(MEMORY_INDEX)?; + self.memory.set(new_mem_slice); - Ok(()) - } - - // specialization of write_array for u32 - pub fn write_u32(&self, offset: usize, value: u32) -> MResult<()> { - self.check_access(offset, 4)?; - - let value = value.to_le_bytes(); - self.memory[offset].set(value[0]); - self.memory[offset + 1].set(value[1]); - self.memory[offset + 2].set(value[2]); - self.memory[offset + 3].set(value[3]); - - Ok(()) - } - - pub fn write_bytes(&self, offset: usize, bytes: &[u8]) -> MResult<()> { - let writer = self.sequential_writer(offset, bytes.len())?; - writer.write_bytes(bytes); - - Ok(()) - } - - pub fn sequential_writer( - &self, - offset: usize, - size: usize, - ) -> MResult> { - self.check_access(offset, size)?; - - Ok(SequentialWriter::new(&self, offset)) - } - - pub fn check_access(&self, offset: usize, size: usize) -> MResult<()> { - let right = offset + size; - - // the first condition is a check for overflow - if right < offset || right >= self.memory.len() { - return Err(MemoryAccessError::InvalidAccess { - offset, - size, - memory_size: self.memory.len(), - }); - } - - Ok(()) + Ok(SequentialWriter::new(offset)) } } -impl<'w, 'm> SequentialWriter<'w, 'm> { - pub(super) fn new(writer: &'w MemoryWriter<'m>, offset: usize) -> Self { - let offset = Cell::new(offset); - - Self { writer, offset } +impl SequentialWriter { + pub(self) fn new(offset: usize) -> Self { + Self { + offset: Cell::new(offset), + start_offset: offset, + } } - pub fn write_array(&self, values: [u8; N]) { + pub fn start_offset(&self) -> usize { + self.start_offset + } + + pub fn write_array( + &self, + writer: &MemoryWriter, + values: [u8; N], + ) { let offset = self.offset.get(); - log::trace!("write array: offset {} {:?}", offset, values); - - self.writer.memory[offset..offset + N] + writer.memory.get()[offset..offset + N] .iter() .zip(values.iter()) .for_each(|(cell, &byte)| cell.set(byte)); @@ -122,33 +94,35 @@ impl<'w, 'm> SequentialWriter<'w, 'm> { } // specialization of write_array for u8 - pub fn write_u8(&self, value: u8) { + pub fn write_u8(&self, writer: &MemoryWriter, value: u8) { let offset = self.offset.get(); - log::trace!("write_u8: write {} to {}", value, offset); - self.writer.memory[offset].set(value); + writer.memory.get()[offset].set(value); self.offset.set(offset + 1); } // specialization of write_array for u32 - pub fn write_u32(&self, value: u32) { + pub fn write_u32(&self, writer: &MemoryWriter, value: u32) { let offset = self.offset.get(); let value = value.to_le_bytes(); - self.writer.memory[offset].set(value[0]); - self.writer.memory[offset + 1].set(value[1]); - self.writer.memory[offset + 2].set(value[2]); - self.writer.memory[offset + 3].set(value[3]); + let memory = writer.memory.get(); + + memory[offset].set(value[0]); + memory[offset + 1].set(value[1]); + memory[offset + 2].set(value[2]); + memory[offset + 3].set(value[3]); self.offset.set(offset + 4); } #[allow(dead_code)] - pub fn write_bytes(&self, bytes: &[u8]) { + pub fn write_bytes(&self, writer: &MemoryWriter, bytes: &[u8]) { let offset = self.offset.get(); - self.writer.memory[offset..offset + bytes.len()] + let memory = writer.memory.get(); + memory[offset..offset + bytes.len()] .iter() .zip(bytes) .for_each(|(cell, &byte)| cell.set(byte)); diff --git a/crates/it-types/src/impls/values.rs b/crates/it-types/src/impls/values.rs index 3d2c12e..6ae6f72 100644 --- a/crates/it-types/src/impls/values.rs +++ b/crates/it-types/src/impls/values.rs @@ -50,4 +50,46 @@ native!(f32, F32); native!(f64, F64); native!(u128, U128); native!(String, String); -native!(Vec, ByteArray); + +impl NativeType for Vec { + const INTERFACE_TYPE: IType = IType::ByteArray; +} + +impl From> for IValue { + fn from(n: Vec) -> Self { + IValue::ByteArray(n) + } +} + +impl TryFrom for Vec { + type Error = WasmValueNativeCastError; + + fn try_from(w: IValue) -> Result { + match w { + IValue::ByteArray(n) => Ok(n), + IValue::Array(ivalues) => try_to_byte_array(ivalues), + _ => Err(WasmValueNativeCastError { + from: w, + to: Vec::::INTERFACE_TYPE, + }), + } + } +} + +fn try_to_byte_array(ivalues: Vec) -> Result, WasmValueNativeCastError> { + let mut result = Vec::with_capacity(ivalues.len()); + + for value in &ivalues { + match value { + IValue::U8(byte) => result.push(*byte), + _ => { + return Err(WasmValueNativeCastError { + from: IValue::Array(ivalues), + to: Vec::::INTERFACE_TYPE, + }) + } + } + } + + Ok(result) +} diff --git a/wasmer-it/src/errors.rs b/wasmer-it/src/errors.rs index a9a894a..1e8601b 100644 --- a/wasmer-it/src/errors.rs +++ b/wasmer-it/src/errors.rs @@ -12,6 +12,7 @@ use std::{ string::{self, ToString}, }; +use it_lilo_utils::error::MemoryWriteError; use thiserror::Error as ThisError; pub use fluence_it_types::WasmValueNativeCastError; @@ -47,6 +48,14 @@ impl InstructionError { let error_kind = InstructionErrorKind::LiLoError(lilo); Self::from_error_kind(instruction, error_kind) } + + pub(crate) fn from_write_error( + instruction: Instruction, + write_error: MemoryWriteError, + ) -> Self { + let error_kind = InstructionErrorKind::MemoryWriteError(write_error); + Self::from_error_kind(instruction, error_kind) + } } impl Error for InstructionError {} @@ -221,6 +230,10 @@ pub enum InstructionErrorKind { /// Errors related to lifting/lowering records. #[error("{0}")] LiLoError(#[from] LiLoError), + + /// Errors related to incorrect writing to memory. + #[error("{0}")] + MemoryWriteError(#[from] MemoryWriteError), } impl From<(TryFromIntError, &'static str)> for InstructionErrorKind { diff --git a/wasmer-it/src/interpreter/instructions/arrays.rs b/wasmer-it/src/interpreter/instructions/arrays.rs index ea885e9..991fe60 100644 --- a/wasmer-it/src/interpreter/instructions/arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays.rs @@ -14,6 +14,7 @@ use crate::{ interpreter::Instruction, IType, IValue, }; +use it_lilo_utils::memory_writer::MemoryWriter; use std::convert::TryInto; @@ -119,25 +120,12 @@ where })?; } - log::trace!("array.lower_memory: 1"); - 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(); - log::trace!("array.lower_memory: 1"); - let memory = memory_view.deref(); + let lo_helper = lilo::LoHelper::new(&**instance); + let memory_writer = MemoryWriter::new(&lo_helper) + .map_err(|e| InstructionError::from_write_error(instruction.clone(), e))?; - let lo_helper = lilo::LoHelper::new(&**instance, memory) - .map_err(|e| InstructionError::from_lilo(instruction.clone(), e))?; - log::trace!("array.lower_memory: 3"); - let (offset, size) = array_lower_memory_impl(&lo_helper, values) - .map_err(|e| InstructionError::from_lilo(instruction.clone(), e))?; + let (offset, size) = array_lower_memory_impl(&memory_writer, values) + .map_err(|e| InstructionError::from_write_error(instruction.clone(), e))?; log::trace!( "array.lower_memory: pushing {}, {} on the stack", diff --git a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs index 2f07af4..3ed7584 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs +++ b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs @@ -1,75 +1,66 @@ -use super::lilo::*; - use crate::IValue; +use it_lilo_utils::memory_writer::Heapable; +use it_lilo_utils::memory_writer::MemoryWriter; use it_lilo_utils::ser_value_size; use it_lilo_utils::type_tag_form_ivalue; +use it_lilo_utils::WriteResult; -pub(crate) fn array_lower_memory_impl( - lo_helper: &LoHelper, +pub(crate) fn array_lower_memory_impl( + writer: &MemoryWriter, array_values: Vec, -) -> LiLoResult<(usize, usize)> { - log::trace!("array_lower_memory_impl: 1"); +) -> WriteResult<(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 = (lo_helper.allocate)( - size_to_allocate as _, - type_tag_form_ivalue(&array_values[0]) as _, - )?; - log::trace!("array_lower_memory_impl: 2"); - - let seq_writer = lo_helper - .writer - .sequential_writer(offset, size_to_allocate)?; - log::trace!("array_lower_memory_impl: 3"); + let elements_count = array_values.len() as u32; + let size = ser_value_size(&array_values[0]) * elements_count; + let type_tag = type_tag_form_ivalue(&array_values[0]); + let seq_writer = writer.sequential_writer(size, type_tag)?; // here it's known that all interface values have the same type for value in array_values { - log::trace!("array_lower_memory_impl: write {:?}", value); match value { - 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::U128(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::Boolean(value) => seq_writer.write_u8(writer, value as _), + IValue::S8(value) => seq_writer.write_u8(writer, value as _), + IValue::S16(value) => seq_writer.write_array(writer, value.to_le_bytes()), + IValue::S32(value) => seq_writer.write_array(writer, value.to_le_bytes()), + IValue::S64(value) => seq_writer.write_array(writer, value.to_le_bytes()), + IValue::U8(value) => seq_writer.write_array(writer, value.to_le_bytes()), + IValue::U16(value) => seq_writer.write_array(writer, value.to_le_bytes()), + IValue::U32(value) => seq_writer.write_array(writer, value.to_le_bytes()), + IValue::U64(value) => seq_writer.write_array(writer, value.to_le_bytes()), + IValue::U128(value) => seq_writer.write_array(writer, value.to_le_bytes()), + IValue::I32(value) => seq_writer.write_array(writer, value.to_le_bytes()), + IValue::I64(value) => seq_writer.write_array(writer, value.to_le_bytes()), + IValue::F32(value) => seq_writer.write_array(writer, value.to_le_bytes()), + IValue::F64(value) => seq_writer.write_array(writer, value.to_le_bytes()), IValue::String(value) => { - let offset = lo_helper.write_to_mem(value.as_bytes())? as u32; + let offset = writer.write_bytes(value.as_bytes())? as u32; - seq_writer.write_array(offset.to_le_bytes()); - seq_writer.write_array((value.len() as u32).to_le_bytes()); + seq_writer.write_array(writer, offset.to_le_bytes()); + seq_writer.write_array(writer, (value.len() as u32).to_le_bytes()); } IValue::ByteArray(values) => { - let offset = lo_helper.write_to_mem(&values)? as u32; + let offset = writer.write_bytes(&values)? as u32; - seq_writer.write_array(offset.to_le_bytes()); - seq_writer.write_array((values.len() as u32).to_le_bytes()); + seq_writer.write_array(writer, offset.to_le_bytes()); + seq_writer.write_array(writer, (values.len() as u32).to_le_bytes()); } IValue::Array(values) => { - let (offset, size) = array_lower_memory_impl(lo_helper, values)?; + let (offset, size) = array_lower_memory_impl(writer, values)?; - seq_writer.write_array((offset as u32).to_le_bytes()); - seq_writer.write_array((size as u32).to_le_bytes()); + seq_writer.write_array(writer, (offset as u32).to_le_bytes()); + seq_writer.write_array(writer, (size as u32).to_le_bytes()); } - IValue::Record(values) => { - let offset = super::record_lower_memory_impl(lo_helper, values)? as u32; - seq_writer.write_array(offset.to_le_bytes()); + let offset = super::record_lower_memory_impl(writer, values)? as u32; + seq_writer.write_array(writer, offset.to_le_bytes()); } } } + let offset = seq_writer.start_offset(); Ok((offset as _, elements_count as _)) } diff --git a/wasmer-it/src/interpreter/instructions/byte_arrays.rs b/wasmer-it/src/interpreter/instructions/byte_arrays.rs index fc0566d..5ca3dff 100644 --- a/wasmer-it/src/interpreter/instructions/byte_arrays.rs +++ b/wasmer-it/src/interpreter/instructions/byte_arrays.rs @@ -129,10 +129,21 @@ executable_instruction!( Ok(()) }, + Some(IValue::Array(array)) => { + let array = check_array_type(array, &instruction)?; + + let length = array.len() as i32; + + log::debug!("byte_array.size: pushing {} on the stack", length); + runtime.stack.push(IValue::I32(length)); + + Ok(()) + }, + Some(value) => instr_error!( instruction.clone(), InstructionErrorKind::InvalidValueOnTheStack { - expected_type: IType::String, + expected_type: IType::ByteArray, received_value: (&value).clone(), } ), @@ -145,3 +156,23 @@ executable_instruction!( } } ); + +fn check_array_type( + ivalues: Vec, + instruction: &Instruction, +) -> Result, InstructionError> { + if ivalues.is_empty() { + return Ok(ivalues); + } + + match &ivalues[0] { + IValue::U8(_) => Ok(ivalues), + _ => instr_error!( + instruction.clone(), + InstructionErrorKind::InvalidValueOnTheStack { + expected_type: IType::ByteArray, + received_value: IValue::Array(ivalues), + } + ), + } +} diff --git a/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs b/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs index 617baba..8dd87ec 100644 --- a/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs +++ b/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs @@ -1,10 +1,12 @@ +use super::LiLoError; use super::LiLoResult; -use super::RecordResolver; use crate::interpreter::wasm; +use crate::IRecordType; use it_lilo_utils::memory_reader::MemoryReader; use std::cell::Cell; +use std::rc::Rc; pub(crate) struct LiHelper<'i> { pub(crate) reader: MemoryReader<'i>, @@ -23,7 +25,7 @@ impl<'instance> LiHelper<'instance> { MemoryView: wasm::structures::MemoryView, Instance: wasm::structures::Instance, { - let record_resolver = super::build_record_resolver(instance)?; + let record_resolver = build_record_resolver(instance)?; let reader = MemoryReader::new(memory); let helper = Self { @@ -34,3 +36,26 @@ impl<'instance> LiHelper<'instance> { Ok(helper) } } + +pub(crate) type RecordResolver<'i> = Box LiLoResult> + 'i>; + +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/lilo/lo_helper.rs b/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs index b2e1b5d..2c8289a 100644 --- a/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs +++ b/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs @@ -1,45 +1,95 @@ -use super::AllocateFunc; -use super::LiLoResult; - use crate::interpreter::wasm; -use crate::IType; +use crate::interpreter::wasm::structures::FunctionIndex; +use crate::IValue; -use it_lilo_utils::memory_writer::MemoryWriter; -use it_lilo_utils::type_tag_form_itype; +use it_lilo_utils::error::MemoryWriteError; +use it_lilo_utils::memory_writer::Heapable; +use it_lilo_utils::WriteResult; use std::cell::Cell; +use std::marker::PhantomData; -pub(crate) struct LoHelper<'i> { - pub(crate) writer: MemoryWriter<'i>, - pub(crate) allocate: AllocateFunc<'i>, +pub struct LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView> +where + Export: wasm::structures::Export + 'i, + LocalImport: wasm::structures::LocalImport + 'i, + Memory: wasm::structures::Memory + 'i, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, +{ + pub(crate) instance: &'i Instance, + _phantom_export: PhantomData, + _phantom_local_import: PhantomData, + _phantom_memory: PhantomData, + _phantom_memory_view: PhantomData, } -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_tag = type_tag_form_itype(&IType::U8); - let offset = (self.allocate)(bytes.len() as _, alloc_type_tag as _)?; - - self.writer.write_bytes(offset, bytes)?; - - Ok(offset) +impl<'i, Instance, Export, LocalImport, Memory, MemoryView> + LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView> +where + Export: wasm::structures::Export + 'i, + LocalImport: wasm::structures::LocalImport + 'i, + Memory: wasm::structures::Memory + 'i, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, +{ + pub(crate) fn new(instance: &'i Instance) -> Self { + Self { + instance, + _phantom_export: PhantomData, + _phantom_local_import: PhantomData, + _phantom_memory: PhantomData, + _phantom_memory_view: PhantomData, + } + } +} + +impl<'i, Instance, Export, LocalImport, Memory, MemoryView> Heapable + for LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView> +where + Export: wasm::structures::Export + 'i, + LocalImport: wasm::structures::LocalImport + 'i, + Memory: wasm::structures::Memory + 'i, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, +{ + fn allocate(&self, size: u32, type_tag: u32) -> WriteResult { + use crate::interpreter::instructions::ALLOCATE_FUNC_INDEX; + use crate::interpreter::wasm::structures::TypedIndex; + + let index = FunctionIndex::new(ALLOCATE_FUNC_INDEX as usize); + let local_or_import = self.instance.local_or_import(index).ok_or( + MemoryWriteError::AllocateFuncIsMissing { + function_index: ALLOCATE_FUNC_INDEX, + }, + )?; + + let inputs = vec![IValue::I32(size as _), IValue::I32(type_tag as _)]; + // TODO: we could check it only once on the module startup or memorize check result + crate::interpreter::instructions::check_function_signature( + self.instance, + local_or_import, + &inputs, + ) + .map_err(|_| MemoryWriteError::AllocateFuncIncompatibleSignature)?; + + let outcome = local_or_import + .call(&inputs) + .map_err(|_| MemoryWriteError::AllocateCallFailed)?; + + if outcome.len() != 1 { + return Err(MemoryWriteError::AllocateFuncIncompatibleOutput); + } + + match outcome[0] { + IValue::I32(offset) => Ok(offset as _), + _ => Err(MemoryWriteError::AllocateFuncIncompatibleOutput), + } + } + + fn memory_slice(&self, memory_index: usize) -> WriteResult<&[Cell]> { + self.instance + .memory_slice(memory_index) + .ok_or(MemoryWriteError::MemoryIsMissing { memory_index }) } } diff --git a/wasmer-it/src/interpreter/instructions/lilo/mod.rs b/wasmer-it/src/interpreter/instructions/lilo/mod.rs index f14ce7e..b651497 100644 --- a/wasmer-it/src/interpreter/instructions/lilo/mod.rs +++ b/wasmer-it/src/interpreter/instructions/lilo/mod.rs @@ -1,13 +1,8 @@ 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 deleted file mode 100644 index 7ac8fce..0000000 --- a/wasmer-it/src/interpreter/instructions/lilo/utils.rs +++ /dev/null @@ -1,88 +0,0 @@ -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| { - log::trace!("call allocate closure 1: {} {}", size, ty); - 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, - })?; - - log::trace!("call allocate closure 2"); - - 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)?; - - log::trace!("call allocate closure 3: {:?}", inputs); - - let outcome = local_or_import - .call(&inputs) - .map_err(|_| LiLoError::AllocateCallFailed)?; - - log::trace!("call allocate closure 4: {:?}", outcome); - - if outcome.len() != 1 { - return Err(LiLoError::AllocateFuncIncompatibleOutput); - } - - log::trace!("call allocate closure 5"); - - 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/records.rs b/wasmer-it/src/interpreter/instructions/records.rs index dfc68bb..d40422b 100644 --- a/wasmer-it/src/interpreter/instructions/records.rs +++ b/wasmer-it/src/interpreter/instructions/records.rs @@ -7,13 +7,13 @@ pub(crate) use lower_record::record_lower_memory_impl; use super::array_lift_memory_impl; use super::array_lower_memory_impl; use super::lilo; - use crate::instr_error; use crate::interpreter::instructions::{is_record_fields_compatible_to_type, to_native}; use crate::IType; use crate::IValue; use crate::{errors::InstructionError, errors::InstructionErrorKind, interpreter::Instruction}; +use it_lilo_utils::memory_writer::MemoryWriter; use std::convert::TryInto; pub(crate) fn record_lift_memory( @@ -113,22 +113,11 @@ where log::debug!("record.lower_memory: obtained {:?} values on the stack for record type = {}", record_fields, record_type_id); - 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))?; + let lo_helper = lilo::LoHelper::new(&**instance); + let memory_writer = MemoryWriter::new(&lo_helper) + .map_err(|e| InstructionError::from_write_error(instruction.clone(), e))?; + let offset = record_lower_memory_impl(&memory_writer, record_fields) + .map_err(|e| InstructionError::from_write_error(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/lower_record.rs b/wasmer-it/src/interpreter/instructions/records/lower_record.rs index 616e777..4604e63 100644 --- a/wasmer-it/src/interpreter/instructions/records/lower_record.rs +++ b/wasmer-it/src/interpreter/instructions/records/lower_record.rs @@ -1,12 +1,13 @@ -use super::lilo::*; - use crate::IValue; use crate::NEVec; +use it_lilo_utils::memory_writer::Heapable; +use it_lilo_utils::memory_writer::MemoryWriter; +use it_lilo_utils::WriteResult; -pub(crate) fn record_lower_memory_impl( - lo_helper: &LoHelper, +pub(crate) fn record_lower_memory_impl( + writer: &MemoryWriter, values: NEVec, -) -> LiLoResult { +) -> WriteResult { let average_field_size = 4; let mut result: Vec = Vec::with_capacity(average_field_size * values.len()); @@ -27,34 +28,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 = lo_helper.write_to_mem(value.as_bytes())? as u32; + let offset = writer.write_bytes(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 offset = lo_helper.write_to_mem(&value)? as u32; + let offset = writer.write_bytes(&value)? as u32; 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(lo_helper, values)?; + let (offset, size) = super::array_lower_memory_impl(writer, 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 offset = record_lower_memory_impl(lo_helper, values)? as u32; + let offset = record_lower_memory_impl(writer, values)? as u32; result.extend_from_slice(&offset.to_le_bytes()); } } } - let result_pointer = lo_helper.write_to_mem(&result)?; + let result_pointer = writer.write_bytes(&result)?; Ok(result_pointer as _) } diff --git a/wasmer-it/src/interpreter/wasm/structures.rs b/wasmer-it/src/interpreter/wasm/structures.rs index 4666a75..e23144a 100644 --- a/wasmer-it/src/interpreter/wasm/structures.rs +++ b/wasmer-it/src/interpreter/wasm/structures.rs @@ -80,6 +80,7 @@ where fn export(&self, export_name: &str) -> Option<&E>; fn local_or_import(&self, index: I) -> Option<&LI>; fn memory(&self, index: usize) -> Option<&M>; + fn memory_slice(&self, index: usize) -> Option<&[Cell]>; fn wit_record_by_id(&self, index: u64) -> Option<&Rc>; } @@ -168,6 +169,10 @@ where None } + fn memory_slice(&self, _: usize) -> Option<&[Cell]> { + None + } + fn local_or_import(&self, _index: I) -> Option<&LI> { None } From cc44e387f7aa0ec4dc3372eddc09a1475e155f49 Mon Sep 17 00:00:00 2001 From: vms Date: Sat, 24 Apr 2021 21:55:14 +0300 Subject: [PATCH 19/27] refactoring --- Cargo.lock | 24 ++--- crates/it-lilo-utils/src/lib.rs | 99 +++-------------- crates/it-lilo-utils/src/lifter/error.rs | 40 +++++++ .../it-lilo-utils/src/lifter}/lift_array.rs | 73 ++++++++----- .../it-lilo-utils/src/lifter}/lift_record.rs | 73 ++++++++----- .../it-lilo-utils/src/{ => lifter}/macros.rs | 2 +- .../src/{ => lifter}/memory_reader.rs | 14 +-- crates/it-lilo-utils/src/lifter/mod.rs | 45 ++++++++ crates/it-lilo-utils/src/lowerer/error.rs | 28 +++++ .../it-lilo-utils/src/lowerer/lower_array.rs | 96 +++++++++++++++++ .../src/lowerer}/lower_record.rs | 40 +++++-- .../src/{ => lowerer}/memory_writer.rs | 45 ++++---- crates/it-lilo-utils/src/lowerer/mod.rs | 43 ++++++++ .../src/{error.rs => traits/heapable.rs} | 26 +++-- crates/it-lilo-utils/src/traits/mod.rs | 21 ++++ .../src/traits/record_resolvable.rs | 29 +++++ crates/it-lilo-utils/src/utils.rs | 95 ++++++++++++++++ wasmer-it/src/errors.rs | 77 ++----------- .../src/interpreter/instructions/arrays.rs | 33 +++--- .../instructions/arrays/lower_array.rs | 65 ----------- .../instructions/lilo/li_helper.rs | 102 +++++++++--------- .../instructions/lilo/lo_helper.rs | 52 ++++----- .../src/interpreter/instructions/lilo/mod.rs | 3 - .../src/interpreter/instructions/records.rs | 29 +++-- 24 files changed, 704 insertions(+), 450 deletions(-) create mode 100644 crates/it-lilo-utils/src/lifter/error.rs rename {wasmer-it/src/interpreter/instructions/arrays => crates/it-lilo-utils/src/lifter}/lift_array.rs (55%) rename {wasmer-it/src/interpreter/instructions/records => crates/it-lilo-utils/src/lifter}/lift_record.rs (54%) rename crates/it-lilo-utils/src/{ => lifter}/macros.rs (98%) rename crates/it-lilo-utils/src/{ => lifter}/memory_reader.rs (92%) create mode 100644 crates/it-lilo-utils/src/lifter/mod.rs create mode 100644 crates/it-lilo-utils/src/lowerer/error.rs create mode 100644 crates/it-lilo-utils/src/lowerer/lower_array.rs rename {wasmer-it/src/interpreter/instructions/records => crates/it-lilo-utils/src/lowerer}/lower_record.rs (61%) rename crates/it-lilo-utils/src/{ => lowerer}/memory_writer.rs (71%) create mode 100644 crates/it-lilo-utils/src/lowerer/mod.rs rename crates/it-lilo-utils/src/{error.rs => traits/heapable.rs} (79%) create mode 100644 crates/it-lilo-utils/src/traits/mod.rs create mode 100644 crates/it-lilo-utils/src/traits/record_resolvable.rs create mode 100644 crates/it-lilo-utils/src/utils.rs delete mode 100644 wasmer-it/src/interpreter/instructions/arrays/lower_array.rs diff --git a/Cargo.lock b/Cargo.lock index 4d73acc..4032009 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,9 +73,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "lexical-core" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ "arrayvec", "bitflags", @@ -127,9 +127,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid", ] @@ -175,18 +175,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.124" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.124" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2", "quote", @@ -212,9 +212,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" -version = "1.0.64" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" +checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883" dependencies = [ "proc-macro2", "quote", @@ -255,9 +255,9 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "version_check" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "wasmer-interface-types-fl" diff --git a/crates/it-lilo-utils/src/lib.rs b/crates/it-lilo-utils/src/lib.rs index d740ff1..2be5ede 100644 --- a/crates/it-lilo-utils/src/lib.rs +++ b/crates/it-lilo-utils/src/lib.rs @@ -14,90 +14,23 @@ * limitations under the License. */ -pub mod error; -mod macros; -pub mod memory_reader; -pub mod memory_writer; +#![deny( + dead_code, + nonstandard_style, + unused_imports, + unused_mut, + unused_variables, + unused_unsafe, + unreachable_patterns +)] +#![warn(rust_2018_idioms)] +pub mod lifter; +pub mod lowerer; +pub mod traits; +pub mod utils; + +pub use fluence_it_types::ne_vec::NEVec; pub use fluence_it_types::IRecordType; pub use fluence_it_types::IType; pub use fluence_it_types::IValue; - -pub type ReadResult = std::result::Result; -pub type WriteResult = 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) -> u32 { - 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_tag_form_itype(itype: &IType) -> u32 { - const POINTER_CODE: u32 = 3; // u32 in 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 => 6, // i8 - IType::S16 => 7, // i16 - IType::S32 | IType::I32 => 8, // i32 - IType::S64 | IType::I64 => 9, // i64 - IType::F32 => 10, // f32 - IType::F64 => 11, // f64 - IType::ByteArray | IType::Array(_) | IType::Record(_) | IType::String => POINTER_CODE, - } -} - -pub fn type_tag_form_ivalue(itype: &IValue) -> u32 { - const POINTER_CODE: u32 = 3; // u32 in 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(_) => 6, // i8 - IValue::S16(_) => 7, // i16 - IValue::S32(_) | IValue::I32(_) => 8, // i32 - IValue::S64(_) | IValue::I64(_) => 9, // i64 - IValue::F32(_) => 10, // f32 - IValue::F64(_) => 11, // f64 - IValue::ByteArray(_) | IValue::Array(_) | IValue::Record(_) | IValue::String(_) => { - POINTER_CODE - } - } -} diff --git a/crates/it-lilo-utils/src/lifter/error.rs b/crates/it-lilo-utils/src/lifter/error.rs new file mode 100644 index 0000000..dc8dd76 --- /dev/null +++ b/crates/it-lilo-utils/src/lifter/error.rs @@ -0,0 +1,40 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::traits::RecordResolvableError; +use thiserror::Error as ThisError; + +#[derive(Debug, ThisError)] +pub enum LiError { + #[error( + "Out-of-bound Wasm memory access: offset {offset}, size {size}, while memory_size {memory_size}" + )] + InvalidAccess { + offset: usize, + size: usize, + memory_size: usize, + }, + + #[error("{0}")] + RecordResolvableError(#[from] RecordResolvableError), + + #[error("{0}")] + InvalidUTF8String(#[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/lift_array.rs b/crates/it-lilo-utils/src/lifter/lift_array.rs similarity index 55% rename from wasmer-it/src/interpreter/instructions/arrays/lift_array.rs rename to crates/it-lilo-utils/src/lifter/lift_array.rs index 88239a8..12a82a4 100644 --- a/wasmer-it/src/interpreter/instructions/arrays/lift_array.rs +++ b/crates/it-lilo-utils/src/lifter/lift_array.rs @@ -1,22 +1,38 @@ -use super::lilo::*; +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +use super::record_lift_memory; +use super::ILifter; +use super::LiResult; +use crate::traits::RecordResolvable; +use crate::utils::ser_type_size; use crate::IType; use crate::IValue; -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, +pub fn array_lift_memory( + lifter: &ILifter<'_, '_, R>, value_type: &IType, offset: usize, elements_count: usize, -) -> LiLoResult { +) -> LiResult { if elements_count == 0 { return Ok(IValue::Array(vec![])); } - let reader = &li_helper.reader; + let reader = &lifter.reader; let ivalues = match value_type { IType::Boolean => reader.read_bool_array(offset, elements_count)?, @@ -32,25 +48,24 @@ pub(crate) fn array_lift_memory_impl( 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::String => read_string_array(lifter, offset, elements_count)?, + IType::ByteArray => read_array_array(lifter, &IType::ByteArray, offset, elements_count)?, + IType::Array(ty) => read_array_array(lifter, &ty, offset, elements_count)?, IType::Record(record_type_id) => { - read_record_array(li_helper, *record_type_id, offset, elements_count)? + read_record_array(lifter, *record_type_id, offset, elements_count)? } }; Ok(IValue::Array(ivalues)) } -// Vec => Vec (2 * len of prev) -fn read_string_array( - li_helper: &LiHelper, +fn read_string_array( + lifter: &ILifter<'_, '_, R>, offset: usize, elements_count: usize, -) -> LiLoResult> { +) -> LiResult> { let mut result = Vec::with_capacity(elements_count); - let seq_reader = li_helper + let seq_reader = lifter .reader .sequential_reader(offset, ser_type_size(&IType::String) * elements_count)?; @@ -58,7 +73,7 @@ fn read_string_array( 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 raw_str = lifter.reader.read_raw_u8_array(offset as _, size as _)?; let str = String::from_utf8(raw_str)?; result.push(IValue::String(str)); } @@ -66,14 +81,14 @@ fn read_string_array( Ok(result) } -fn read_array_array( - li_helper: &LiHelper, +fn read_array_array( + lifter: &ILifter<'_, '_, R>, ty: &IType, offset: usize, elements_count: usize, -) -> LiLoResult> { +) -> LiResult> { let mut result = Vec::with_capacity(elements_count); - let seq_reader = li_helper + let seq_reader = lifter .reader .sequential_reader(offset, ser_type_size(ty) * elements_count)?; @@ -81,29 +96,29 @@ fn read_array_array( 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 _)?; + let array = array_lift_memory(lifter, ty, offset as _, size as _)?; result.push(array); } Ok(result) } -fn read_record_array( - li_helper: &LiHelper, +fn read_record_array( + lifter: &ILifter<'_, '_, R>, record_type_id: u64, offset: usize, elements_count: usize, -) -> LiLoResult> { +) -> LiResult> { let mut result = Vec::with_capacity(elements_count); - let seq_reader = li_helper + let seq_reader = lifter .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_ty = lifter.resolver.resolve_record(record_type_id)?; - let record = record_lift_memory_impl(li_helper, &record_ty, offset as _)?; + let record = record_lift_memory(lifter, &record_ty, offset as _)?; result.push(record); } diff --git a/wasmer-it/src/interpreter/instructions/records/lift_record.rs b/crates/it-lilo-utils/src/lifter/lift_record.rs similarity index 54% rename from wasmer-it/src/interpreter/instructions/records/lift_record.rs rename to crates/it-lilo-utils/src/lifter/lift_record.rs index b52ab43..8fe23a9 100644 --- a/wasmer-it/src/interpreter/instructions/records/lift_record.rs +++ b/crates/it-lilo-utils/src/lifter/lift_record.rs @@ -1,23 +1,40 @@ -use super::lilo::*; +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +use super::ILifter; +use super::LiError; +use super::LiResult; +use super::MemoryReader; +use super::SequentialReader; +use crate::traits::RecordResolvable; +use crate::utils::record_size; use crate::IRecordType; use crate::IType; use crate::IValue; use crate::NEVec; -use it_lilo_utils::memory_reader::MemoryReader; -use it_lilo_utils::memory_reader::SequentialReader; -use it_lilo_utils::record_size; - -pub(crate) fn record_lift_memory_impl( - li_helper: &LiHelper<'_>, +pub fn record_lift_memory( + lifter: &ILifter<'_, '_, R>, record_type: &IRecordType, offset: usize, -) -> LiLoResult { +) -> LiResult { let mut values = Vec::with_capacity(record_type.fields.len()); let size = record_size(record_type); - let reader = &li_helper.reader; + let reader = &lifter.reader; let seq_reader = reader.sequential_reader(offset, size)?; for field in (*record_type.fields).iter() { @@ -37,20 +54,23 @@ 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(&li_helper, &seq_reader, &**ty)?), + IType::Array(ty) => values.push(read_array(&lifter, &seq_reader, &**ty)?), IType::Record(record_type_id) => { - values.push(read_record(li_helper, &seq_reader, *record_type_id)?) + values.push(read_record(lifter, &seq_reader, *record_type_id)?) } } } let record = NEVec::new(values.into_iter().collect()) - .map_err(|_| LiLoError::EmptyRecord(record_type.name.clone()))?; + .map_err(|_| LiError::EmptyRecord(record_type.name.clone()))?; Ok(IValue::Record(record)) } -fn read_string(reader: &MemoryReader, seq_reader: &SequentialReader) -> LiLoResult { +fn read_string( + reader: &MemoryReader<'_>, + seq_reader: &SequentialReader<'_, '_>, +) -> LiResult { let offset = seq_reader.read_u32(); let size = seq_reader.read_u32(); @@ -60,7 +80,10 @@ fn read_string(reader: &MemoryReader, seq_reader: &SequentialReader) -> LiLoResu Ok(string) } -fn read_byte_array(reader: &MemoryReader, seq_reader: &SequentialReader) -> LiLoResult { +fn read_byte_array( + reader: &MemoryReader<'_>, + seq_reader: &SequentialReader<'_, '_>, +) -> LiResult { let offset = seq_reader.read_u32(); let size = seq_reader.read_u32(); @@ -69,25 +92,25 @@ fn read_byte_array(reader: &MemoryReader, seq_reader: &SequentialReader) -> LiLo Ok(IValue::ByteArray(array)) } -fn read_array( - li_helper: &LiHelper, - seq_reader: &SequentialReader, +fn read_array( + lifter: &ILifter<'_, '_, R>, + seq_reader: &SequentialReader<'_, '_>, value_type: &IType, -) -> LiLoResult { +) -> LiResult { let offset = seq_reader.read_u32(); let size = seq_reader.read_u32(); - super::array_lift_memory_impl(li_helper, value_type, offset as _, size as _) + super::array_lift_memory(lifter, value_type, offset as _, size as _) } -fn read_record( - li_helper: &LiHelper, - seq_reader: &SequentialReader, +fn read_record( + lifter: &ILifter<'_, '_, R>, + seq_reader: &SequentialReader<'_, '_>, record_type_id: u64, -) -> LiLoResult { +) -> LiResult { let offset = seq_reader.read_u32(); - let record_type = (li_helper.record_resolver)(record_type_id)?; + let record_type = lifter.resolver.resolve_record(record_type_id)?; - record_lift_memory_impl(li_helper, &record_type, offset as _) + record_lift_memory(lifter, &record_type, offset as _) } diff --git a/crates/it-lilo-utils/src/macros.rs b/crates/it-lilo-utils/src/lifter/macros.rs similarity index 98% rename from crates/it-lilo-utils/src/macros.rs rename to crates/it-lilo-utils/src/lifter/macros.rs index edd8c0e..0c7e973 100644 --- a/crates/it-lilo-utils/src/macros.rs +++ b/crates/it-lilo-utils/src/lifter/macros.rs @@ -101,7 +101,7 @@ macro_rules! read_array_ty { &self, offset: usize, elements_count: usize, - ) -> crate::ReadResult> { + ) -> super::LiResult> { let reader = self.sequential_reader(offset, std::mem::size_of::<$ty>() * elements_count)?; let mut result = Vec::with_capacity(elements_count); diff --git a/crates/it-lilo-utils/src/memory_reader.rs b/crates/it-lilo-utils/src/lifter/memory_reader.rs similarity index 92% rename from crates/it-lilo-utils/src/memory_reader.rs rename to crates/it-lilo-utils/src/lifter/memory_reader.rs index 4271782..17b147d 100644 --- a/crates/it-lilo-utils/src/memory_reader.rs +++ b/crates/it-lilo-utils/src/lifter/memory_reader.rs @@ -14,11 +14,11 @@ * limitations under the License. */ -use crate::error::MemoryAccessError; +use super::LiError; +use super::LiResult; use crate::read_array_ty; use crate::read_ty; use crate::IValue; -use crate::ReadResult; use std::cell::Cell; @@ -46,13 +46,13 @@ impl<'m> MemoryReader<'m> { &self, offset: usize, size: usize, - ) -> ReadResult> { + ) -> LiResult> { self.check_access(offset, size)?; Ok(SequentialReader::new(&self, offset)) } - pub fn read_raw_u8_array(&self, offset: usize, elements_count: usize) -> ReadResult> { + pub fn read_raw_u8_array(&self, offset: usize, elements_count: usize) -> LiResult> { let reader = self.sequential_reader(offset, elements_count)?; let mut result = Vec::with_capacity(elements_count); @@ -64,7 +64,7 @@ impl<'m> MemoryReader<'m> { Ok(result) } - pub fn read_bool_array(&self, offset: usize, elements_count: usize) -> ReadResult> { + pub fn read_bool_array(&self, offset: usize, elements_count: usize) -> LiResult> { let reader = self.sequential_reader(offset, elements_count)?; let mut result = Vec::with_capacity(elements_count); @@ -76,12 +76,12 @@ impl<'m> MemoryReader<'m> { Ok(result) } - pub fn check_access(&self, offset: usize, size: usize) -> ReadResult<()> { + pub fn check_access(&self, offset: usize, size: usize) -> LiResult<()> { let right = offset + size; // the first condition is a check for overflow if right < offset || right >= self.memory.len() { - return Err(MemoryAccessError::InvalidAccess { + return Err(LiError::InvalidAccess { offset, size, memory_size: self.memory.len(), diff --git a/crates/it-lilo-utils/src/lifter/mod.rs b/crates/it-lilo-utils/src/lifter/mod.rs new file mode 100644 index 0000000..802a531 --- /dev/null +++ b/crates/it-lilo-utils/src/lifter/mod.rs @@ -0,0 +1,45 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +mod error; +mod lift_array; +mod lift_record; +mod macros; +mod memory_reader; + +pub use error::LiError; +pub use lift_array::array_lift_memory; +pub use lift_record::record_lift_memory; +pub use memory_reader::MemoryReader; +pub use memory_reader::SequentialReader; + +use super::traits::RecordResolvable; + +use std::cell::Cell; + +pub type LiResult = std::result::Result; + +pub struct ILifter<'m, 'r, R: RecordResolvable> { + pub reader: MemoryReader<'m>, + pub resolver: &'r R, +} + +impl<'m, 'r, R: RecordResolvable> ILifter<'m, 'r, R> { + pub fn new(memory: &'m [Cell], resolver: &'r R) -> Self { + let reader = MemoryReader::new(memory); + Self { reader, resolver } + } +} diff --git a/crates/it-lilo-utils/src/lowerer/error.rs b/crates/it-lilo-utils/src/lowerer/error.rs new file mode 100644 index 0000000..6d1d501 --- /dev/null +++ b/crates/it-lilo-utils/src/lowerer/error.rs @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::traits::AllocatableError; +use crate::traits::RecordResolvableError; +use thiserror::Error as ThisError; + +#[derive(Debug, ThisError)] +pub enum LoError { + #[error("{0}")] + AllocatableError(#[from] AllocatableError), + + #[error("{0}")] + RecordResolvableError(#[from] RecordResolvableError), +} diff --git a/crates/it-lilo-utils/src/lowerer/lower_array.rs b/crates/it-lilo-utils/src/lowerer/lower_array.rs new file mode 100644 index 0000000..d4cf737 --- /dev/null +++ b/crates/it-lilo-utils/src/lowerer/lower_array.rs @@ -0,0 +1,96 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::ILowerer; +use super::LoResult; +use crate::traits::Allocatable; +use crate::utils::ser_value_size; +use crate::utils::type_tag_form_ivalue; +use crate::IValue; + +pub struct LoweredArray { + pub offset: usize, + pub size: usize, +} + +impl LoweredArray { + pub fn new(offset: usize, size: usize) -> Self { + Self { offset, size } + } + + pub fn empty() -> Self { + Self { offset: 0, size: 0 } + } +} + +pub fn array_lower_memory( + lowerer: &ILowerer<'_, A>, + array_values: Vec, +) -> LoResult { + if array_values.is_empty() { + return Ok(LoweredArray::empty()); + } + + let elements_count = array_values.len() as u32; + let size = ser_value_size(&array_values[0]) * elements_count; + let type_tag = type_tag_form_ivalue(&array_values[0]); + let seq_writer = lowerer.writer.sequential_writer(size, type_tag)?; + + // here it's known that all interface values have the same type + for value in array_values { + match value { + IValue::Boolean(value) => seq_writer.write_u8(&lowerer.writer, value as _), + IValue::S8(value) => seq_writer.write_u8(&lowerer.writer, value as _), + IValue::S16(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()), + IValue::S32(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()), + IValue::S64(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()), + IValue::U8(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()), + IValue::U16(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()), + IValue::U32(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()), + IValue::U64(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()), + IValue::I32(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()), + IValue::I64(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()), + IValue::F32(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()), + IValue::F64(value) => seq_writer.write_array(&lowerer.writer, value.to_le_bytes()), + IValue::String(value) => { + let offset = lowerer.writer.write_bytes(value.as_bytes())? as u32; + + seq_writer.write_array(&lowerer.writer, offset.to_le_bytes()); + seq_writer.write_array(&lowerer.writer, (value.len() as u32).to_le_bytes()); + } + IValue::ByteArray(values) => { + let offset = lowerer.writer.write_bytes(&values)? as u32; + + seq_writer.write_array(&lowerer.writer, offset.to_le_bytes()); + seq_writer.write_array(&lowerer.writer, (values.len() as u32).to_le_bytes()); + } + IValue::Array(values) => { + let LoweredArray { offset, size } = array_lower_memory(lowerer, values)?; + + seq_writer.write_array(&lowerer.writer, (offset as u32).to_le_bytes()); + seq_writer.write_array(&lowerer.writer, (size as u32).to_le_bytes()); + } + IValue::Record(values) => { + let offset = super::record_lower_memory(lowerer, values)? as u32; + seq_writer.write_array(&lowerer.writer, offset.to_le_bytes()); + } + } + } + + let offset = seq_writer.start_offset(); + let lowered_array = LoweredArray::new(offset as _, elements_count as _); + Ok(lowered_array) +} diff --git a/wasmer-it/src/interpreter/instructions/records/lower_record.rs b/crates/it-lilo-utils/src/lowerer/lower_record.rs similarity index 61% rename from wasmer-it/src/interpreter/instructions/records/lower_record.rs rename to crates/it-lilo-utils/src/lowerer/lower_record.rs index 88557e0..b1699e1 100644 --- a/wasmer-it/src/interpreter/instructions/records/lower_record.rs +++ b/crates/it-lilo-utils/src/lowerer/lower_record.rs @@ -1,14 +1,32 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::ILowerer; +use super::LoResult; +use super::LoweredArray; +use crate::traits::Allocatable; use crate::IValue; use crate::NEVec; -use it_lilo_utils::memory_writer::Heapable; -use it_lilo_utils::memory_writer::MemoryWriter; -use it_lilo_utils::WriteResult; -pub(crate) fn record_lower_memory_impl( - writer: &MemoryWriter, +pub fn record_lower_memory( + lowerer: &ILowerer<'_, A>, values: NEVec, -) -> WriteResult { +) -> LoResult { let average_field_size = 4; + // TODO: avoid this additional allocation after fixing github.com/fluencelabs/fce/issues/77 let mut result: Vec = Vec::with_capacity(average_field_size * values.len()); for value in values.into_vec() { @@ -27,34 +45,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 = writer.write_bytes(value.as_bytes())? as u32; + let offset = lowerer.writer.write_bytes(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 offset = writer.write_bytes(&value)? as u32; + let offset = lowerer.writer.write_bytes(&value)? as u32; 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(writer, values)?; + let LoweredArray { offset, size } = super::array_lower_memory(lowerer, 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 offset = record_lower_memory_impl(writer, values)? as u32; + let offset = record_lower_memory(lowerer, values)? as u32; result.extend_from_slice(&offset.to_le_bytes()); } } } - let result_pointer = writer.write_bytes(&result)?; + let result_pointer = lowerer.writer.write_bytes(&result)?; Ok(result_pointer as _) } diff --git a/crates/it-lilo-utils/src/memory_writer.rs b/crates/it-lilo-utils/src/lowerer/memory_writer.rs similarity index 71% rename from crates/it-lilo-utils/src/memory_writer.rs rename to crates/it-lilo-utils/src/lowerer/memory_writer.rs index a3d6ff3..cfad04e 100644 --- a/crates/it-lilo-utils/src/memory_writer.rs +++ b/crates/it-lilo-utils/src/lowerer/memory_writer.rs @@ -14,21 +14,16 @@ * limitations under the License. */ -use crate::WriteResult; +use super::LoResult; +use crate::traits::Allocatable; +use crate::traits::MemSlice; +use crate::traits::DEFAULT_MEMORY_INDEX; +use crate::utils::type_tag_form_itype; + use std::cell::Cell; -pub type MemSlice<'m> = &'m [Cell]; - -const MEMORY_INDEX: usize = 0; - -pub trait Heapable { - fn allocate(&self, size: u32, type_tag: u32) -> WriteResult; - - fn memory_slice(&self, memory_index: usize) -> WriteResult>; -} - -pub struct MemoryWriter<'i, T: Heapable> { - heap_manager: &'i T, +pub struct MemoryWriter<'i, R: Allocatable> { + heap_manager: &'i R, pub(self) memory: Cell>, } @@ -37,9 +32,9 @@ pub struct SequentialWriter { offset: Cell, } -impl<'i, T: Heapable> MemoryWriter<'i, T> { - pub fn new(heap_manager: &'i T) -> WriteResult { - let mem_slice = heap_manager.memory_slice(MEMORY_INDEX)?; +impl<'i, A: Allocatable> MemoryWriter<'i, A> { + pub fn new(heap_manager: &'i A) -> LoResult { + let mem_slice = heap_manager.memory_slice(DEFAULT_MEMORY_INDEX)?; let memory = Cell::new(mem_slice); let writer = Self { @@ -49,17 +44,17 @@ impl<'i, T: Heapable> MemoryWriter<'i, T> { Ok(writer) } - pub fn write_bytes(&self, bytes: &[u8]) -> WriteResult { - let byte_type_tag = crate::type_tag_form_itype(&crate::IType::U8); + pub fn write_bytes(&self, bytes: &[u8]) -> LoResult { + let byte_type_tag = type_tag_form_itype(&crate::IType::U8); let seq_writer = self.sequential_writer(bytes.len() as _, byte_type_tag)?; seq_writer.write_bytes(self, bytes); Ok(seq_writer.start_offset()) } - pub fn sequential_writer(&self, size: u32, type_tag: u32) -> WriteResult { + pub fn sequential_writer(&self, size: u32, type_tag: u32) -> LoResult { let offset = self.heap_manager.allocate(size, type_tag)?; - let new_mem_slice = self.heap_manager.memory_slice(MEMORY_INDEX)?; + let new_mem_slice = self.heap_manager.memory_slice(DEFAULT_MEMORY_INDEX)?; self.memory.set(new_mem_slice); Ok(SequentialWriter::new(offset)) @@ -78,9 +73,9 @@ impl SequentialWriter { self.start_offset } - pub fn write_array( + pub fn write_array( &self, - writer: &MemoryWriter, + writer: &MemoryWriter<'_, A>, values: [u8; N], ) { let offset = self.offset.get(); @@ -94,7 +89,7 @@ impl SequentialWriter { } // specialization of write_array for u8 - pub fn write_u8(&self, writer: &MemoryWriter, value: u8) { + pub fn write_u8(&self, writer: &MemoryWriter<'_, A>, value: u8) { let offset = self.offset.get(); writer.memory.get()[offset].set(value); @@ -103,7 +98,7 @@ impl SequentialWriter { } // specialization of write_array for u32 - pub fn write_u32(&self, writer: &MemoryWriter, value: u32) { + pub fn write_u32(&self, writer: &MemoryWriter<'_, A>, value: u32) { let offset = self.offset.get(); let value = value.to_le_bytes(); @@ -118,7 +113,7 @@ impl SequentialWriter { } #[allow(dead_code)] - pub fn write_bytes(&self, writer: &MemoryWriter, bytes: &[u8]) { + pub fn write_bytes(&self, writer: &MemoryWriter<'_, A>, bytes: &[u8]) { let offset = self.offset.get(); let memory = writer.memory.get(); diff --git a/crates/it-lilo-utils/src/lowerer/mod.rs b/crates/it-lilo-utils/src/lowerer/mod.rs new file mode 100644 index 0000000..d890a11 --- /dev/null +++ b/crates/it-lilo-utils/src/lowerer/mod.rs @@ -0,0 +1,43 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +mod error; +mod lower_array; +mod lower_record; +mod memory_writer; + +use crate::lowerer::memory_writer::MemoryWriter; +use crate::traits::Allocatable; + +pub use error::LoError; +pub use lower_array::array_lower_memory; +pub use lower_array::LoweredArray; +pub use lower_record::record_lower_memory; + +pub type LoResult = std::result::Result; + +pub struct ILowerer<'m, A: Allocatable> { + pub writer: MemoryWriter<'m, A>, +} + +impl<'m, A: Allocatable> ILowerer<'m, A> { + pub fn new(allocatable: &'m A) -> LoResult { + let writer = MemoryWriter::new(allocatable)?; + let lowerer = Self { writer }; + + Ok(lowerer) + } +} diff --git a/crates/it-lilo-utils/src/error.rs b/crates/it-lilo-utils/src/traits/heapable.rs similarity index 79% rename from crates/it-lilo-utils/src/error.rs rename to crates/it-lilo-utils/src/traits/heapable.rs index fb7660f..a675db3 100644 --- a/crates/it-lilo-utils/src/error.rs +++ b/crates/it-lilo-utils/src/traits/heapable.rs @@ -14,22 +14,21 @@ * limitations under the License. */ +use std::cell::Cell; use thiserror::Error as ThisError; -#[derive(Debug, ThisError)] -pub enum MemoryAccessError { - #[error( - "Out-of-bound Wasm memory access: offset {offset}, size {size}, while memory_size {memory_size}" - )] - InvalidAccess { - offset: usize, - size: usize, - memory_size: usize, - }, +pub const DEFAULT_MEMORY_INDEX: usize = 0; + +pub type MemSlice<'m> = &'m [Cell]; + +pub trait Allocatable { + fn allocate(&self, size: u32, type_tag: u32) -> Result; + + fn memory_slice(&self, memory_index: usize) -> Result, AllocatableError>; } #[derive(Debug, ThisError)] -pub enum MemoryWriteError { +pub enum AllocatableError { /// The memory doesn't exist. #[error("memory `{memory_index}` does not exist")] MemoryIsMissing { @@ -61,4 +60,9 @@ pub enum MemoryWriteError { probably a Wasm module's built with unsupported sdk version" )] AllocateFuncIncompatibleOutput, + + // TODO: make it generic in future. + /// User defined error. + #[error("{0}")] + UserDefinedError(String), } diff --git a/crates/it-lilo-utils/src/traits/mod.rs b/crates/it-lilo-utils/src/traits/mod.rs new file mode 100644 index 0000000..8d2189a --- /dev/null +++ b/crates/it-lilo-utils/src/traits/mod.rs @@ -0,0 +1,21 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +mod heapable; +mod record_resolvable; + +pub use heapable::*; +pub use record_resolvable::*; diff --git a/crates/it-lilo-utils/src/traits/record_resolvable.rs b/crates/it-lilo-utils/src/traits/record_resolvable.rs new file mode 100644 index 0000000..ad53e0d --- /dev/null +++ b/crates/it-lilo-utils/src/traits/record_resolvable.rs @@ -0,0 +1,29 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::IRecordType; +use thiserror::Error as ThisError; + +pub trait RecordResolvable { + fn resolve_record(&self, record_type_id: u64) -> Result<&IRecordType, RecordResolvableError>; +} + +#[derive(Debug, ThisError)] +pub enum RecordResolvableError { + /// Record for such type is wasn't found. + #[error("Record with type id '{0}' not found")] + RecordNotFound(u64), +} diff --git a/crates/it-lilo-utils/src/utils.rs b/crates/it-lilo-utils/src/utils.rs new file mode 100644 index 0000000..374704f --- /dev/null +++ b/crates/it-lilo-utils/src/utils.rs @@ -0,0 +1,95 @@ +/* + * Copyright 2021 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::IRecordType; +use crate::IType; +use crate::IValue; + +/// 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) -> u32 { + 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_tag_form_itype(itype: &IType) -> u32 { + const POINTER_CODE: u32 = 3; // u32 in 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 => 6, // i8 + IType::S16 => 7, // i16 + IType::S32 | IType::I32 => 8, // i32 + IType::S64 | IType::I64 => 9, // i64 + IType::F32 => 10, // f32 + IType::F64 => 11, // f64 + IType::ByteArray | IType::Array(_) | IType::Record(_) | IType::String => POINTER_CODE, + } +} + +pub fn type_tag_form_ivalue(itype: &IValue) -> u32 { + const POINTER_CODE: u32 = 3; // u32 in 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(_) => 6, // i8 + IValue::S16(_) => 7, // i16 + IValue::S32(_) | IValue::I32(_) => 8, // i32 + IValue::S64(_) | IValue::I64(_) => 9, // i64 + IValue::F32(_) => 10, // f32 + IValue::F64(_) => 11, // f64 + IValue::ByteArray(_) | IValue::Array(_) | IValue::Record(_) | IValue::String(_) => { + POINTER_CODE + } + } +} diff --git a/wasmer-it/src/errors.rs b/wasmer-it/src/errors.rs index 1e8601b..3d29d3c 100644 --- a/wasmer-it/src/errors.rs +++ b/wasmer-it/src/errors.rs @@ -12,7 +12,8 @@ use std::{ string::{self, ToString}, }; -use it_lilo_utils::error::MemoryWriteError; +use it_lilo_utils::lifter::LiError; +use it_lilo_utils::lowerer::LoError; use thiserror::Error as ThisError; pub use fluence_it_types::WasmValueNativeCastError; @@ -44,16 +45,13 @@ impl InstructionError { } } - pub(crate) fn from_lilo(instruction: Instruction, lilo: LiLoError) -> Self { - let error_kind = InstructionErrorKind::LiLoError(lilo); + pub(crate) fn from_li(instruction: Instruction, li: LiError) -> Self { + let error_kind = InstructionErrorKind::LiError(li); Self::from_error_kind(instruction, error_kind) } - pub(crate) fn from_write_error( - instruction: Instruction, - write_error: MemoryWriteError, - ) -> Self { - let error_kind = InstructionErrorKind::MemoryWriteError(write_error); + pub(crate) fn from_lo(instruction: Instruction, lo: LoError) -> Self { + let error_kind = InstructionErrorKind::LoError(lo); Self::from_error_kind(instruction, error_kind) } } @@ -229,11 +227,11 @@ pub enum InstructionErrorKind { /// Errors related to lifting/lowering records. #[error("{0}")] - LiLoError(#[from] LiLoError), + LiError(#[from] LiError), /// Errors related to incorrect writing to memory. #[error("{0}")] - MemoryWriteError(#[from] MemoryWriteError), + LoError(#[from] LoError), } impl From<(TryFromIntError, &'static str)> for InstructionErrorKind { @@ -241,62 +239,3 @@ 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 991fe60..a3592e6 100644 --- a/wasmer-it/src/interpreter/instructions/arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays.rs @@ -1,11 +1,4 @@ -mod lift_array; -mod lower_array; - -pub(crate) use lift_array::array_lift_memory_impl; -pub(crate) use lower_array::array_lower_memory_impl; - use super::lilo; -use super::record_lower_memory_impl; use crate::instr_error; use crate::interpreter::instructions::to_native; @@ -14,7 +7,9 @@ use crate::{ interpreter::Instruction, IType, IValue, }; -use it_lilo_utils::memory_writer::MemoryWriter; +use it_lilo_utils::lifter::ILifter; +use it_lilo_utils::lowerer::ILowerer; +use it_lilo_utils::lowerer::LoweredArray; use std::convert::TryInto; @@ -72,10 +67,15 @@ where .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))?; + let li_helper = lilo::LiHelper::new(&**instance); + let lifter = ILifter::new(memory, &li_helper); + let array = it_lilo_utils::lifter::array_lift_memory( + &lifter, + &value_type, + offset as _, + size as _, + ) + .map_err(|e| InstructionError::from_li(instruction.clone(), e))?; log::trace!("array.lift_memory: pushing {:?} on the stack", array); runtime.stack.push(array); @@ -121,11 +121,12 @@ where } let lo_helper = lilo::LoHelper::new(&**instance); - let memory_writer = MemoryWriter::new(&lo_helper) - .map_err(|e| InstructionError::from_write_error(instruction.clone(), e))?; + let lowerer = ILowerer::new(&lo_helper) + .map_err(|e| InstructionError::from_lo(instruction.clone(), e))?; - let (offset, size) = array_lower_memory_impl(&memory_writer, values) - .map_err(|e| InstructionError::from_write_error(instruction.clone(), e))?; + let LoweredArray { offset, size } = + it_lilo_utils::lowerer::array_lower_memory(&lowerer, values) + .map_err(|e| InstructionError::from_lo(instruction.clone(), e))?; log::trace!( "array.lower_memory: pushing {}, {} on the stack", diff --git a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs b/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs deleted file mode 100644 index 8771602..0000000 --- a/wasmer-it/src/interpreter/instructions/arrays/lower_array.rs +++ /dev/null @@ -1,65 +0,0 @@ -use crate::IValue; - -use it_lilo_utils::memory_writer::Heapable; -use it_lilo_utils::memory_writer::MemoryWriter; -use it_lilo_utils::ser_value_size; -use it_lilo_utils::type_tag_form_ivalue; -use it_lilo_utils::WriteResult; - -pub(crate) fn array_lower_memory_impl( - writer: &MemoryWriter, - array_values: Vec, -) -> WriteResult<(usize, usize)> { - if array_values.is_empty() { - return Ok((0, 0)); - } - - let elements_count = array_values.len() as u32; - let size = ser_value_size(&array_values[0]) * elements_count; - let type_tag = type_tag_form_ivalue(&array_values[0]); - let seq_writer = writer.sequential_writer(size, type_tag)?; - - // here it's known that all interface values have the same type - for value in array_values { - match value { - IValue::Boolean(value) => seq_writer.write_u8(writer, value as _), - IValue::S8(value) => seq_writer.write_u8(writer, value as _), - IValue::S16(value) => seq_writer.write_array(writer, value.to_le_bytes()), - IValue::S32(value) => seq_writer.write_array(writer, value.to_le_bytes()), - IValue::S64(value) => seq_writer.write_array(writer, value.to_le_bytes()), - IValue::U8(value) => seq_writer.write_array(writer, value.to_le_bytes()), - IValue::U16(value) => seq_writer.write_array(writer, value.to_le_bytes()), - IValue::U32(value) => seq_writer.write_array(writer, value.to_le_bytes()), - IValue::U64(value) => seq_writer.write_array(writer, value.to_le_bytes()), - IValue::I32(value) => seq_writer.write_array(writer, value.to_le_bytes()), - IValue::I64(value) => seq_writer.write_array(writer, value.to_le_bytes()), - IValue::F32(value) => seq_writer.write_array(writer, value.to_le_bytes()), - IValue::F64(value) => seq_writer.write_array(writer, value.to_le_bytes()), - IValue::String(value) => { - let offset = writer.write_bytes(value.as_bytes())? as u32; - - seq_writer.write_array(writer, offset.to_le_bytes()); - seq_writer.write_array(writer, (value.len() as u32).to_le_bytes()); - } - IValue::ByteArray(values) => { - let offset = writer.write_bytes(&values)? as u32; - - seq_writer.write_array(writer, offset.to_le_bytes()); - seq_writer.write_array(writer, (values.len() as u32).to_le_bytes()); - } - IValue::Array(values) => { - let (offset, size) = array_lower_memory_impl(writer, values)?; - - seq_writer.write_array(writer, (offset as u32).to_le_bytes()); - seq_writer.write_array(writer, (size as u32).to_le_bytes()); - } - IValue::Record(values) => { - let offset = super::record_lower_memory_impl(writer, values)? as u32; - seq_writer.write_array(writer, offset.to_le_bytes()); - } - } - } - - let offset = seq_writer.start_offset(); - Ok((offset as _, elements_count as _)) -} diff --git a/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs b/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs index 8dd87ec..69a3aff 100644 --- a/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs +++ b/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs @@ -1,61 +1,61 @@ -use super::LiLoError; -use super::LiLoResult; use crate::interpreter::wasm; use crate::IRecordType; -use it_lilo_utils::memory_reader::MemoryReader; +use it_lilo_utils::traits::RecordResolvable; +use it_lilo_utils::traits::RecordResolvableError; -use std::cell::Cell; -use std::rc::Rc; +use std::marker::PhantomData; -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 = build_record_resolver(instance)?; - let reader = MemoryReader::new(memory); - - let helper = Self { - reader, - record_resolver, - }; - - Ok(helper) - } -} - -pub(crate) type RecordResolver<'i> = Box LiLoResult> + 'i>; - -pub(super) fn build_record_resolver<'instance, Instance, Export, LocalImport, Memory, MemoryView>( - instance: &'instance Instance, -) -> LiLoResult> +pub struct LiHelper<'i, Instance, Export, LocalImport, Memory, MemoryView> where - Export: wasm::structures::Export + 'instance, - LocalImport: wasm::structures::LocalImport + 'instance, - Memory: wasm::structures::Memory + 'instance, + Export: wasm::structures::Export + 'i, + LocalImport: wasm::structures::LocalImport + 'i, + Memory: wasm::structures::Memory + 'i, 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)) + pub(crate) instance: &'i Instance, + _export: PhantomData, + _local_import: PhantomData, + _memory: PhantomData, + _memory_view: PhantomData, +} + +impl<'i, Instance, Export, LocalImport, Memory, MemoryView> + LiHelper<'i, Instance, Export, LocalImport, Memory, MemoryView> +where + Export: wasm::structures::Export + 'i, + LocalImport: wasm::structures::LocalImport + 'i, + Memory: wasm::structures::Memory + 'i, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, +{ + pub(crate) fn new(instance: &'i Instance) -> Self { + Self { + instance, + _export: PhantomData, + _local_import: PhantomData, + _memory: PhantomData, + _memory_view: PhantomData, + } + } +} + +impl<'i, Instance, Export, LocalImport, Memory, MemoryView> RecordResolvable + for LiHelper<'i, Instance, Export, LocalImport, Memory, MemoryView> +where + Export: wasm::structures::Export + 'i, + LocalImport: wasm::structures::LocalImport + 'i, + Memory: wasm::structures::Memory + 'i, + MemoryView: wasm::structures::MemoryView, + Instance: wasm::structures::Instance, +{ + fn resolve_record(&self, record_type_id: u64) -> Result<&IRecordType, RecordResolvableError> { + let record = self + .instance + .wit_record_by_id(record_type_id) + .ok_or(RecordResolvableError::RecordNotFound(record_type_id))?; + + Ok(record) + } } diff --git a/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs b/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs index 2c8289a..9501177 100644 --- a/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs +++ b/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs @@ -2,11 +2,10 @@ use crate::interpreter::wasm; use crate::interpreter::wasm::structures::FunctionIndex; use crate::IValue; -use it_lilo_utils::error::MemoryWriteError; -use it_lilo_utils::memory_writer::Heapable; -use it_lilo_utils::WriteResult; +use it_lilo_utils::traits::Allocatable; +use it_lilo_utils::traits::AllocatableError; +use it_lilo_utils::traits::MemSlice; -use std::cell::Cell; use std::marker::PhantomData; pub struct LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView> @@ -18,10 +17,10 @@ where Instance: wasm::structures::Instance, { pub(crate) instance: &'i Instance, - _phantom_export: PhantomData, - _phantom_local_import: PhantomData, - _phantom_memory: PhantomData, - _phantom_memory_view: PhantomData, + _export: PhantomData, + _local_import: PhantomData, + _memory: PhantomData, + _memory_view: PhantomData, } impl<'i, Instance, Export, LocalImport, Memory, MemoryView> @@ -36,15 +35,15 @@ where pub(crate) fn new(instance: &'i Instance) -> Self { Self { instance, - _phantom_export: PhantomData, - _phantom_local_import: PhantomData, - _phantom_memory: PhantomData, - _phantom_memory_view: PhantomData, + _export: PhantomData, + _local_import: PhantomData, + _memory: PhantomData, + _memory_view: PhantomData, } } } -impl<'i, Instance, Export, LocalImport, Memory, MemoryView> Heapable +impl<'i, Instance, Export, LocalImport, Memory, MemoryView> Allocatable for LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView> where Export: wasm::structures::Export + 'i, @@ -53,16 +52,19 @@ where MemoryView: wasm::structures::MemoryView, Instance: wasm::structures::Instance, { - fn allocate(&self, size: u32, type_tag: u32) -> WriteResult { + fn allocate(&self, size: u32, type_tag: u32) -> Result { + use AllocatableError::*; + use crate::interpreter::instructions::ALLOCATE_FUNC_INDEX; use crate::interpreter::wasm::structures::TypedIndex; let index = FunctionIndex::new(ALLOCATE_FUNC_INDEX as usize); - let local_or_import = self.instance.local_or_import(index).ok_or( - MemoryWriteError::AllocateFuncIsMissing { - function_index: ALLOCATE_FUNC_INDEX, - }, - )?; + let local_or_import = + self.instance + .local_or_import(index) + .ok_or(AllocateFuncIsMissing { + function_index: ALLOCATE_FUNC_INDEX, + })?; let inputs = vec![IValue::I32(size as _), IValue::I32(type_tag as _)]; // TODO: we could check it only once on the module startup or memorize check result @@ -71,25 +73,25 @@ where local_or_import, &inputs, ) - .map_err(|_| MemoryWriteError::AllocateFuncIncompatibleSignature)?; + .map_err(|_| AllocateFuncIncompatibleSignature)?; let outcome = local_or_import .call(&inputs) - .map_err(|_| MemoryWriteError::AllocateCallFailed)?; + .map_err(|_| AllocateCallFailed)?; if outcome.len() != 1 { - return Err(MemoryWriteError::AllocateFuncIncompatibleOutput); + return Err(AllocateFuncIncompatibleOutput); } match outcome[0] { IValue::I32(offset) => Ok(offset as _), - _ => Err(MemoryWriteError::AllocateFuncIncompatibleOutput), + _ => Err(AllocateFuncIncompatibleOutput), } } - fn memory_slice(&self, memory_index: usize) -> WriteResult<&[Cell]> { + fn memory_slice(&self, memory_index: usize) -> Result, AllocatableError> { self.instance .memory_slice(memory_index) - .ok_or(MemoryWriteError::MemoryIsMissing { memory_index }) + .ok_or(AllocatableError::MemoryIsMissing { memory_index }) } } diff --git a/wasmer-it/src/interpreter/instructions/lilo/mod.rs b/wasmer-it/src/interpreter/instructions/lilo/mod.rs index b651497..ba078ea 100644 --- a/wasmer-it/src/interpreter/instructions/lilo/mod.rs +++ b/wasmer-it/src/interpreter/instructions/lilo/mod.rs @@ -1,8 +1,5 @@ mod li_helper; mod lo_helper; -pub(crate) use crate::errors::LiLoError; pub(crate) use li_helper::LiHelper; pub(crate) use lo_helper::LoHelper; - -pub(crate) type LiLoResult = std::result::Result; diff --git a/wasmer-it/src/interpreter/instructions/records.rs b/wasmer-it/src/interpreter/instructions/records.rs index d40422b..4581274 100644 --- a/wasmer-it/src/interpreter/instructions/records.rs +++ b/wasmer-it/src/interpreter/instructions/records.rs @@ -1,11 +1,3 @@ -mod lift_record; -mod lower_record; - -pub(crate) use lift_record::record_lift_memory_impl; -pub(crate) use lower_record::record_lower_memory_impl; - -use super::array_lift_memory_impl; -use super::array_lower_memory_impl; use super::lilo; use crate::instr_error; use crate::interpreter::instructions::{is_record_fields_compatible_to_type, to_native}; @@ -13,7 +5,9 @@ use crate::IType; use crate::IValue; use crate::{errors::InstructionError, errors::InstructionErrorKind, interpreter::Instruction}; -use it_lilo_utils::memory_writer::MemoryWriter; +use it_lilo_utils::lifter::ILifter; +use it_lilo_utils::lowerer::ILowerer; + use std::convert::TryInto; pub(crate) fn record_lift_memory( @@ -71,10 +65,10 @@ where .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))?; + let li_helper = lilo::LiHelper::new(&**instance); + let lifter = ILifter::new(memory, &li_helper); + let record = it_lilo_utils::lifter::record_lift_memory(&lifter, record_type, offset) + .map_err(|e| InstructionError::from_li(instruction.clone(), e))?; log::debug!("record.lift_memory: pushing {:?} on the stack", record); runtime.stack.push(record); @@ -114,10 +108,11 @@ where log::debug!("record.lower_memory: obtained {:?} values on the stack for record type = {}", record_fields, record_type_id); let lo_helper = lilo::LoHelper::new(&**instance); - let memory_writer = MemoryWriter::new(&lo_helper) - .map_err(|e| InstructionError::from_write_error(instruction.clone(), e))?; - let offset = record_lower_memory_impl(&memory_writer, record_fields) - .map_err(|e| InstructionError::from_write_error(instruction.clone(), e))?; + let memory_writer = ILowerer::new(&lo_helper) + .map_err(|e| InstructionError::from_lo(instruction.clone(), e))?; + let offset = + it_lilo_utils::lowerer::record_lower_memory(&memory_writer, record_fields) + .map_err(|e| InstructionError::from_lo(instruction.clone(), e))?; log::debug!("record.lower_memory: pushing {} on the stack", offset); runtime.stack.push(IValue::I32(offset)); From e75a108998ff408df48fdc60651758f7c8eb7655 Mon Sep 17 00:00:00 2001 From: vms Date: Sat, 24 Apr 2021 23:04:34 +0300 Subject: [PATCH 20/27] rename it-lilo-utils to it-lilo --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- crates/{it-lilo-utils => it-lilo}/Cargo.toml | 4 ++-- crates/{it-lilo-utils => it-lilo}/src/lib.rs | 0 .../src/lifter/error.rs | 0 .../src/lifter/lift_array.rs | 0 .../src/lifter/lift_record.rs | 0 .../src/lifter/macros.rs | 0 .../src/lifter/memory_reader.rs | 0 .../src/lifter/mod.rs | 0 .../src/lowerer/error.rs | 0 .../src/lowerer/lower_array.rs | 0 .../src/lowerer/lower_record.rs | 0 .../src/lowerer/memory_writer.rs | 0 .../src/lowerer/mod.rs | 0 .../src/traits/heapable.rs | 0 .../src/traits/mod.rs | 0 .../src/traits/record_resolvable.rs | 0 crates/{it-lilo-utils => it-lilo}/src/utils.rs | 0 crates/it-types/src/values.rs | 2 +- wasmer-it/Cargo.toml | 2 +- wasmer-it/src/errors.rs | 4 ++-- .../src/interpreter/instructions/arrays.rs | 18 +++++++----------- .../interpreter/instructions/lilo/li_helper.rs | 4 ++-- .../interpreter/instructions/lilo/lo_helper.rs | 6 +++--- .../src/interpreter/instructions/records.rs | 8 ++++---- 26 files changed, 25 insertions(+), 29 deletions(-) rename crates/{it-lilo-utils => it-lilo}/Cargo.toml (87%) rename crates/{it-lilo-utils => it-lilo}/src/lib.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/lifter/error.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/lifter/lift_array.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/lifter/lift_record.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/lifter/macros.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/lifter/memory_reader.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/lifter/mod.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/lowerer/error.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/lowerer/lower_array.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/lowerer/lower_record.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/lowerer/memory_writer.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/lowerer/mod.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/traits/heapable.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/traits/mod.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/traits/record_resolvable.rs (100%) rename crates/{it-lilo-utils => it-lilo}/src/utils.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 4032009..fdce1a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,7 +37,7 @@ dependencies = [ ] [[package]] -name = "it-lilo-utils" +name = "it-lilo" version = "0.1.0" dependencies = [ "fluence-it-types", @@ -264,7 +264,7 @@ name = "wasmer-interface-types-fl" version = "0.20.0" dependencies = [ "fluence-it-types", - "it-lilo-utils", + "it-lilo", "it-to-bytes", "itertools", "log", diff --git a/Cargo.toml b/Cargo.toml index 726f79a..cc38e80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] members = [ - "crates/it-lilo-utils", + "crates/it-lilo", "crates/to-bytes", "crates/it-types", "wasmer-it", diff --git a/crates/it-lilo-utils/Cargo.toml b/crates/it-lilo/Cargo.toml similarity index 87% rename from crates/it-lilo-utils/Cargo.toml rename to crates/it-lilo/Cargo.toml index 05fe25e..6792fbf 100644 --- a/crates/it-lilo-utils/Cargo.toml +++ b/crates/it-lilo/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "it-lilo-utils" +name = "it-lilo" version = "0.1.0" authors = ["Fluence Labs"] description = "Defines some helper utils for lifting/lowering IT" @@ -7,7 +7,7 @@ edition = "2018" license = "Apache-2.0" [lib] -name = "it_lilo_utils" +name = "it_lilo" path = "src/lib.rs" [dependencies] diff --git a/crates/it-lilo-utils/src/lib.rs b/crates/it-lilo/src/lib.rs similarity index 100% rename from crates/it-lilo-utils/src/lib.rs rename to crates/it-lilo/src/lib.rs diff --git a/crates/it-lilo-utils/src/lifter/error.rs b/crates/it-lilo/src/lifter/error.rs similarity index 100% rename from crates/it-lilo-utils/src/lifter/error.rs rename to crates/it-lilo/src/lifter/error.rs diff --git a/crates/it-lilo-utils/src/lifter/lift_array.rs b/crates/it-lilo/src/lifter/lift_array.rs similarity index 100% rename from crates/it-lilo-utils/src/lifter/lift_array.rs rename to crates/it-lilo/src/lifter/lift_array.rs diff --git a/crates/it-lilo-utils/src/lifter/lift_record.rs b/crates/it-lilo/src/lifter/lift_record.rs similarity index 100% rename from crates/it-lilo-utils/src/lifter/lift_record.rs rename to crates/it-lilo/src/lifter/lift_record.rs diff --git a/crates/it-lilo-utils/src/lifter/macros.rs b/crates/it-lilo/src/lifter/macros.rs similarity index 100% rename from crates/it-lilo-utils/src/lifter/macros.rs rename to crates/it-lilo/src/lifter/macros.rs diff --git a/crates/it-lilo-utils/src/lifter/memory_reader.rs b/crates/it-lilo/src/lifter/memory_reader.rs similarity index 100% rename from crates/it-lilo-utils/src/lifter/memory_reader.rs rename to crates/it-lilo/src/lifter/memory_reader.rs diff --git a/crates/it-lilo-utils/src/lifter/mod.rs b/crates/it-lilo/src/lifter/mod.rs similarity index 100% rename from crates/it-lilo-utils/src/lifter/mod.rs rename to crates/it-lilo/src/lifter/mod.rs diff --git a/crates/it-lilo-utils/src/lowerer/error.rs b/crates/it-lilo/src/lowerer/error.rs similarity index 100% rename from crates/it-lilo-utils/src/lowerer/error.rs rename to crates/it-lilo/src/lowerer/error.rs diff --git a/crates/it-lilo-utils/src/lowerer/lower_array.rs b/crates/it-lilo/src/lowerer/lower_array.rs similarity index 100% rename from crates/it-lilo-utils/src/lowerer/lower_array.rs rename to crates/it-lilo/src/lowerer/lower_array.rs diff --git a/crates/it-lilo-utils/src/lowerer/lower_record.rs b/crates/it-lilo/src/lowerer/lower_record.rs similarity index 100% rename from crates/it-lilo-utils/src/lowerer/lower_record.rs rename to crates/it-lilo/src/lowerer/lower_record.rs diff --git a/crates/it-lilo-utils/src/lowerer/memory_writer.rs b/crates/it-lilo/src/lowerer/memory_writer.rs similarity index 100% rename from crates/it-lilo-utils/src/lowerer/memory_writer.rs rename to crates/it-lilo/src/lowerer/memory_writer.rs diff --git a/crates/it-lilo-utils/src/lowerer/mod.rs b/crates/it-lilo/src/lowerer/mod.rs similarity index 100% rename from crates/it-lilo-utils/src/lowerer/mod.rs rename to crates/it-lilo/src/lowerer/mod.rs diff --git a/crates/it-lilo-utils/src/traits/heapable.rs b/crates/it-lilo/src/traits/heapable.rs similarity index 100% rename from crates/it-lilo-utils/src/traits/heapable.rs rename to crates/it-lilo/src/traits/heapable.rs diff --git a/crates/it-lilo-utils/src/traits/mod.rs b/crates/it-lilo/src/traits/mod.rs similarity index 100% rename from crates/it-lilo-utils/src/traits/mod.rs rename to crates/it-lilo/src/traits/mod.rs diff --git a/crates/it-lilo-utils/src/traits/record_resolvable.rs b/crates/it-lilo/src/traits/record_resolvable.rs similarity index 100% rename from crates/it-lilo-utils/src/traits/record_resolvable.rs rename to crates/it-lilo/src/traits/record_resolvable.rs diff --git a/crates/it-lilo-utils/src/utils.rs b/crates/it-lilo/src/utils.rs similarity index 100% rename from crates/it-lilo-utils/src/utils.rs rename to crates/it-lilo/src/utils.rs diff --git a/crates/it-types/src/values.rs b/crates/it-types/src/values.rs index b3a8f3a..2e0a237 100644 --- a/crates/it-types/src/values.rs +++ b/crates/it-types/src/values.rs @@ -37,7 +37,7 @@ pub enum IValue { /// A 64-bits float. F64(f64), - + /// A string. String(String), diff --git a/wasmer-it/Cargo.toml b/wasmer-it/Cargo.toml index ef8b07d..a16f5d6 100644 --- a/wasmer-it/Cargo.toml +++ b/wasmer-it/Cargo.toml @@ -10,7 +10,7 @@ edition = "2018" [dependencies] fluence-it-types = { path = "../crates/it-types", version = "0.2.0", features = ["impls"] } it-to-bytes = { path = "../crates/to-bytes", version = "0.1.0" } -it-lilo-utils = { path = "../crates/it-lilo-utils", version = "0.1.0" } +it-lilo = { path = "../crates/it-lilo", version = "0.1.0" } nom = "5.1" wast = "8.0" diff --git a/wasmer-it/src/errors.rs b/wasmer-it/src/errors.rs index 3d29d3c..9aa428c 100644 --- a/wasmer-it/src/errors.rs +++ b/wasmer-it/src/errors.rs @@ -12,8 +12,8 @@ use std::{ string::{self, ToString}, }; -use it_lilo_utils::lifter::LiError; -use it_lilo_utils::lowerer::LoError; +use it_lilo::lifter::LiError; +use it_lilo::lowerer::LoError; use thiserror::Error as ThisError; pub use fluence_it_types::WasmValueNativeCastError; diff --git a/wasmer-it/src/interpreter/instructions/arrays.rs b/wasmer-it/src/interpreter/instructions/arrays.rs index a3592e6..30867e9 100644 --- a/wasmer-it/src/interpreter/instructions/arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays.rs @@ -7,9 +7,9 @@ use crate::{ interpreter::Instruction, IType, IValue, }; -use it_lilo_utils::lifter::ILifter; -use it_lilo_utils::lowerer::ILowerer; -use it_lilo_utils::lowerer::LoweredArray; +use it_lilo::lifter::ILifter; +use it_lilo::lowerer::ILowerer; +use it_lilo::lowerer::LoweredArray; use std::convert::TryInto; @@ -69,13 +69,9 @@ where let li_helper = lilo::LiHelper::new(&**instance); let lifter = ILifter::new(memory, &li_helper); - let array = it_lilo_utils::lifter::array_lift_memory( - &lifter, - &value_type, - offset as _, - size as _, - ) - .map_err(|e| InstructionError::from_li(instruction.clone(), e))?; + let array = + it_lilo::lifter::array_lift_memory(&lifter, &value_type, offset as _, size as _) + .map_err(|e| InstructionError::from_li(instruction.clone(), e))?; log::trace!("array.lift_memory: pushing {:?} on the stack", array); runtime.stack.push(array); @@ -125,7 +121,7 @@ where .map_err(|e| InstructionError::from_lo(instruction.clone(), e))?; let LoweredArray { offset, size } = - it_lilo_utils::lowerer::array_lower_memory(&lowerer, values) + it_lilo::lowerer::array_lower_memory(&lowerer, values) .map_err(|e| InstructionError::from_lo(instruction.clone(), e))?; log::trace!( diff --git a/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs b/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs index 69a3aff..a761a79 100644 --- a/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs +++ b/wasmer-it/src/interpreter/instructions/lilo/li_helper.rs @@ -1,8 +1,8 @@ use crate::interpreter::wasm; use crate::IRecordType; -use it_lilo_utils::traits::RecordResolvable; -use it_lilo_utils::traits::RecordResolvableError; +use it_lilo::traits::RecordResolvable; +use it_lilo::traits::RecordResolvableError; use std::marker::PhantomData; diff --git a/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs b/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs index 9501177..72e2b66 100644 --- a/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs +++ b/wasmer-it/src/interpreter/instructions/lilo/lo_helper.rs @@ -2,9 +2,9 @@ use crate::interpreter::wasm; use crate::interpreter::wasm::structures::FunctionIndex; use crate::IValue; -use it_lilo_utils::traits::Allocatable; -use it_lilo_utils::traits::AllocatableError; -use it_lilo_utils::traits::MemSlice; +use it_lilo::traits::Allocatable; +use it_lilo::traits::AllocatableError; +use it_lilo::traits::MemSlice; use std::marker::PhantomData; diff --git a/wasmer-it/src/interpreter/instructions/records.rs b/wasmer-it/src/interpreter/instructions/records.rs index 4581274..0920b1f 100644 --- a/wasmer-it/src/interpreter/instructions/records.rs +++ b/wasmer-it/src/interpreter/instructions/records.rs @@ -5,8 +5,8 @@ use crate::IType; use crate::IValue; use crate::{errors::InstructionError, errors::InstructionErrorKind, interpreter::Instruction}; -use it_lilo_utils::lifter::ILifter; -use it_lilo_utils::lowerer::ILowerer; +use it_lilo::lifter::ILifter; +use it_lilo::lowerer::ILowerer; use std::convert::TryInto; @@ -67,7 +67,7 @@ where let li_helper = lilo::LiHelper::new(&**instance); let lifter = ILifter::new(memory, &li_helper); - let record = it_lilo_utils::lifter::record_lift_memory(&lifter, record_type, offset) + let record = it_lilo::lifter::record_lift_memory(&lifter, record_type, offset) .map_err(|e| InstructionError::from_li(instruction.clone(), e))?; log::debug!("record.lift_memory: pushing {:?} on the stack", record); @@ -111,7 +111,7 @@ where let memory_writer = ILowerer::new(&lo_helper) .map_err(|e| InstructionError::from_lo(instruction.clone(), e))?; let offset = - it_lilo_utils::lowerer::record_lower_memory(&memory_writer, record_fields) + it_lilo::lowerer::record_lower_memory(&memory_writer, record_fields) .map_err(|e| InstructionError::from_lo(instruction.clone(), e))?; log::debug!("record.lower_memory: pushing {} on the stack", offset); From 39dca73210fcae8cdc90aedd2da4edc104006e7b Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 25 Apr 2021 00:09:11 +0300 Subject: [PATCH 21/27] rename heapable to allocatable --- crates/it-lilo/src/traits/{heapable.rs => allocatable.rs} | 0 crates/it-lilo/src/traits/mod.rs | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename crates/it-lilo/src/traits/{heapable.rs => allocatable.rs} (100%) diff --git a/crates/it-lilo/src/traits/heapable.rs b/crates/it-lilo/src/traits/allocatable.rs similarity index 100% rename from crates/it-lilo/src/traits/heapable.rs rename to crates/it-lilo/src/traits/allocatable.rs diff --git a/crates/it-lilo/src/traits/mod.rs b/crates/it-lilo/src/traits/mod.rs index 8d2189a..308218b 100644 --- a/crates/it-lilo/src/traits/mod.rs +++ b/crates/it-lilo/src/traits/mod.rs @@ -14,8 +14,8 @@ * limitations under the License. */ -mod heapable; +mod allocatable; mod record_resolvable; -pub use heapable::*; +pub use allocatable::*; pub use record_resolvable::*; From 4a41d36c528c66dfb0a22c1c02cebf9d80018ea5 Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 25 Apr 2021 01:04:23 +0300 Subject: [PATCH 22/27] return error if allocate returns 0 --- crates/it-lilo/src/lowerer/error.rs | 3 +++ crates/it-lilo/src/lowerer/memory_writer.rs | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/crates/it-lilo/src/lowerer/error.rs b/crates/it-lilo/src/lowerer/error.rs index 6d1d501..f57437c 100644 --- a/crates/it-lilo/src/lowerer/error.rs +++ b/crates/it-lilo/src/lowerer/error.rs @@ -20,6 +20,9 @@ use thiserror::Error as ThisError; #[derive(Debug, ThisError)] pub enum LoError { + #[error("Allocator of Wasm module returns 0 which means that it's out of memory")] + AllocateWasInvalid, + #[error("{0}")] AllocatableError(#[from] AllocatableError), diff --git a/crates/it-lilo/src/lowerer/memory_writer.rs b/crates/it-lilo/src/lowerer/memory_writer.rs index cfad04e..c5c2e7d 100644 --- a/crates/it-lilo/src/lowerer/memory_writer.rs +++ b/crates/it-lilo/src/lowerer/memory_writer.rs @@ -21,6 +21,7 @@ use crate::traits::DEFAULT_MEMORY_INDEX; use crate::utils::type_tag_form_itype; use std::cell::Cell; +use crate::lowerer::LoError; pub struct MemoryWriter<'i, R: Allocatable> { heap_manager: &'i R, @@ -54,6 +55,10 @@ impl<'i, A: Allocatable> MemoryWriter<'i, A> { pub fn sequential_writer(&self, size: u32, type_tag: u32) -> LoResult { let offset = self.heap_manager.allocate(size, type_tag)?; + if offset == 0 { + return Err(LoError::AllocateWasInvalid); + } + let new_mem_slice = self.heap_manager.memory_slice(DEFAULT_MEMORY_INDEX)?; self.memory.set(new_mem_slice); From e8e492dd4811d969ff9ddd6a6871a770a52007df Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 25 Apr 2021 01:08:19 +0300 Subject: [PATCH 23/27] fix type tags --- crates/it-lilo/src/utils.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/it-lilo/src/utils.rs b/crates/it-lilo/src/utils.rs index 374704f..9c8b9c0 100644 --- a/crates/it-lilo/src/utils.rs +++ b/crates/it-lilo/src/utils.rs @@ -63,12 +63,12 @@ pub fn type_tag_form_itype(itype: &IType) -> u32 { IType::U16 => 2, // u16 IType::U32 => 3, // u32 IType::U64 => 4, // u64 - IType::S8 => 6, // i8 - IType::S16 => 7, // i16 - IType::S32 | IType::I32 => 8, // i32 - IType::S64 | IType::I64 => 9, // i64 - IType::F32 => 10, // f32 - IType::F64 => 11, // f64 + 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, } } @@ -82,12 +82,12 @@ pub fn type_tag_form_ivalue(itype: &IValue) -> u32 { IValue::U16(_) => 2, // u16 IValue::U32(_) => 3, // u32 IValue::U64(_) => 4, // u64 - IValue::S8(_) => 6, // i8 - IValue::S16(_) => 7, // i16 - IValue::S32(_) | IValue::I32(_) => 8, // i32 - IValue::S64(_) | IValue::I64(_) => 9, // i64 - IValue::F32(_) => 10, // f32 - IValue::F64(_) => 11, // f64 + 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 } From 27c13e9547ac55ddbc5e7a4e1ab6f1a1368075ed Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 25 Apr 2021 01:21:06 +0300 Subject: [PATCH 24/27] disable check --- crates/it-lilo/src/lowerer/error.rs | 3 --- crates/it-lilo/src/lowerer/memory_writer.rs | 3 --- 2 files changed, 6 deletions(-) diff --git a/crates/it-lilo/src/lowerer/error.rs b/crates/it-lilo/src/lowerer/error.rs index f57437c..6d1d501 100644 --- a/crates/it-lilo/src/lowerer/error.rs +++ b/crates/it-lilo/src/lowerer/error.rs @@ -20,9 +20,6 @@ use thiserror::Error as ThisError; #[derive(Debug, ThisError)] pub enum LoError { - #[error("Allocator of Wasm module returns 0 which means that it's out of memory")] - AllocateWasInvalid, - #[error("{0}")] AllocatableError(#[from] AllocatableError), diff --git a/crates/it-lilo/src/lowerer/memory_writer.rs b/crates/it-lilo/src/lowerer/memory_writer.rs index c5c2e7d..5c6f10f 100644 --- a/crates/it-lilo/src/lowerer/memory_writer.rs +++ b/crates/it-lilo/src/lowerer/memory_writer.rs @@ -55,9 +55,6 @@ impl<'i, A: Allocatable> MemoryWriter<'i, A> { pub fn sequential_writer(&self, size: u32, type_tag: u32) -> LoResult { let offset = self.heap_manager.allocate(size, type_tag)?; - if offset == 0 { - return Err(LoError::AllocateWasInvalid); - } let new_mem_slice = self.heap_manager.memory_slice(DEFAULT_MEMORY_INDEX)?; self.memory.set(new_mem_slice); From a44c433c4d0f6bce8dfddcd1ed777eb26bb3ed8e Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 25 Apr 2021 13:11:38 +0300 Subject: [PATCH 25/27] add some logs --- wasmer-it/src/interpreter/instructions/byte_arrays.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wasmer-it/src/interpreter/instructions/byte_arrays.rs b/wasmer-it/src/interpreter/instructions/byte_arrays.rs index 5ca3dff..18a6d7d 100644 --- a/wasmer-it/src/interpreter/instructions/byte_arrays.rs +++ b/wasmer-it/src/interpreter/instructions/byte_arrays.rs @@ -18,6 +18,7 @@ executable_instruction!( InstructionErrorKind::StackIsTooSmall { needed: 2 }, ) })?; + println!("byte_array lift memory: {:?}", inputs); let memory_index = 0; let memory = runtime @@ -38,10 +39,13 @@ executable_instruction!( .try_into() .map_err(|e| (e, "length").into()) .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; + + println!("byte_array lift memory: pointer {} length {}", pointer, length); + let memory_view = memory.view(); if length == 0 { - runtime.stack.push(IValue::String("".into())); + runtime.stack.push(IValue::ByteArray(vec![])); return Ok(()) } From f8aa7e061689ca5398995a986603503cd12bb6f7 Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 25 Apr 2021 13:20:12 +0300 Subject: [PATCH 26/27] make array_lower_memory work with bytearrays --- crates/it-lilo/src/lowerer/memory_writer.rs | 1 - .../src/interpreter/instructions/arrays.rs | 21 +++++++++++++++++++ .../interpreter/instructions/byte_arrays.rs | 3 --- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/crates/it-lilo/src/lowerer/memory_writer.rs b/crates/it-lilo/src/lowerer/memory_writer.rs index 5c6f10f..722b52f 100644 --- a/crates/it-lilo/src/lowerer/memory_writer.rs +++ b/crates/it-lilo/src/lowerer/memory_writer.rs @@ -21,7 +21,6 @@ use crate::traits::DEFAULT_MEMORY_INDEX; use crate::utils::type_tag_form_itype; use std::cell::Cell; -use crate::lowerer::LoError; pub struct MemoryWriter<'i, R: Allocatable> { heap_manager: &'i R, diff --git a/wasmer-it/src/interpreter/instructions/arrays.rs b/wasmer-it/src/interpreter/instructions/arrays.rs index 30867e9..96cc728 100644 --- a/wasmer-it/src/interpreter/instructions/arrays.rs +++ b/wasmer-it/src/interpreter/instructions/arrays.rs @@ -134,6 +134,27 @@ where Ok(()) } + IValue::ByteArray(bytearray) => { + let lo_helper = lilo::LoHelper::new(&**instance); + let lowerer = ILowerer::new(&lo_helper) + .map_err(|e| InstructionError::from_lo(instruction.clone(), e))?; + + let offset = lowerer + .writer + .write_bytes(&bytearray) + .map_err(|e| InstructionError::from_lo(instruction.clone(), e))?; + let size = bytearray.len(); + + log::trace!( + "array.lower_memory: pushing bytes {}, {} on the stack", + offset, + size + ); + runtime.stack.push(IValue::I32(offset as _)); + runtime.stack.push(IValue::I32(size as _)); + + Ok(()) + } _ => instr_error!( instruction.clone(), InstructionErrorKind::InvalidValueOnTheStack { diff --git a/wasmer-it/src/interpreter/instructions/byte_arrays.rs b/wasmer-it/src/interpreter/instructions/byte_arrays.rs index 18a6d7d..a7aa715 100644 --- a/wasmer-it/src/interpreter/instructions/byte_arrays.rs +++ b/wasmer-it/src/interpreter/instructions/byte_arrays.rs @@ -18,7 +18,6 @@ executable_instruction!( InstructionErrorKind::StackIsTooSmall { needed: 2 }, ) })?; - println!("byte_array lift memory: {:?}", inputs); let memory_index = 0; let memory = runtime @@ -40,8 +39,6 @@ executable_instruction!( .map_err(|e| (e, "length").into()) .map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?; - println!("byte_array lift memory: pointer {} length {}", pointer, length); - let memory_view = memory.view(); if length == 0 { From 7f049c0551fce18dc9e106d0f2b1ff3bdd909280 Mon Sep 17 00:00:00 2001 From: vms Date: Mon, 26 Apr 2021 00:35:31 +0300 Subject: [PATCH 27/27] fix bug with byte arrays --- crates/it-lilo/src/lifter/lift_array.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/it-lilo/src/lifter/lift_array.rs b/crates/it-lilo/src/lifter/lift_array.rs index 12a82a4..01de7cd 100644 --- a/crates/it-lilo/src/lifter/lift_array.rs +++ b/crates/it-lilo/src/lifter/lift_array.rs @@ -49,7 +49,7 @@ pub fn array_lift_memory( IType::F32 => reader.read_f32_array(offset, elements_count)?, IType::F64 => reader.read_f64_array(offset, elements_count)?, IType::String => read_string_array(lifter, offset, elements_count)?, - IType::ByteArray => read_array_array(lifter, &IType::ByteArray, offset, elements_count)?, + IType::ByteArray => read_array_array(lifter, &IType::U8, offset, elements_count)?, IType::Array(ty) => read_array_array(lifter, &ty, offset, elements_count)?, IType::Record(record_type_id) => { read_record_array(lifter, *record_type_id, offset, elements_count)?