refactor reader

This commit is contained in:
vms 2021-04-19 16:08:06 +03:00
parent 51af2df63e
commit 532043a884
10 changed files with 374 additions and 229 deletions

View File

@ -1,7 +1,7 @@
mod lift_array;
mod lower_array;
mod memory_writer;
mod read_arrays;
mod utils;
mod write_arrays;
pub(crate) use lift_array::array_lift_memory_impl;
@ -9,8 +9,8 @@ pub(crate) use lower_array::array_lower_memory_impl;
use super::allocate;
use super::read_from_instance_mem;
use super::record_lift_memory_;
use super::record_lower_memory_;
use super::record_lift_memory_impl;
use super::record_lower_memory_impl;
use super::write_to_instance_mem;
use crate::instr_error;

View File

@ -1,4 +1,4 @@
use super::utils::MemoryWriter;
use super::memory_writer::MemoryWriter;
use super::write_to_instance_mem;
use crate::{
@ -75,7 +75,7 @@ where
IValue::Record(values) => {
let record_offset =
super::record_lower_memory_(instance, instruction.clone(), values)?;
super::record_lower_memory_impl(instance, instruction.clone(), values)?;
writer.write_array(record_offset.to_le_bytes());
}
}

View File

@ -397,7 +397,7 @@ where
let mut result = Vec::with_capacity(data.len());
for record_offset in data {
result.push(super::record_lift_memory_(
result.push(super::record_lift_memory_impl(
instance,
record_type,
*record_offset as _,

View File

@ -1,169 +1,23 @@
mod lift_record;
mod lower_record;
mod value_reader;
pub(crate) use lift_record::record_lift_memory_impl;
pub(crate) use lower_record::record_lower_memory_impl;
use super::array_lift_memory_impl;
use super::array_lower_memory_impl;
use super::read_from_instance_mem;
use super::write_to_instance_mem;
use crate::instr_error;
use crate::interpreter::instructions::{is_record_fields_compatible_to_type, to_native};
use crate::IRecordType;
use crate::IType;
use crate::IValue;
use crate::NEVec;
use crate::{
errors::{InstructionError, InstructionErrorKind},
interpreter::Instruction,
};
use crate::{errors::InstructionError, errors::InstructionErrorKind, interpreter::Instruction};
use std::convert::TryInto;
pub(super) fn record_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
record_type: &IRecordType,
offset: usize,
instruction: Instruction,
) -> Result<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 length = record_type.fields.len();
let mut values = Vec::with_capacity(length);
let size = record_size(record_type);
let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?;
let mut field_id = 0;
for field in (*record_type.fields).iter() {
let value = data[field_id];
match &field.ty {
IType::Boolean => {
values.push(IValue::Boolean(value as _));
}
IType::S8 => {
values.push(IValue::S8(value as _));
}
IType::S16 => {
values.push(IValue::S16(value as _));
}
IType::S32 => {
values.push(IValue::S32(value as _));
}
IType::S64 => {
values.push(IValue::S64(value as _));
}
IType::I32 => {
values.push(IValue::I32(value as _));
}
IType::I64 => {
values.push(IValue::I64(value as _));
}
IType::U8 => {
values.push(IValue::U8(value as _));
}
IType::U16 => {
values.push(IValue::U16(value as _));
}
IType::U32 => {
values.push(IValue::U32(value as _));
}
IType::U64 => {
values.push(IValue::U64(value as _));
}
IType::F32 => {
values.push(IValue::F32(value as _));
}
IType::F64 => values.push(IValue::F64(f64::from_bits(value))),
IType::String => {
let string_offset = value;
field_id += 1;
let string_size = data[field_id];
if string_size != 0 {
let string_mem = read_from_instance_mem(
instance,
instruction.clone(),
string_offset as _,
string_size as _,
)?;
// TODO: check
let string = String::from_utf8(string_mem).unwrap();
values.push(IValue::String(string));
} else {
values.push(IValue::String(String::new()));
}
}
IType::Array(ty) => {
let array_offset = value;
field_id += 1;
let array_size = data[field_id];
if array_size != 0 {
let array = super::array_lift_memory_impl(
instance,
&**ty,
array_offset as _,
array_size as _,
instruction.clone(),
)?;
values.push(array);
} else {
values.push(IValue::Array(vec![]));
}
}
IType::Record(record_type_id) => {
let offset = value;
let record_type = instance.wit_record_by_id(*record_type_id).ok_or_else(|| {
InstructionError::new(
instruction.clone(),
InstructionErrorKind::RecordTypeByNameIsMissing {
record_type_id: *record_type_id,
},
)
})?;
values.push(record_lift_memory_(
instance,
record_type,
offset as _,
instruction.clone(),
)?)
}
}
field_id += 1;
}
Ok(IValue::Record(
NEVec::new(values.into_iter().collect())
.expect("Record must have at least one field, zero given"),
))
}
/// Returns record size in bytes.
fn record_size(record_type: &IRecordType) -> usize {
let mut record_size = 0;
for field_type in record_type.fields.iter() {
record_size += match field_type.ty {
IType::Boolean | IType::S8 | IType::U8 => 1,
IType::S16 | IType::U16 => 2,
IType::S32
| IType::U32
| IType::I32
| IType::F32
| IType::String
| IType::ByteArray
| IType::Array(_)
| IType::Record(_) => 32,
IType::S64 | IType::U64 | IType::I64 | IType::F64 => 64,
};
}
record_size
}
pub(crate) fn record_lift_memory<Instance, Export, LocalImport, Memory, MemoryView>(
record_type_id: u64,
instruction: Instruction,
@ -208,7 +62,7 @@ where
);
let record =
record_lift_memory_(&**instance, record_type, offset, instruction.clone())?;
record_lift_memory_impl(&**instance, record_type, offset, instruction.clone())?;
log::debug!("record.lift_memory: pushing {:?} on the stack", record);
runtime.stack.push(record);
@ -218,71 +72,6 @@ where
})
}
pub(super) fn record_lower_memory_<Instance, Export, LocalImport, Memory, MemoryView>(
instance: &mut Instance,
instruction: Instruction,
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());
for value in values.into_vec() {
match value {
IValue::Boolean(value) => result.push(value as _),
IValue::S8(value) => result.push(value as _),
IValue::S16(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::S32(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::S64(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::U8(value) => result.push(value),
IValue::U16(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::U32(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::U64(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::I32(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::I64(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::F32(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::F64(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::String(value) => {
let string_pointer =
write_to_instance_mem(instance, instruction.clone(), value.as_bytes())?;
result.extend_from_slice(&string_pointer.to_le_bytes());
result.extend_from_slice(&value.len().to_le_bytes());
}
IValue::ByteArray(value) => {
let array_pointer = write_to_instance_mem(instance, instruction.clone(), &value)?;
result.extend_from_slice(&array_pointer.to_le_bytes());
result.extend_from_slice(&value.len().to_le_bytes());
}
IValue::Array(values) => {
let (offset, size) =
super::array_lower_memory_impl(instance, instruction.clone(), values)?;
result.extend_from_slice(&offset.to_le_bytes());
result.extend_from_slice(&size.to_le_bytes());
}
IValue::Record(values) => {
let record_ptr = record_lower_memory_(instance, instruction.clone(), values)?;
result.extend_from_slice(&record_ptr.to_le_bytes());
}
}
}
let result_pointer = write_to_instance_mem(instance, instruction, &result)?;
Ok(result_pointer as _)
}
pub(crate) fn record_lower_memory<Instance, Export, LocalImport, Memory, MemoryView>(
record_type_id: u64,
instruction: Instruction,
@ -313,7 +102,7 @@ where
log::debug!("record.lower_memory: obtained {:?} values on the stack for record type = {}", record_fields, record_type_id);
let offset =
record_lower_memory_(*instance, instruction.clone(), record_fields)?;
record_lower_memory_impl(*instance, instruction.clone(), record_fields)?;
log::debug!("record.lower_memory: pushing {} on the stack", offset);
runtime.stack.push(IValue::I32(offset));

View File

@ -0,0 +1,192 @@
use super::read_from_instance_mem;
use super::value_reader::ValueReader;
use crate::IRecordType;
use crate::IType;
use crate::IValue;
use crate::NEVec;
use crate::{
errors::{InstructionError, InstructionErrorKind},
interpreter::Instruction,
};
#[rustfmt::skip]
pub(crate) fn record_lift_memory_impl<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
record_type: &IRecordType,
offset: usize,
instruction: Instruction,
) -> Result<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 mut values = Vec::with_capacity(record_type.fields.len());
let size = record_size(record_type);
let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?;
let reader = ValueReader::new(data);
for field in (*record_type.fields).iter() {
match &field.ty {
IType::Boolean => values.push(IValue::Boolean(reader.read_u8() == 1)),
IType::S8 => values.push(IValue::S8(reader.read_i8())),
IType::S16 => values.push(IValue::S16(reader.read_i16())),
IType::S32 => values.push(IValue::S32(reader.read_i32())),
IType::S64 => values.push(IValue::S64(reader.read_i64())),
IType::I32 => values.push(IValue::I32(reader.read_i32())),
IType::I64 => values.push(IValue::I64(reader.read_i64())),
IType::U8 => values.push(IValue::U8(reader.read_u8())),
IType::U16 => values.push(IValue::U16(reader.read_u16())),
IType::U32 => values.push(IValue::U32(reader.read_u32())),
IType::U64 => values.push(IValue::U64(reader.read_u64())),
IType::F32 => values.push(IValue::F32(reader.read_f32())),
IType::F64 => values.push(IValue::F64(reader.read_f64())),
IType::String => values.push(IValue::String(read_string(instance, instruction.clone(), &reader)?)),
IType::ByteArray => values.push(read_byte_array(instance, instruction.clone(), &reader)?),
IType::Array(ty) => values.push(read_array(instance, instruction.clone(), &reader, &**ty)?),
IType::Record(record_type_id) => values.push(read_record(instance, instruction.clone(), &reader, *record_type_id)?),
}
}
Ok(IValue::Record(
NEVec::new(values.into_iter().collect())
.expect("Record must have at least one field, zero given"),
))
}
/// Returns record size in bytes.
fn record_size(record_type: &IRecordType) -> usize {
let mut record_size = 0;
for field_type in record_type.fields.iter() {
record_size += match field_type.ty {
IType::Boolean | IType::S8 | IType::U8 => 1,
IType::S16 | IType::U16 => 2,
IType::S32
| IType::U32
| IType::I32
| IType::F32
| IType::String
| IType::ByteArray
| IType::Array(_)
| IType::Record(_) => 32,
IType::S64 | IType::U64 | IType::I64 | IType::F64 => 64,
};
}
record_size
}
fn read_string<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &Instance,
instruction: Instruction,
reader: &ValueReader,
) -> Result<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();
let string_mem = read_from_instance_mem(
instance,
instruction.clone(),
string_offset as _,
string_size as _,
)?;
// TODO: check
let string = String::from_utf8(string_mem).unwrap();
Ok(string)
}
fn read_byte_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &Instance,
instruction: Instruction,
reader: &ValueReader,
) -> Result<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();
let array = read_from_instance_mem(
instance,
instruction.clone(),
offset as _,
elements_count as _,
)?;
let byte_array = IValue::ByteArray(array);
Ok(byte_array)
}
fn read_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &Instance,
instruction: Instruction,
reader: &ValueReader,
ty: &IType,
) -> Result<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();
super::array_lift_memory_impl(
instance,
ty,
array_offset as _,
elements_count as _,
instruction.clone(),
)
}
fn read_record<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &Instance,
instruction: Instruction,
reader: &ValueReader,
record_type_id: u64,
) -> Result<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 record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| {
InstructionError::new(
instruction.clone(),
InstructionErrorKind::RecordTypeByNameIsMissing {
record_type_id,
},
)
})?;
record_lift_memory_impl(instance, record_type, offset as _, instruction.clone())
}

