improve array passing

This commit is contained in:
vms 2021-04-18 19:43:29 +03:00
parent 28114f8cdb
commit 41555d4d32
17 changed files with 624 additions and 228 deletions

16
Cargo.lock generated
View File

@ -20,6 +20,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "fluence-it-types"
version = "0.1.1"
@ -34,6 +40,15 @@ dependencies = [
name = "it-to-bytes"
version = "0.1.0"
[[package]]
name = "itertools"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "0.4.7"
@ -214,6 +229,7 @@ version = "0.19.0"
dependencies = [
"fluence-it-types",
"it-to-bytes",
"itertools",
"log",
"nom",
"safe-transmute",

View File

@ -18,6 +18,7 @@ where
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
match self {
IType::Boolean => 0x0b_u8.to_bytes(writer),
IType::S8 => 0x00_u8.to_bytes(writer),
IType::S16 => 0x01_u8.to_bytes(writer),
IType::S32 => 0x02_u8.to_bytes(writer),
@ -29,11 +30,11 @@ where
IType::F32 => 0x08_u8.to_bytes(writer),
IType::F64 => 0x09_u8.to_bytes(writer),
IType::String => 0x0a_u8.to_bytes(writer),
IType::ByteArray => 0x3C_u8.to_bytes(writer),
IType::Array(ty) => {
0x36_u8.to_bytes(writer)?;
ty.to_bytes(writer)
}
IType::Anyref => 0x0b_u8.to_bytes(writer),
IType::I32 => 0x0c_u8.to_bytes(writer),
IType::I64 => 0x0d_u8.to_bytes(writer),
IType::Record(record_id) => {
@ -77,6 +78,7 @@ mod keyword {
custom_keyword!(field);
// New types.
custom_keyword!(boolean);
custom_keyword!(s8);
custom_keyword!(s16);
custom_keyword!(s32);
@ -92,7 +94,11 @@ mod keyword {
impl Parse<'_> for IType {
fn parse(parser: Parser<'_>) -> Result<IType, ParseError> {
let mut lookahead = parser.lookahead1();
if lookahead.peek::<keyword::s8>() {
if lookahead.peek::<keyword::boolean>() {
parser.parse::<keyword::boolean>()?;
Ok(IType::Boolean)
} else if lookahead.peek::<keyword::s8>() {
parser.parse::<keyword::s8>()?;
Ok(IType::S8)
@ -142,10 +148,6 @@ impl Parse<'_> for IType {
let array_type = parser.parens(|p| p.parse())?;
Ok(IType::Array(Box::new(array_type)))
} else if lookahead.peek::<keyword::anyref>() {
parser.parse::<keyword::anyref>()?;
Ok(IType::Anyref)
} else if lookahead.peek::<keyword::i32>() {
parser.parse::<keyword::i32>()?;

View File

@ -8,6 +8,9 @@ use serde::Serialize;
/// Represents the types supported by WIT.
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub enum IType {
/// Boolean.
Boolean,
/// A 8-bits signed integer.
S8,
@ -41,12 +44,12 @@ pub enum IType {
/// A string.
String,
/// Specialization of arrays for byte vector.
ByteArray,
/// An array of values of the same type.
Array(Box<IType>),
/// An `any` reference.
Anyref,
/// A 32-bits integer (as defined in WebAssembly core).
I32,
@ -98,6 +101,7 @@ impl Default for RecordType {
impl ToString for &IType {
fn to_string(&self) -> String {
match &self {
IType::Boolean => "boolean".to_string(),
IType::S8 => "s8".to_string(),
IType::S16 => "s16".to_string(),
IType::S32 => "s32".to_string(),
@ -109,8 +113,8 @@ impl ToString for &IType {
IType::F32 => "f32".to_string(),
IType::F64 => "f64".to_string(),
IType::String => "string".to_string(),
IType::ByteArray => "array (u8)".to_string(),
IType::Array(ty) => format!("array ({})", ty.as_ref().to_string()),
IType::Anyref => "anyref".to_string(),
IType::I32 => "i32".to_string(),
IType::I64 => "i64".to_string(),
IType::Record(record_type_id) => format!("record {}", record_type_id),

View File

@ -5,6 +5,9 @@ use crate::ne_vec::NEVec;
/// A WIT value.
#[derive(Debug, Clone, PartialEq)]
pub enum IValue {
/// Boolean value.
Boolean(bool),
/// A 8-bits signed integer.
S8(i8),
@ -38,14 +41,16 @@ pub enum IValue {
/// A string.
String(String),
/// Specialization of array type for byte vector.
ByteArray(Vec<u8>),
/// A byte array.
Array(Vec<IValue>),
//Anyref(?),
/// A 32-bits integer (as defined in WebAssembly core).
I32(i32),
/// A 64-bits integer (as defiend in WebAssembly core).
/// A 64-bits integer (as defined in WebAssembly core).
I64(i64),
/// A record.

View File

@ -21,6 +21,7 @@ serde = { version = "1.0", features = ["derive", "rc"], optional = true }
serde_json = "1.0"
safe-transmute = "0.11.0"
log = "0.4.11"
itertools = "0.10.0"
semver = "0.11.0"

View File

@ -112,6 +112,7 @@ fn ty<'input, E: ParseError<&'input [u8]>>(
consume!((input, opcode) = byte(input)?);
let ty = match opcode {
0x0b => IType::Boolean,
0x00 => IType::S8,
0x01 => IType::S16,
0x02 => IType::S32,
@ -123,12 +124,12 @@ fn ty<'input, E: ParseError<&'input [u8]>>(
0x08 => IType::F32,
0x09 => IType::F64,
0x0a => IType::String,
0x3c => IType::ByteArray,
0x36 => {
consume!((input, array_value_type) = ty(input)?);
IType::Array(Box::new(array_value_type))
}
0x0b => IType::Anyref,
0x0c => IType::I32,
0x0d => IType::I64,
0x0e => {

View File

@ -354,7 +354,6 @@ mod tests {
(&IType::F32).to_string(),
(&IType::F64).to_string(),
(&IType::String).to_string(),
(&IType::Anyref).to_string(),
(&IType::I32).to_string(),
(&IType::I64).to_string(),
(&IType::Record(RecordType {

View File

@ -41,6 +41,16 @@ impl InstructionError {
impl Error for InstructionError {}
#[macro_export]
macro_rules! instr_error {
($instruction:expr, $error_kind:expr) => {
Err(crate::errors::InstructionError::new(
$instruction,
$error_kind,
))
};
}
impl Display for InstructionError {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(

View File

@ -1,7 +1,5 @@
use crate::{
errors::{InstructionError, InstructionErrorKind},
interpreter::Instruction,
};
use crate::instr_error;
use crate::{errors::InstructionErrorKind, interpreter::Instruction};
executable_instruction!(
argument_get(index: u32, instruction: Instruction) -> _ {
@ -9,10 +7,10 @@ executable_instruction!(
let invocation_inputs = runtime.invocation_inputs;
if (index as usize) >= invocation_inputs.len() {
return Err(InstructionError::new(
return instr_error!(
instruction.clone(),
InstructionErrorKind::InvocationInputIsMissing { index },
));
InstructionErrorKind::InvocationInputIsMissing { index }
);
}
log::debug!("arg.get: pushing {:?} on the stack", invocation_inputs[index as usize]);

View File

@ -1,6 +1,11 @@
use super::read_from_instance_mem;
use super::write_to_instance_mem;
mod read_arrays;
use super::read_from_instance_mem;
use super::record_lift_memory_;
use super::write_to_instance_mem;
use read_arrays::*;
use crate::instr_error;
use crate::interpreter::instructions::to_native;
use crate::{
errors::{InstructionError, InstructionErrorKind},
@ -14,9 +19,9 @@ pub(super) fn array_lift_memory_<'instance, Instance, Export, LocalImport, Memor
instance: &'instance Instance,
value_type: &IType,
offset: usize,
size: usize,
elements_count: usize,
instruction: Instruction,
) -> Result<Vec<IValue>, InstructionError>
) -> Result<IValue, InstructionError>
where
Export: crate::interpreter::wasm::structures::Export,
LocalImport: crate::interpreter::wasm::structures::LocalImport,
@ -25,162 +30,43 @@ where
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>
+ 'instance,
{
use safe_transmute::guard::AllOrNothingGuard;
use safe_transmute::transmute_many;
use safe_transmute::transmute_vec;
if size == 0 {
return Ok(vec![]);
if elements_count == 0 {
return Ok(IValue::Array(vec![]));
}
let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?;
let result_array = match value_type {
IType::S8 => {
let data = transmute_vec::<u8, i8>(data).unwrap();
data.into_iter().map(IValue::S8).collect::<Vec<_>>()
}
IType::S16 => {
let data = transmute_many::<i16, AllOrNothingGuard>(&data).unwrap();
data.iter().map(|v| IValue::S16(*v)).collect::<Vec<_>>()
}
IType::S32 => {
let data = transmute_many::<i32, AllOrNothingGuard>(&data).unwrap();
data.iter().map(|v| IValue::S32(*v)).collect::<Vec<_>>()
}
IType::S64 => {
let data = transmute_many::<i64, AllOrNothingGuard>(&data).unwrap();
data.iter().map(|v| IValue::S64(*v)).collect::<Vec<_>>()
}
IType::I32 => {
let data = transmute_many::<i32, AllOrNothingGuard>(&data).unwrap();
data.iter().map(|v| IValue::I32(*v)).collect::<Vec<_>>()
}
IType::I64 => {
let data = transmute_many::<i64, AllOrNothingGuard>(&data).unwrap();
data.iter().map(|v| IValue::S64(*v)).collect::<Vec<_>>()
}
IType::U8 => data.into_iter().map(IValue::U8).collect::<Vec<_>>(),
IType::U16 => {
let data = transmute_many::<u16, AllOrNothingGuard>(&data).unwrap();
data.iter().map(|v| IValue::U16(*v)).collect::<Vec<_>>()
}
IType::U32 => {
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
data.iter().map(|v| IValue::U32(*v)).collect::<Vec<_>>()
}
IType::U64 => {
let data = transmute_many::<u64, AllOrNothingGuard>(&data).unwrap();
data.iter().map(|v| IValue::U64(*v)).collect::<Vec<_>>()
}
IType::F32 => {
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
data.iter()
.map(|v| IValue::F32(f32::from_bits(*v)))
.collect::<Vec<_>>()
}
IType::F64 => {
let data = transmute_many::<u64, AllOrNothingGuard>(&data).unwrap();
data.iter()
.map(|v| IValue::F64(f64::from_bits(*v)))
.collect::<Vec<_>>()
}
IType::Anyref => unimplemented!(),
IType::String => {
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
if data.is_empty() {
return Ok(vec![]);
}
let mut result = Vec::with_capacity(data.len() / 2);
let mut data = data.iter();
while let Some(string_offset) = data.next() {
let string_size = data.next().ok_or_else(|| {
InstructionError::new(
instruction.clone(),
InstructionErrorKind::CorruptedArray(String::from(
"serialized array must contain even count of elements",
)),
)
})?;
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();
result.push(IValue::String(string));
}
result
}
match value_type {
IType::Boolean => read_bool_array(instance, instruction.clone(), offset, elements_count),
IType::S8 => read_s8_array(instance, instruction.clone(), offset, elements_count),
IType::S16 => read_s16_array(instance, instruction.clone(), offset, elements_count),
IType::S32 => read_s32_array(instance, instruction.clone(), offset, elements_count),
IType::S64 => read_s64_array(instance, instruction.clone(), offset, elements_count),
IType::I32 => read_i32_array(instance, instruction.clone(), offset, elements_count),
IType::I64 => read_i64_array(instance, instruction.clone(), offset, elements_count),
IType::U8 => read_u8_array(instance, instruction.clone(), offset, elements_count),
IType::U16 => read_u16_array(instance, instruction.clone(), offset, elements_count),
IType::U32 => read_u32_array(instance, instruction.clone(), offset, elements_count),
IType::U64 => read_u64_array(instance, instruction.clone(), offset, elements_count),
IType::F32 => read_f32_array(instance, instruction.clone(), offset, elements_count),
IType::F64 => read_f64_array(instance, instruction.clone(), offset, elements_count),
IType::String => read_string_array(instance, instruction.clone(), offset, elements_count),
IType::Record(record_type_id) => read_record_array(
instance,
instruction.clone(),
*record_type_id,
offset,
elements_count,
),
IType::ByteArray => read_array_array(
instance,
instruction.clone(),
&IType::ByteArray,
offset,
elements_count,
),
IType::Array(ty) => {
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
if data.is_empty() {
return Ok(vec![]);
}
let mut result = Vec::with_capacity(data.len() / 2);
let mut data = data.iter();
while let Some(array_offset) = data.next() {
let array_size = data.next().ok_or_else(|| {
InstructionError::new(
instruction.clone(),
InstructionErrorKind::CorruptedArray(String::from(
"serialized array must contain even count of elements",
)),
)
})?;
let value = array_lift_memory_(
instance,
&*ty,
*array_offset as _,
*array_size as _,
instruction.clone(),
)?;
result.push(IValue::Array(value));
}
result
read_array_array(instance, instruction.clone(), &ty, offset, elements_count)
}
IType::Record(record_type_id) => {
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,
},
)
})?;
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
let mut result = Vec::with_capacity(data.len());
for record_offset in data {
result.push(super::record_lift_memory_(
instance,
record_type,
*record_offset as _,
instruction.clone(),
)?);
}
result
}
};
Ok(result_array)
}
}
pub(crate) fn array_lift_memory<Instance, Export, LocalImport, Memory, MemoryView>(
@ -233,7 +119,7 @@ where
)?;
log::trace!("array.lift_memory: pushing {:?} on the stack", array);
runtime.stack.push(IValue::Array(array));
runtime.stack.push(array);
Ok(())
}
@ -356,13 +242,13 @@ where
Ok(())
}
_ => Err(InstructionError::new(
_ => instr_error!(
instruction.clone(),
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: IType::Array(Box::new(value_type.clone())),
received_value: stack_value.clone(),
},
)),
received_value: stack_value.clone()
}
),
}
}
})

View File

@ -0,0 +1,476 @@
use crate::instr_error;
use crate::interpreter::wasm;
use crate::IValue;
use crate::{
errors::{InstructionError, InstructionErrorKind},
interpreter::Instruction,
};
use std::cell::Cell;
macro_rules! def_read_func {
($func_name: ident, ($ty:ident, $elements_count:ident), $ctor:expr) => {
pub(super) fn $func_name<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
instruction: Instruction,
offset: usize,
$elements_count: usize,
) -> Result<IValue, InstructionError>
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 value_size = std::mem::size_of::<$ty>();
let ctor_ = $ctor;
let ivalues = ivalues_from_mem(
instance,
instruction,
offset,
value_size * $elements_count,
ctor_,
)?;
let ivalue = IValue::Array(ivalues);
Ok(ivalue)
}
};
}
fn ivalues_from_mem<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
instruction: Instruction,
offset: usize,
size: usize,
ivalue_ctor: impl FnOnce(&[Cell<u8>]) -> Vec<IValue>,
) -> Result<Vec<IValue>, InstructionError>
where
Export: wasm::structures::Export + 'instance,
LocalImport: wasm::structures::LocalImport + 'instance,
Memory: wasm::structures::Memory<MemoryView> + 'instance,
MemoryView: wasm::structures::MemoryView + 'instance,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
let memory_index: u32 = 0;
let memory_view = instance
.memory(memory_index as usize)
.ok_or_else(|| {
InstructionError::new(
instruction.clone(),
InstructionErrorKind::MemoryIsMissing { memory_index },
)
})?
.view();
log::trace!("reading {} bytes from offset {}", size, offset);
let right = offset + size;
if right < offset || right >= memory_view.len() {
return instr_error!(
instruction,
InstructionErrorKind::MemoryOutOfBoundsAccess {
index: right,
length: memory_view.len(),
}
);
}
let view = &memory_view[offset..offset + size];
let ivalues = ivalue_ctor(view);
Ok(ivalues)
}
def_read_func!(read_bool_array, (bool, elements_count), {
|memory_view: &[Cell<u8>]| {
let mut result = Vec::with_capacity(elements_count);
for element_id in 0..elements_count {
let value = Cell::get(&memory_view[element_id]);
result.push(IValue::Boolean(value == 1));
}
result
}
});
def_read_func!(read_u8_array, (u8, elements_count), {
|memory_view: &[Cell<u8>]| {
let mut result = Vec::with_capacity(elements_count);
for element_id in 0..elements_count {
let value = Cell::get(&memory_view[element_id]);
result.push(IValue::U8(value));
}
result
}
});
def_read_func!(read_s8_array, (i8, elements_count), {
|memory_view: &[Cell<u8>]| {
let mut result = Vec::with_capacity(elements_count);
for element_id in 0..elements_count {
let value = i8::from_be_bytes([Cell::get(&memory_view[element_id])]);
result.push(IValue::S8(value));
}
result
}
});
def_read_func!(read_u16_array, (u16, elements_count), {
|memory_view: &[Cell<u8>]| {
let mut result = Vec::with_capacity(elements_count);
for element_id in 0..elements_count {
let value = u16::from_be_bytes([
Cell::get(&memory_view[2 * element_id]),
Cell::get(&memory_view[2 * element_id + 1]),
]);
result.push(IValue::U16(value));
}
result
}
});
def_read_func!(read_s16_array, (i16, elements_count), {
|memory_view: &[Cell<u8>]| {
let mut result = Vec::with_capacity(elements_count);
for element_id in 0..elements_count {
let value = i16::from_be_bytes([
Cell::get(&memory_view[2 * element_id]),
Cell::get(&memory_view[2 * element_id + 1]),
]);
result.push(IValue::S16(value));
}
result
}
});
def_read_func!(read_u32_array, (u32, elements_count), {
|memory_view: &[Cell<u8>]| {
let mut result = Vec::with_capacity(elements_count);
for element_id in 0..elements_count {
let value = u32::from_be_bytes([
Cell::get(&memory_view[4 * element_id]),
Cell::get(&memory_view[4 * element_id + 1]),
Cell::get(&memory_view[4 * element_id + 2]),
Cell::get(&memory_view[4 * element_id + 3]),
]);
result.push(IValue::U32(value));
}
result
}
});
def_read_func!(read_f32_array, (f32, elements_count), {
|memory_view: &[Cell<u8>]| {
let mut result = Vec::with_capacity(elements_count);
for element_id in 0..elements_count {
let value = f32::from_be_bytes([
Cell::get(&memory_view[4 * element_id]),
Cell::get(&memory_view[4 * element_id + 1]),
Cell::get(&memory_view[4 * element_id + 2]),
Cell::get(&memory_view[4 * element_id + 3]),
]);
result.push(IValue::F32(value));
}
result
}
});
def_read_func!(read_s32_array, (i32, elements_count), {
|memory_view: &[Cell<u8>]| {
let mut result = Vec::with_capacity(elements_count);
for element_id in 0..elements_count {
let value = i32::from_be_bytes([
Cell::get(&memory_view[4 * element_id]),
Cell::get(&memory_view[4 * element_id + 1]),
Cell::get(&memory_view[4 * element_id + 2]),
Cell::get(&memory_view[4 * element_id + 3]),
]);
result.push(IValue::S32(value));
}
result
}
});
def_read_func!(read_i32_array, (i32, elements_count), {
|memory_view: &[Cell<u8>]| {
let mut result = Vec::with_capacity(elements_count);
for element_id in 0..elements_count {
let value = i32::from_be_bytes([
Cell::get(&memory_view[4 * element_id]),
Cell::get(&memory_view[4 * element_id + 1]),
Cell::get(&memory_view[4 * element_id + 2]),
Cell::get(&memory_view[4 * element_id + 3]),
]);
result.push(IValue::I32(value));
}
result
}
});
def_read_func!(read_u64_array, (u64, elements_count), {
|memory_view: &[Cell<u8>]| {
let mut result = Vec::with_capacity(elements_count);
for element_id in 0..elements_count {
let value = u64::from_be_bytes([
Cell::get(&memory_view[4 * element_id]),
Cell::get(&memory_view[4 * element_id + 1]),
Cell::get(&memory_view[4 * element_id + 2]),
Cell::get(&memory_view[4 * element_id + 3]),
Cell::get(&memory_view[4 * element_id + 4]),
Cell::get(&memory_view[4 * element_id + 5]),
Cell::get(&memory_view[4 * element_id + 6]),
Cell::get(&memory_view[4 * element_id + 7]),
]);
result.push(IValue::U64(value));
}
result
}
});
def_read_func!(read_f64_array, (f64, elements_count), {
|memory_view: &[Cell<u8>]| {
let mut result = Vec::with_capacity(elements_count);
for element_id in 0..elements_count {
let value = f64::from_be_bytes([
Cell::get(&memory_view[4 * element_id]),
Cell::get(&memory_view[4 * element_id + 1]),
Cell::get(&memory_view[4 * element_id + 2]),
Cell::get(&memory_view[4 * element_id + 3]),
Cell::get(&memory_view[4 * element_id + 4]),
Cell::get(&memory_view[4 * element_id + 5]),
Cell::get(&memory_view[4 * element_id + 6]),
Cell::get(&memory_view[4 * element_id + 7]),
]);
result.push(IValue::F64(value));
}
result
}
});
def_read_func!(read_s64_array, (i64, elements_count), {
|memory_view: &[Cell<u8>]| {
let mut result = Vec::with_capacity(elements_count);
for element_id in 0..elements_count {
let value = i64::from_be_bytes([
Cell::get(&memory_view[4 * element_id]),
Cell::get(&memory_view[4 * element_id + 1]),
Cell::get(&memory_view[4 * element_id + 2]),
Cell::get(&memory_view[4 * element_id + 3]),
Cell::get(&memory_view[4 * element_id + 4]),
Cell::get(&memory_view[4 * element_id + 5]),
Cell::get(&memory_view[4 * element_id + 6]),
Cell::get(&memory_view[4 * element_id + 7]),
]);
result.push(IValue::S64(value));
}
result
}
});
def_read_func!(read_i64_array, (i64, elements_count), {
|memory_view: &[Cell<u8>]| {
let mut result = Vec::with_capacity(elements_count);
for element_id in 0..elements_count {
let value = i64::from_be_bytes([
Cell::get(&memory_view[4 * element_id]),
Cell::get(&memory_view[4 * element_id + 1]),
Cell::get(&memory_view[4 * element_id + 2]),
Cell::get(&memory_view[4 * element_id + 3]),
Cell::get(&memory_view[4 * element_id + 4]),
Cell::get(&memory_view[4 * element_id + 5]),
Cell::get(&memory_view[4 * element_id + 6]),
Cell::get(&memory_view[4 * element_id + 7]),
]);
result.push(IValue::I64(value));
}
result
}
});
use super::read_from_instance_mem;
use safe_transmute::guard::AllOrNothingGuard;
use safe_transmute::transmute_many;
const WASM_POINTER_SIZE: usize = 4;
pub(super) fn read_string_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
instruction: Instruction,
offset: usize,
elements_count: usize,
) -> 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 data = read_from_instance_mem(
instance,
instruction.clone(),
offset,
WASM_POINTER_SIZE * elements_count,
)?;
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
if data.is_empty() {
return Ok(IValue::Array(vec![]));
}
let mut result = Vec::with_capacity(data.len() / 2);
let mut data = data.iter();
while let Some(string_offset) = data.next() {
let string_size = data.next().ok_or_else(|| {
InstructionError::new(
instruction.clone(),
InstructionErrorKind::CorruptedArray(String::from(
"serialized array must contain even count of elements",
)),
)
})?;
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();
result.push(IValue::String(string));
}
let result = IValue::Array(result);
Ok(result)
}
pub(super) fn read_record_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
instruction: Instruction,
record_type_id: u64,
offset: usize,
elements_count: usize,
) -> 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 record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| {
InstructionError::new(
instruction.clone(),
InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id },
)
})?;
let data = read_from_instance_mem(
instance,
instruction.clone(),
offset,
WASM_POINTER_SIZE * elements_count,
)?;
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
let mut result = Vec::with_capacity(data.len());
for record_offset in data {
result.push(super::record_lift_memory_(
instance,
record_type,
*record_offset as _,
instruction.clone(),
)?);
}
let result = IValue::Array(result);
Ok(result)
}
pub(super) fn read_array_array<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance Instance,
instruction: Instruction,
ty: &crate::IType,
offset: usize,
elements_count: usize,
) -> 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 data = read_from_instance_mem(
instance,
instruction.clone(),
offset,
WASM_POINTER_SIZE * elements_count,
)?;
let data = transmute_many::<u32, AllOrNothingGuard>(&data).unwrap();
if data.is_empty() {
return Ok(IValue::Array(vec![]));
}
let mut result = Vec::with_capacity(data.len() / 2);
let mut data = data.iter();
while let Some(array_offset) = data.next() {
let array_size = data.next().ok_or_else(|| {
InstructionError::new(
instruction.clone(),
InstructionErrorKind::CorruptedArray(String::from(
"serialized array must contain even count of elements",
)),
)
})?;
let value = match ty {
crate::IType::ByteArray => {
let value = read_from_instance_mem(
instance,
instruction.clone(),
*array_offset as _,
*array_size as _,
)?;
IValue::ByteArray(value)
}
_ => super::array_lift_memory_(
instance,
&*ty,
*array_offset as _,
*array_size as _,
instruction.clone(),
)?,
};
result.push(value);
}
let result = IValue::Array(result);
Ok(result)
}

View File

@ -11,10 +11,12 @@ mod utils;
use crate::errors::{
InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError,
};
use crate::instr_error;
use crate::interpreter::wasm;
use crate::IType;
use crate::IValue;
use crate::NEVec;
pub(crate) use argument_get::argument_get;
pub(crate) use arrays::*;
pub(crate) use call_core::call_core;
@ -292,13 +294,13 @@ where
Ok(())
}
_ => Err(InstructionError::new(
_ => instr_error!(
instruction,
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: interface_type.clone(),
received_value: interface_value.clone(),
},
)),
}
),
}
}
@ -330,14 +332,14 @@ where
})?;
if record_fields.len() != record_type.fields.len() {
return Err(InstructionError::new(
return instr_error!(
instruction.clone(),
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: IType::Record(record_type_id),
// unwrap is safe here - len's been already checked
received_value: IValue::Record(NEVec::new(record_fields.to_vec()).unwrap()),
},
));
}
);
}
for (record_type_field, record_value_field) in

