to save it

This commit is contained in:
vms 2021-04-20 23:39:16 +03:00
parent 2c40ced55d
commit 5d219e963b
18 changed files with 551 additions and 236 deletions

36
Cargo.lock generated
View File

@ -36,6 +36,15 @@ dependencies = [
"wast",
]
[[package]]
name = "it-lilo-utils"
version = "0.1.0"
dependencies = [
"fluence-it-types",
"paste",
"thiserror",
]
[[package]]
name = "it-to-bytes"
version = "0.1.0"
@ -100,6 +109,12 @@ dependencies = [
"version_check",
]
[[package]]
name = "paste"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58"
[[package]]
name = "pest"
version = "2.1.3"
@ -205,6 +220,26 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "thiserror"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "ucd-trie"
version = "0.1.3"
@ -228,6 +263,7 @@ name = "wasmer-interface-types-fl"
version = "0.20.0"
dependencies = [
"fluence-it-types",
"it-lilo-utils",
"it-to-bytes",
"itertools",
"log",

View File

@ -1,5 +1,6 @@
[workspace]
members = [
"crates/it-lilo-utils",
"crates/to-bytes",
"crates/it-types",
"wasmer-it",

View File

@ -0,0 +1,17 @@
[package]
name = "it-lilo-utils"
version = "0.1.0"
authors = ["Fluence Labs"]
description = "Defines some helper utils for lifting/lowering IT"
edition = "2018"
license = "Apache-2.0"
[lib]
name = "it_lilo_utils"
path = "src/lib.rs"
[dependencies]
fluence-it-types = { path = "../it-types/", version = "0.2.0" }
paste = "1.0.5"
thiserror = "1.0.24"

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

View File

@ -0,0 +1,7 @@
pub mod error;
pub mod memory_reader;
pub mod memory_writer;
pub use fluence_it_types::IValue;
pub type MResult<T> = std::result::Result<T, error::MemoryAccessError>;

View File

@ -0,0 +1,213 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::error::MemoryAccessError;
use crate::IValue;
use crate::MResult;
use std::cell::Cell;
pub struct MemoryReader<'m> {
pub(self) memory: &'m [Cell<u8>],
}
/// Reads values of basic types sequentially from the provided reader.
/// It don't check memory limits for the optimization purposes,
/// so it could created by the MemoryReader::sequential_reader method.
pub struct SequentialReader<'r, 'm> {
reader: &'r MemoryReader<'m>,
offset: Cell<usize>,
}
macro_rules! value_der {
($self:expr, $offset:expr, @seq_start $($ids:tt),* @seq_end) => {
[$($self.reader.memory[$offset + $ids].get()),+]
};
($self:expr, $offset:expr, 1) => {
value_der!($self, $offset, @seq_start 0 @seq_end);
};
($self:expr, $offset:expr, 2) => {
value_der!($self, $offset, @seq_start 0, 1 @seq_end);
};
($self:expr, $offset:expr, 4) => {
value_der!($self, $offset, @seq_start 0, 1, 2, 3 @seq_end);
};
($self:expr, $offset:expr, 8) => {
value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7 @seq_end);
};
}
macro_rules! read_ty {
($func_name:ident, $ty:ty, 1) => {
pub fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(value_der!(self, offset, 1));
self.offset.set(offset + 1);
result
}
};
($func_name:ident, $ty:ty, 2) => {
pub fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(value_der!(self, offset, 2));
self.offset.set(offset + 2);
result
}
};
($func_name:ident, $ty:ty, 4) => {
pub fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(value_der!(self, offset, 4));
self.offset.set(offset + 4);
result
}
};
($func_name:ident, $ty:ty, 8) => {
pub fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(value_der!(self, offset, 8));
self.offset.set(offset + 8);
result
}
};
}
macro_rules! read_array_ty {
($func_name:ident, $ty:ident, $ity:ident) => {
pub fn $func_name(
&self,
offset: usize,
elements_count: usize,
) -> crate::MResult<Vec<crate::IValue>> {
let reader =
self.sequential_reader(offset, std::mem::size_of::<$ty>() * elements_count)?;
let mut result = Vec::with_capacity(elements_count);
for _ in 0..elements_count {
let value = paste::paste! { reader.[<read_ $ty>]()};
result.push(IValue::$ity(value));
}
Ok(result)
}
};
}
impl<'m> MemoryReader<'m> {
pub fn new(memory: &'m [Cell<u8>]) -> Self {
Self { memory }
}
/// Returns reader that allows read sequentially. It's important that memory limit is checked
/// only inside this function. All others functions of the returned reader don't have any
/// checks assuming that reader is well-formed.
pub fn sequential_reader(
&self,
offset: usize,
size: usize,
) -> MResult<SequentialReader<'_, '_>> {
self.check_access(offset, size)?;
Ok(SequentialReader::new(&self, offset))
}
pub fn read_raw_u8_array(&self, offset: usize, elements_count: usize) -> MResult<Vec<u8>> {
let reader = self.sequential_reader(offset, elements_count)?;
let mut result = Vec::with_capacity(elements_count);
for _ in 0..elements_count {
let value = reader.read_u8();
result.push(value);
}
Ok(result)
}
pub fn read_bool_array(&self, offset: usize, elements_count: usize) -> MResult<Vec<IValue>> {
let reader = self.sequential_reader(offset, elements_count)?;
let mut result = Vec::with_capacity(elements_count);
for _ in 0..elements_count {
let value = reader.read_u8();
result.push(IValue::Boolean(value != 0));
}
Ok(result)
}
pub fn check_access(&self, offset: usize, size: usize) -> MResult<()> {
let right = offset + size;
if right < offset || right >= self.memory.len() {
return Err(MemoryAccessError::InvalidAccess {
offset,
size,
memory_size: self.memory.len(),
});
}
Ok(())
}
read_array_ty!(read_u8_array, u8, U8);
read_array_ty!(read_s8_array, i8, S8);
read_array_ty!(read_u16_array, u16, U16);
read_array_ty!(read_s16_array, i16, S16);
read_array_ty!(read_u32_array, u32, U32);
read_array_ty!(read_s32_array, i32, S32);
read_array_ty!(read_i32_array, i32, I32);
read_array_ty!(read_f32_array, f32, F32);
read_array_ty!(read_u64_array, u64, U64);
read_array_ty!(read_s64_array, i64, S64);
read_array_ty!(read_i64_array, i64, I64);
read_array_ty!(read_f64_array, f64, F64);
}
impl<'r, 'm> SequentialReader<'r, 'm> {
pub(self) fn new(reader: &'r MemoryReader<'m>, offset: usize) -> Self {
let offset = Cell::new(offset);
Self { reader, offset }
}
pub fn read_bool(&self) -> bool {
let offset = self.offset.get();
let result = self.reader.memory[offset].get() != 0;
self.offset.set(offset + 1);
result
}
read_ty!(read_u8, u8, 1);
read_ty!(read_i8, i8, 1);
read_ty!(read_u16, u16, 2);
read_ty!(read_i16, i16, 2);
read_ty!(read_u32, u32, 4);
read_ty!(read_i32, i32, 4);
read_ty!(read_f32, f32, 4);
read_ty!(read_u64, u64, 8);
read_ty!(read_i64, i64, 8);
read_ty!(read_f64, f64, 8);
}

