From cc44e387f7aa0ec4dc3372eddc09a1475e155f49 Mon Sep 17 00:00:00 2001 From: vms Date: Sat, 24 Apr 2021 21:55:14 +0300 Subject: [PATCH] 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));