View File

@ -1,9 +1,11 @@
use crate::instr_error;
use crate::IType;
use crate::IValue;
use crate::{
errors::{InstructionError, InstructionErrorKind},
interpreter::Instruction,
};
use std::convert::TryInto;
macro_rules! lowering_lifting {
@ -34,20 +36,20 @@ macro_rules! lowering_lifting {
})
}
Some(wrong_value) => {
return Err(InstructionError::new(
return instr_error!(
instruction.clone(),
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: IType::$from_variant,
received_value: wrong_value,
}
))
)
},
None => {
return Err(InstructionError::new(
return instr_error!(
instruction.clone(),
InstructionErrorKind::StackIsTooSmall { needed: 1 },
))
InstructionErrorKind::StackIsTooSmall { needed: 1 }
)
}
}

View File

@ -1,6 +1,7 @@
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;
@ -175,7 +176,6 @@ where
values.push(IValue::F32(value as _));
}
IType::F64 => values.push(IValue::F64(f64::from_bits(value))),
IType::Anyref => {}
IType::String => {
let string_offset = value;
field_id += 1;
@ -209,7 +209,7 @@ where
array_size as _,
instruction.clone(),
)?;
values.push(IValue::Array(array));
values.push(array);
} else {
values.push(IValue::Array(vec![]));
}
@ -399,17 +399,17 @@ where
Ok(())
}
Some(value) => Err(InstructionError::new(
Some(value) => instr_error!(
instruction.clone(),
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: IType::Record(record_type_id),
received_value: value,
},
)),
None => Err(InstructionError::new(
}
),
None => instr_error!(
instruction.clone(),
InstructionErrorKind::StackIsTooSmall { needed: 1 },
)),
InstructionErrorKind::StackIsTooSmall { needed: 1 }
),
}
}
})