View File

@ -0,0 +1,149 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::MResult;
use crate::error::MemoryAccessError;
use std::cell::Cell;
pub struct MemoryWriter<'m> {
memory: &'m [Cell<u8>],
}
/// Writes values of basic types sequentially to the provided writer.
/// It don't check memory limits for the optimization purposes,
/// so it could created by the MemoryReader::sequential_reader method.
pub struct SequentialWriter<'w, 'm> {
writer: &'w MemoryWriter<'m>,
offset: Cell<usize>,
}
impl<'m> MemoryWriter<'m> {
pub fn new(memory: &'m [Cell<u8>]) -> Self {
Self { memory }
}
pub fn write_array<const N: usize>(&self, offset: usize, values: [u8; N]) -> MResult<()> {
self.check_access(offset, values.len())?;
self.memory[offset..offset + N]
.iter()
.zip(values.iter())
.for_each(|(cell, &byte)| cell.set(byte));
Ok(())
}
// specialization of write_array for u8
pub fn write_u8(&self, offset: usize, value: u8) -> MResult<()> {
self.check_access(offset, 1)?;
self.memory[offset].set(value);
Ok(())
}
// specialization of write_array for u32
pub fn write_u32(&self, offset: usize, value: u32) -> MResult<()> {
self.check_access(offset, 4)?;
let value = value.to_le_bytes();
self.memory[offset].set(value[0]);
self.memory[offset + 1].set(value[1]);
self.memory[offset + 2].set(value[2]);
self.memory[offset + 3].set(value[3]);
Ok(())
}
pub fn write_bytes(&self, offset: usize, bytes: &[u8]) -> MResult<()> {
let writer = self.sequential_writer(offset, bytes.len())?;
writer.write_bytes(bytes);
Ok(())
}
pub fn sequential_writer(&self, offset: usize, size: usize) -> MResult<SequentialWriter<'_, '_>> {
self.check_access(offset, size)?;
Ok(SequentialWriter::new(&self, offset))
}
pub fn check_access(&self, offset: usize, size: usize) -> MResult<()> {
let right = offset + size;
if right < offset || right >= self.memory.len() {
return Err(MemoryAccessError::InvalidAccess {
offset,
size,
memory_size: self.memory.len(),
});
}
Ok(())
}
}
impl<'w, 'm> SequentialWriter<'w, 'm> {
pub(super) fn new(writer: &'w MemoryWriter<'m>, offset: usize) -> Self {
let offset = Cell::new(offset);
Self { writer, offset }
}
pub fn write_array<const N: usize>(&self, values: [u8; N]) {
let offset = self.offset.get();
self.writer.memory[offset..offset + N]
.iter()
.zip(values.iter())
.for_each(|(cell, &byte)| cell.set(byte));
self.offset.set(offset + N);
}
// specialization of write_array for u8
pub fn write_u8(&self, value: u8) {
let offset = self.offset.get();
self.writer.memory[offset].set(value);
self.offset.set(offset + 1);
}
// specialization of write_array for u32
pub fn write_u32(&self, value: u32) {
let offset = self.offset.get();
let value = value.to_le_bytes();
self.writer.memory[offset].set(value[0]);
self.writer.memory[offset + 1].set(value[1]);
self.writer.memory[offset + 2].set(value[2]);
self.writer.memory[offset + 3].set(value[3]);
self.offset.set(offset + 4);
}
#[allow(dead_code)]
pub fn write_bytes(&self, bytes: &[u8]) {
let offset = self.offset.get();
self.writer.memory[offset..offset + bytes.len()]
.iter()
.zip(bytes)
.for_each(|(cell, &byte)| cell.set(byte));
self.offset.set(offset + bytes.len());
}
}