View File

@ -0,0 +1,70 @@
use super::write_to_instance_mem;
use crate::IValue;
use crate::NEVec;
use crate::{errors::InstructionError, interpreter::Instruction};
pub(crate) fn record_lower_memory_impl<Instance, Export, LocalImport, Memory, MemoryView>(
instance: &mut Instance,
instruction: Instruction,
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());
for value in values.into_vec() {
match value {
IValue::Boolean(value) => result.push(value as _),
IValue::S8(value) => result.push(value as _),
IValue::S16(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::S32(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::S64(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::U8(value) => result.push(value),
IValue::U16(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::U32(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::U64(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::I32(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::I64(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::F32(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::F64(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::String(value) => {
let string_pointer =
write_to_instance_mem(instance, instruction.clone(), value.as_bytes())?;
result.extend_from_slice(&string_pointer.to_le_bytes());
result.extend_from_slice(&value.len().to_le_bytes());
}
IValue::ByteArray(value) => {
let array_pointer = write_to_instance_mem(instance, instruction.clone(), &value)?;
result.extend_from_slice(&array_pointer.to_le_bytes());
result.extend_from_slice(&value.len().to_le_bytes());
}
IValue::Array(values) => {
let (offset, size) =
super::array_lower_memory_impl(instance, instruction.clone(), values)?;
result.extend_from_slice(&offset.to_le_bytes());
result.extend_from_slice(&size.to_le_bytes());
}
IValue::Record(values) => {
let record_ptr = record_lower_memory_impl(instance, instruction.clone(), values)?;
result.extend_from_slice(&record_ptr.to_le_bytes());
}
}
}
let result_pointer = write_to_instance_mem(instance, instruction, &result)?;
Ok(result_pointer as _)
}

View File

@ -0,0 +1,89 @@
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
}
};
}
// TODO: rewrite this with macros
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

@ -24,6 +24,10 @@ where
MemoryView: wasm::structures::MemoryView,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
if size == 0 {
return Ok(vec![]);
}
let memory_index = 0;
let memory_view = instance
.memory(memory_index)

View File

@ -52,6 +52,7 @@
// #![forbid(unsafe_code)]
#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
#![doc(html_logo_url = "https://github.com/wasmerio.png")]
#![recursion_limit = "512"]
pub mod ast;
#[macro_use]