View File

@ -1,10 +1,12 @@
use super::to_native;
use crate::instr_error;
use crate::IType;
use crate::IValue;
use crate::{
errors::{InstructionError, InstructionErrorKind},
interpreter::Instruction,
};
use std::{cell::Cell, convert::TryInto};
executable_instruction!(
@ -45,13 +47,13 @@ executable_instruction!(
}
if memory_view.len() < pointer + length {
return Err(InstructionError::new(
return instr_error!(
instruction.clone(),
InstructionErrorKind::MemoryOutOfBoundsAccess {
index: pointer + length,
length: memory_view.len(),
},
));
}
);
}
let data: Vec<u8> = (&memory_view[pointer..pointer + length])
@ -131,18 +133,18 @@ executable_instruction!(
Ok(())
},
Some(value) => Err(InstructionError::new(
Some(value) => instr_error!(
instruction.clone(),
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: IType::String,
received_value: (&value).clone(),
},
)),
}
),
None => Err(InstructionError::new(
None => instr_error!(
instruction.clone(),
InstructionErrorKind::StackIsTooSmall { needed: 1 },
)),
InstructionErrorKind::StackIsTooSmall { needed: 1 }
),
}
}
}

View File

@ -2,6 +2,7 @@ use crate::interpreter::instructions::ALLOCATE_FUNC_INDEX;
use crate::interpreter::wasm;
use crate::interpreter::wasm::structures::{FunctionIndex, TypedIndex};
use crate::instr_error;
use crate::interpreter::instructions::to_native;
use crate::IType;
use crate::IValue;
@ -38,13 +39,13 @@ where
let right = offset + size;
if right < offset || right >= memory_view.len() {
return Err(InstructionError::new(
return instr_error!(
instruction,
InstructionErrorKind::MemoryOutOfBoundsAccess {
index: right,
length: memory_view.len(),
},
));
}
);
}
Ok((&memory_view[offset..offset + size])
@ -82,13 +83,13 @@ where
let right = offset + bytes.len();
if right < offset || right >= memory_view.len() {
return Err(InstructionError::new(
return instr_error!(
instruction,
InstructionErrorKind::MemoryOutOfBoundsAccess {
index: right,
length: memory_view.len(),
},
));
}
);
}
for (byte_id, byte) in bytes.iter().enumerate() {
@ -117,14 +118,14 @@ where
vec![IValue::I32(size as _)],
)?;
if values.len() != 1 {
return Err(InstructionError::new(
return instr_error!(
instruction,
InstructionErrorKind::LocalOrImportSignatureMismatch {
function_index: ALLOCATE_FUNC_INDEX,
expected: (vec![IType::I32], vec![]),
received: (vec![], vec![]),
},
));
}
);
}
to_native::<i32>(&values[0], instruction).map(|v| v as usize)
}

View File

@ -242,15 +242,6 @@ where
let value_type = value_type.clone();
instructions::array_lower_memory(instruction, value_type)
}
/*
Instruction::RecordLift { type_index } => {
instructions::record_lift(*type_index, instruction)
}
Instruction::RecordLower { type_index } => {
instructions::record_lower(*type_index, instruction)
}
*/
Instruction::RecordLiftMemory { record_type_id } => {
instructions::record_lift_memory(record_type_id as _, instruction)
}