View File

@ -6,6 +6,10 @@ authors = ["Fluence Labs"]
edition = "2018"
license = "Apache-2.0"
[lib]
name = "fluence_it_types"
path = "src/lib.rs"
[dependencies]
it-to-bytes = { path = "../to-bytes/", version = "0.1.0" }

View File

@ -5,3 +5,7 @@ authors = ["Fluence Labs"]
description = "Defines trait ToBytes used for IT serialization"
edition = "2018"
license = "Apache-2.0"
[lib]
name = "it_to_bytes"
path = "src/lib.rs"

View File

@ -10,6 +10,7 @@ edition = "2018"
[dependencies]
fluence-it-types = { path = "../crates/it-types", version = "0.2.0", features = ["impls"] }
it-to-bytes = { path = "../crates/to-bytes", version = "0.1.0" }
it-lilo-utils = { path = "../crates/it-lilo-utils", version = "0.1.0" }
nom = "5.1"
wast = "8.0"
@ -23,6 +24,7 @@ safe-transmute = "0.11.0"
log = "0.4.11"
itertools = "0.10.0"
thiserror = "1.0.24"
semver = "0.11.0"
[features]

View File

@ -24,7 +24,8 @@ where
return Ok((0, 0));
}
let size_to_allocate = ser_value_size(&array_values[0]) * array_values.len();
let elements_count = array_values.len();
let size_to_allocate = ser_value_size(&array_values[0]) * elements_count;
let offset = super::allocate(instance, instruction.clone(), size_to_allocate)?;
let memory_index = 0;
@ -88,7 +89,7 @@ where
}
}
Ok((offset as _, writer.written_values() as _))
Ok((offset as _, elements_count as _))
}
/// Size of a value in a serialized view.

