refactoring

This commit is contained in:
vms 2021-04-24 21:55:14 +03:00
parent 6116c5c252
commit cc44e387f7
24 changed files with 704 additions and 450 deletions

24
Cargo.lock generated
View File

@ -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"

View File

@ -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<T> = std::result::Result<T, error::MemoryAccessError>;
pub type WriteResult<T> = std::result::Result<T, error::MemoryWriteError>;
/// 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
}
}
}

View File

@ -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),
}

View File

@ -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<R: RecordResolvable>(
lifter: &ILifter<'_, '_, R>,
value_type: &IType,
offset: usize,
elements_count: usize,
) -> LiLoResult<IValue> {
) -> LiResult<IValue> {
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<String> => Vec<u32> (2 * len of prev)
fn read_string_array(
li_helper: &LiHelper,
fn read_string_array<R: RecordResolvable>(
lifter: &ILifter<'_, '_, R>,
offset: usize,
elements_count: usize,
) -> LiLoResult<Vec<IValue>> {
) -> LiResult<Vec<IValue>> {
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<R: RecordResolvable>(
lifter: &ILifter<'_, '_, R>,
ty: &IType,
offset: usize,
elements_count: usize,
) -> LiLoResult<Vec<IValue>> {
) -> LiResult<Vec<IValue>> {
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<R: RecordResolvable>(
lifter: &ILifter<'_, '_, R>,
record_type_id: u64,
offset: usize,
elements_count: usize,
) -> LiLoResult<Vec<IValue>> {
) -> LiResult<Vec<IValue>> {
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);
}

View File

@ -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<R: RecordResolvable>(
lifter: &ILifter<'_, '_, R>,
record_type: &IRecordType,
offset: usize,
) -> LiLoResult<IValue> {
) -> LiResult<IValue> {
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<String> {
fn read_string(
reader: &MemoryReader<'_>,
seq_reader: &SequentialReader<'_, '_>,
) -> LiResult<String> {
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<IValue> {
fn read_byte_array(
reader: &MemoryReader<'_>,
seq_reader: &SequentialReader<'_, '_>,
) -> LiResult<IValue> {
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<R: RecordResolvable>(
lifter: &ILifter<'_, '_, R>,
seq_reader: &SequentialReader<'_, '_>,
value_type: &IType,
) -> LiLoResult<IValue> {
) -> LiResult<IValue> {
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<R: RecordResolvable>(
lifter: &ILifter<'_, '_, R>,
seq_reader: &SequentialReader<'_, '_>,
record_type_id: u64,
) -> LiLoResult<IValue> {
) -> LiResult<IValue> {
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 _)
}

View File

@ -101,7 +101,7 @@ macro_rules! read_array_ty {
&self,
offset: usize,
elements_count: usize,
) -> crate::ReadResult<Vec<crate::IValue>> {
) -> super::LiResult<Vec<crate::IValue>> {
let reader =
self.sequential_reader(offset, std::mem::size_of::<$ty>() * elements_count)?;
let mut result = Vec::with_capacity(elements_count);

View File

@ -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<SequentialReader<'_, '_>> {
) -> LiResult<SequentialReader<'_, '_>> {
self.check_access(offset, size)?;
Ok(SequentialReader::new(&self, offset))
}
pub fn read_raw_u8_array(&self, offset: usize, elements_count: usize) -> ReadResult<Vec<u8>> {
pub fn read_raw_u8_array(&self, offset: usize, elements_count: usize) -> LiResult<Vec<u8>> {
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<Vec<IValue>> {
pub fn read_bool_array(&self, offset: usize, elements_count: usize) -> LiResult<Vec<IValue>> {
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(),

View File

@ -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<T> = std::result::Result<T, error::LiError>;
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<u8>], resolver: &'r R) -> Self {
let reader = MemoryReader::new(memory);
Self { reader, resolver }
}
}

View File

@ -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),
}

View File

@ -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<A: Allocatable>(
lowerer: &ILowerer<'_, A>,
array_values: Vec<IValue>,
) -> LoResult<LoweredArray> {
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)
}

View File

@ -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<T: Heapable>(
writer: &MemoryWriter<T>,
pub fn record_lower_memory<A: Allocatable>(
lowerer: &ILowerer<'_, A>,
values: NEVec<IValue>,
) -> WriteResult<i32> {
) -> LoResult<i32> {
let average_field_size = 4;
// TODO: avoid this additional allocation after fixing github.com/fluencelabs/fce/issues/77
let mut result: Vec<u8> = 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<T: Heapable>(
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 _)
}

View File

@ -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<u8>];
const MEMORY_INDEX: usize = 0;
pub trait Heapable {
fn allocate(&self, size: u32, type_tag: u32) -> WriteResult<usize>;
fn memory_slice(&self, memory_index: usize) -> WriteResult<MemSlice<'_>>;
}
pub struct MemoryWriter<'i, T: Heapable> {
heap_manager: &'i T,
pub struct MemoryWriter<'i, R: Allocatable> {
heap_manager: &'i R,
pub(self) memory: Cell<MemSlice<'i>>,
}
@ -37,9 +32,9 @@ pub struct SequentialWriter {
offset: Cell<usize>,
}
impl<'i, T: Heapable> MemoryWriter<'i, T> {
pub fn new(heap_manager: &'i T) -> WriteResult<Self> {
let mem_slice = heap_manager.memory_slice(MEMORY_INDEX)?;
impl<'i, A: Allocatable> MemoryWriter<'i, A> {
pub fn new(heap_manager: &'i A) -> LoResult<Self> {
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<usize> {
let byte_type_tag = crate::type_tag_form_itype(&crate::IType::U8);
pub fn write_bytes(&self, bytes: &[u8]) -> LoResult<usize> {
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<SequentialWriter> {
pub fn sequential_writer(&self, size: u32, type_tag: u32) -> LoResult<SequentialWriter> {
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<T: Heapable, const N: usize>(
pub fn write_array<A: Allocatable, const N: usize>(
&self,
writer: &MemoryWriter<T>,
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<T: Heapable>(&self, writer: &MemoryWriter<T>, value: u8) {
pub fn write_u8<A: Allocatable>(&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<T: Heapable>(&self, writer: &MemoryWriter<T>, value: u32) {
pub fn write_u32<A: Allocatable>(&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<T: Heapable>(&self, writer: &MemoryWriter<T>, bytes: &[u8]) {
pub fn write_bytes<A: Allocatable>(&self, writer: &MemoryWriter<'_, A>, bytes: &[u8]) {
let offset = self.offset.get();
let memory = writer.memory.get();

View File

@ -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<T> = std::result::Result<T, error::LoError>;
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<Self> {
let writer = MemoryWriter::new(allocatable)?;
let lowerer = Self { writer };
Ok(lowerer)
}
}

View File

@ -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<u8>];
pub trait Allocatable {
fn allocate(&self, size: u32, type_tag: u32) -> Result<usize, AllocatableError>;
fn memory_slice(&self, memory_index: usize) -> Result<MemSlice<'_>, 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),
}

View File

@ -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::*;

View File

@ -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),
}

View File

@ -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
}
}
}

View File

@ -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),
}

View File

@ -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",

View File

@ -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<T: Heapable>(
writer: &MemoryWriter<T>,
array_values: Vec<IValue>,
) -> 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 _))
}

View File

@ -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, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
memory: &'instance [Cell<u8>],
) -> LiLoResult<Self>
where
Export: wasm::structures::Export + 'instance,
LocalImport: wasm::structures::LocalImport + 'instance,
Memory: wasm::structures::Memory<MemoryView> + 'instance,
MemoryView: wasm::structures::MemoryView,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
let record_resolver = build_record_resolver(instance)?;
let reader = MemoryReader::new(memory);
let helper = Self {
reader,
record_resolver,
};
Ok(helper)
}
}
pub(crate) type RecordResolver<'i> = Box<dyn Fn(u64) -> LiLoResult<Rc<IRecordType>> + 'i>;
pub(super) fn build_record_resolver<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
) -> LiLoResult<RecordResolver<'instance>>
pub struct LiHelper<'i, Instance, Export, LocalImport, Memory, MemoryView>
where
Export: wasm::structures::Export + 'instance,
LocalImport: wasm::structures::LocalImport + 'instance,
Memory: wasm::structures::Memory<MemoryView> + 'instance,
Export: wasm::structures::Export + 'i,
LocalImport: wasm::structures::LocalImport + 'i,
Memory: wasm::structures::Memory<MemoryView> + 'i,
MemoryView: wasm::structures::MemoryView,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
let resolver = move |record_type_id: u64| {
let record = instance
.wit_record_by_id(record_type_id)
.ok_or(LiLoError::RecordTypeByNameIsMissing { record_type_id })?;
Ok(record.clone())
};
Ok(Box::new(resolver))
pub(crate) instance: &'i Instance,
_export: PhantomData<Export>,
_local_import: PhantomData<LocalImport>,
_memory: PhantomData<Memory>,
_memory_view: PhantomData<MemoryView>,
}
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<MemoryView> + 'i,
MemoryView: wasm::structures::MemoryView,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
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<MemoryView> + 'i,
MemoryView: wasm::structures::MemoryView,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
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)
}
}

View File

@ -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<Export, LocalImport, Memory, MemoryView>,
{
pub(crate) instance: &'i Instance,
_phantom_export: PhantomData<Export>,
_phantom_local_import: PhantomData<LocalImport>,
_phantom_memory: PhantomData<Memory>,
_phantom_memory_view: PhantomData<MemoryView>,
_export: PhantomData<Export>,
_local_import: PhantomData<LocalImport>,
_memory: PhantomData<Memory>,
_memory_view: PhantomData<MemoryView>,
}
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<Export, LocalImport, Memory, MemoryView>,
{
fn allocate(&self, size: u32, type_tag: u32) -> WriteResult<usize> {
fn allocate(&self, size: u32, type_tag: u32) -> Result<usize, AllocatableError> {
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<u8>]> {
fn memory_slice(&self, memory_index: usize) -> Result<MemSlice<'_>, AllocatableError> {
self.instance
.memory_slice(memory_index)
.ok_or(MemoryWriteError::MemoryIsMissing { memory_index })
.ok_or(AllocatableError::MemoryIsMissing { memory_index })
}
}

View File

@ -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<T> = std::result::Result<T, LiLoError>;

View File

@ -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<Instance, Export, LocalImport, Memory, MemoryView>(
@ -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));