From 5d219e963b110b7ee7e6fb10a189a5a5eb788552 Mon Sep 17 00:00:00 2001 From: vms Date: Tue, 20 Apr 2021 23:39:16 +0300 Subject: [PATCH] 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;