View File

@ -3,18 +3,15 @@ use std::cell::Cell;
pub(super) struct MemoryWriter<'m> {
memory_view: &'m [Cell<u8>],
offset: Cell<usize>,
written_values: Cell<usize>,
}
impl<'m> MemoryWriter<'m> {
pub(crate) fn new(memory_view: &'m [Cell<u8>], offset: usize) -> Self {
let offset = Cell::new(offset);
let written_values = Cell::new(0);
Self {
memory_view,
offset,
written_values,
}
}
@ -22,7 +19,6 @@ impl<'m> MemoryWriter<'m> {
let offset = self.offset.get();
self.memory_view[offset].set(value);
self.offset.set(offset + 1);
self.update_counter();
}
#[allow(dead_code)]
@ -36,7 +32,6 @@ impl<'m> MemoryWriter<'m> {
}
self.offset.set(offset + values.len());
self.update_counter();
}
pub(crate) fn write_array<const N: usize>(&self, values: [u8; N]) {
@ -49,15 +44,5 @@ impl<'m> MemoryWriter<'m> {
}
self.offset.set(offset + values.len());
self.update_counter();
}
fn update_counter(&self) {
let written_values_count = self.written_values.get();
self.written_values.set(written_values_count + 1);
}
pub(crate) fn written_values(&self) -> usize {
self.written_values.get()
}
}

View File

@ -1,12 +1,15 @@
mod error;
mod lift_record;
mod lower_record;
mod value_reader;
pub use lift_record::record_size;
pub(crate) use lift_record::record_lift_memory_impl;
pub(crate) use lower_record::record_lower_memory_impl;
pub(self) use error::LiLoRecordError;
pub(self) type LiLoResult<T> = std::result::Result<T, LiLoRecordError>;
use super::array_lift_memory_impl;
use super::array_lower_memory_impl;
use super::read_from_instance_mem;

View File

@ -0,0 +1,17 @@
use it_lilo_utils::error::MemoryAccessError;
use thiserror::Error as ThisError;
#[derive(Debug, ThisError)]
pub(crate) enum LiLoRecordError {
/// This error occurred from out-of-bound memory access.
#[error("{0}")]
MemoryAccessError(#[from] MemoryAccessError),
/// An error related to not found record in module record types.
#[error("Record with type id {0} not found")]
RecordTypeNotFound(u64),
/// This error occurred when a record is created from empty values array.
#[error("Record with name '{0}' can't be empty")]
EmptyRecord(String),
}

View File

@ -1,6 +1,6 @@
use super::read_from_instance_mem;
use super::LiLoRecordError;
use super::LiLoResult;
use super::value_reader::ValueReader;
use crate::IRecordType;
use crate::IType;
use crate::IValue;
@ -10,52 +10,46 @@ use crate::{
interpreter::Instruction,
};
use it_lilo_utils::memory_reader::MemoryReader;
use it_lilo_utils::memory_reader::SequentialReader;
#[rustfmt::skip]
pub(crate) fn record_lift_memory_impl<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
pub(crate) fn record_lift_memory_impl(
reader: &MemoryReader<'_>,
record_type: &IRecordType,
offset: usize,
instruction: Instruction,
) -> Result<IValue, InstructionError>
where
Export: crate::interpreter::wasm::structures::Export,
LocalImport: crate::interpreter::wasm::structures::LocalImport,
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
MemoryView: crate::interpreter::wasm::structures::MemoryView,
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView> + 'instance,
{
) -> LiLoResult<IValue> {
let mut values = Vec::with_capacity(record_type.fields.len());
let size = record_size(record_type);
let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?;
let reader = ValueReader::new(data);
let seq_reader = reader.sequential_reader(offset, size)?;
for field in (*record_type.fields).iter() {
match &field.ty {
IType::Boolean => values.push(IValue::Boolean(reader.read_u8() != 0)),
IType::S8 => values.push(IValue::S8(reader.read_i8())),
IType::S16 => values.push(IValue::S16(reader.read_i16())),
IType::S32 => values.push(IValue::S32(reader.read_i32())),
IType::S64 => values.push(IValue::S64(reader.read_i64())),
IType::I32 => values.push(IValue::I32(reader.read_i32())),
IType::I64 => values.push(IValue::I64(reader.read_i64())),
IType::U8 => values.push(IValue::U8(reader.read_u8())),
IType::U16 => values.push(IValue::U16(reader.read_u16())),
IType::U32 => values.push(IValue::U32(reader.read_u32())),
IType::U64 => values.push(IValue::U64(reader.read_u64())),
IType::F32 => values.push(IValue::F32(reader.read_f32())),
IType::F64 => values.push(IValue::F64(reader.read_f64())),
IType::String => values.push(IValue::String(read_string(instance, instruction.clone(), &reader)?)),
IType::ByteArray => values.push(read_byte_array(instance, instruction.clone(), &reader)?),
IType::Array(ty) => values.push(read_array(instance, instruction.clone(), &reader, &**ty)?),
IType::Record(record_type_id) => values.push(read_record(instance, instruction.clone(), &reader, *record_type_id)?),
IType::Boolean => values.push(IValue::Boolean(seq_reader.read_u8() != 0)),
IType::S8 => values.push(IValue::S8(seq_reader.read_i8())),
IType::S16 => values.push(IValue::S16(seq_reader.read_i16())),
IType::S32 => values.push(IValue::S32(seq_reader.read_i32())),
IType::S64 => values.push(IValue::S64(seq_reader.read_i64())),
IType::I32 => values.push(IValue::I32(seq_reader.read_i32())),
IType::I64 => values.push(IValue::I64(seq_reader.read_i64())),
IType::U8 => values.push(IValue::U8(seq_reader.read_u8())),
IType::U16 => values.push(IValue::U16(seq_reader.read_u16())),
IType::U32 => values.push(IValue::U32(seq_reader.read_u32())),
IType::U64 => values.push(IValue::U64(seq_reader.read_u64())),
IType::F32 => values.push(IValue::F32(seq_reader.read_f32())),
IType::F64 => values.push(IValue::F64(seq_reader.read_f64())),
IType::String => values.push(IValue::String(read_string(reader, &seq_reader)?)),
IType::ByteArray => values.push(read_byte_array(reader, &seq_reader)?),
IType::Array(ty) => values.push(read_array(&reader, &seq_reader, &**ty)?),
IType::Record(record_type_id) => values.push(read_record(&reader, &seq_reader, *record_type_id)?),
}
}
Ok(IValue::Record(
NEVec::new(values.into_iter().collect())
.expect("Record must have at least one field, zero given"),
))
let record = NEVec::new(values.into_iter().collect())
.map_err(|_| LiLoRecordError::EmptyRecord(record_type.name.clone()))?;
Ok(IValue::Record(record))
}
/// Returns the record size in bytes.
@ -76,28 +70,11 @@ pub fn record_size(record_type: &IRecordType) -> usize {
record_size
}
fn read_string<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &Instance,
instruction: Instruction,
reader: &ValueReader,
) -> Result<String, InstructionError>
where
Export: crate::interpreter::wasm::structures::Export,
LocalImport: crate::interpreter::wasm::structures::LocalImport,
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
MemoryView: crate::interpreter::wasm::structures::MemoryView,
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>
+ 'instance,
{
let string_offset = reader.read_u32();
let string_size = reader.read_u32();
fn read_string(reader: &MemoryReader, seq_reader: &SequentialReader) -> LiLoResult<String> {
let offset = seq_reader.read_u32();
let size = seq_reader.read_u32();
let string_mem = read_from_instance_mem(
instance,
instruction.clone(),
string_offset as _,
string_size as _,
)?;
let string_mem = reader.read_raw_u8_array(offset as _, size as _)?;
let string = String::from_utf8(string_mem).map_err(|e| {
InstructionError::new(instruction, InstructionErrorKind::CorruptedUTF8String(e))
@ -106,69 +83,32 @@ where
Ok(string)
}
fn read_byte_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &Instance,
instruction: Instruction,
reader: &ValueReader,
) -> Result<IValue, InstructionError>
where
Export: crate::interpreter::wasm::structures::Export,
LocalImport: crate::interpreter::wasm::structures::LocalImport,
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
MemoryView: crate::interpreter::wasm::structures::MemoryView,
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>
+ 'instance,
{
let offset = reader.read_u32();
let elements_count = reader.read_u32();
fn read_byte_array(reader: &MemoryReader, seq_reader: &SequentialReader) -> LiLoResult<IValue> {
let offset = seq_reader.read_u32();
let size = seq_reader.read_u32();
let array = read_from_instance_mem(instance, instruction, offset as _, elements_count as _)?;
let byte_array = IValue::ByteArray(array);
let array = reader.read_raw_u8_array(offset as _, size as _)?;
Ok(byte_array)
Ok(IValue::ByteArray(array))
}
fn read_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &Instance,
instruction: Instruction,
reader: &ValueReader,
ty: &IType,
) -> Result<IValue, InstructionError>
where
Export: crate::interpreter::wasm::structures::Export,
LocalImport: crate::interpreter::wasm::structures::LocalImport,
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
MemoryView: crate::interpreter::wasm::structures::MemoryView,
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>
+ 'instance,
{
let array_offset = reader.read_u32();
let elements_count = reader.read_u32();
fn read_array(
reader: &MemoryReader,
seq_reader: &SequentialReader,
value_type: &IType,
) -> LiLoResult<IValue> {
let offset = seq_reader.read_u32();
let size = seq_reader.read_u32();
super::array_lift_memory_impl(
instance,
ty,
array_offset as _,
elements_count as _,
instruction,
)
super::array_lift_memory_impl(reader, value_type, offset as _, size as _)
}
fn read_record<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &Instance,
instruction: Instruction,
reader: &ValueReader,
fn read_record(
reader: &MemoryReader,
seq_reader: &SequentialReader,
record_type_id: u64,
) -> Result<IValue, InstructionError>
where
Export: crate::interpreter::wasm::structures::Export,
LocalImport: crate::interpreter::wasm::structures::LocalImport,
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
MemoryView: crate::interpreter::wasm::structures::MemoryView,
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>
+ 'instance,
{
let offset = reader.read_u32();
) -> LiLoResult<IValue> {
let offset = seq_reader.read_u32();
let record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| {
InstructionError::new(
@ -177,5 +117,5 @@ where
)
})?;
record_lift_memory_impl(instance, record_type, offset as _, instruction)
record_lift_memory_impl(reader, record_type, offset as _)
}

View File

@ -1,23 +1,17 @@
use super::write_to_instance_mem;
use super::LiLoResult;
use super::LiLoRecordError;
use crate::IValue;
use crate::NEVec;
use crate::{errors::InstructionError, interpreter::Instruction};
pub(crate) fn record_lower_memory_impl<Instance, Export, LocalImport, Memory, MemoryView>(
instance: &mut Instance,
instruction: Instruction,
use it_lilo_utils::memory_writer::MemoryWriter;
pub(crate) fn record_lower_memory_impl(
writer: &MemoryWriter,
values: NEVec<IValue>,
) -> Result<i32, InstructionError>
where
Export: crate::interpreter::wasm::structures::Export,
LocalImport: crate::interpreter::wasm::structures::LocalImport,
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
MemoryView: crate::interpreter::wasm::structures::MemoryView,
Instance:
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
let mut result: Vec<u8> = Vec::with_capacity(values.len());
) -> LiLoResult<i32> {
let average_field_size = 4;
let mut result: Vec<u8> = Vec::with_capacity(average_field_size * values.len());
for value in values.into_vec() {
match value {
@ -35,10 +29,10 @@ where
IValue::F32(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::F64(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::String(value) => {
let string_pointer =
let offset =
write_to_instance_mem(instance, instruction.clone(), value.as_bytes())? as u32;
result.extend_from_slice(&string_pointer.to_le_bytes());
result.extend_from_slice(&offset.to_le_bytes());
result.extend_from_slice(&(value.len() as u32).to_le_bytes());
}
IValue::ByteArray(value) => {

View File

@ -1,88 +0,0 @@
use std::cell::Cell;
pub(super) struct ValueReader {
stream: Vec<u8>,
offset: Cell<usize>,
}
macro_rules! value_der {
($self:expr, $offset:expr, @seq_start $($ids:tt),* @seq_end) => {
[$($self.stream[$offset + $ids]),+]
};
($self:expr, $offset:expr, 1) => {
value_der!($self, $offset, @seq_start 0 @seq_end);
};
($self:expr, $offset:expr, 2) => {
value_der!($self, $offset, @seq_start 0, 1 @seq_end);
};
($self:expr, $offset:expr, 4) => {
value_der!($self, $offset, @seq_start 0, 1, 2, 3 @seq_end);
};
($self:expr, $offset:expr, 8) => {
value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7 @seq_end);
};
}
macro_rules! read_ty {
($func_name:ident, $ty:ty, 1) => {
pub(super) fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(value_der!(self, offset, 1));
self.offset.set(offset + 1);
result
}
};
($func_name:ident, $ty:ty, 2) => {
pub(super) fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(value_der!(self, offset, 2));
self.offset.set(offset + 2);
result
}
};
($func_name:ident, $ty:ty, 4) => {
pub(super) fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(value_der!(self, offset, 4));
self.offset.set(offset + 4);
result
}
};
($func_name:ident, $ty:ty, 8) => {
pub(super) fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(value_der!(self, offset, 8));
self.offset.set(offset + 8);
result
}
};
}
impl ValueReader {
pub(super) fn new(stream: Vec<u8>) -> Self {
let offset = Cell::new(0);
Self { stream, offset }
}
read_ty!(read_u8, u8, 1);
read_ty!(read_i8, i8, 1);
read_ty!(read_u16, u16, 2);
read_ty!(read_i16, i16, 2);
read_ty!(read_u32, u32, 4);
read_ty!(read_i32, i32, 4);
read_ty!(read_f32, f32, 4);
read_ty!(read_u64, u64, 8);
read_ty!(read_i64, i64, 8);
read_ty!(read_f64, f64, 8);
}

View File

@ -65,6 +65,7 @@ mod serde;
mod values;
// re-exports
pub use fluence_it_types::ne_vec;
pub use fluence_it_types::ne_vec::NEVec;
pub use fluence_it_types::IRecordFieldType;
pub use fluence_it_types::IRecordType;