From 0bae64ad3c6de4fbbd1771ad76045b76cc667804 Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 20 Sep 2020 21:53:03 +0300 Subject: [PATCH] initial --- src/decoders/binary.rs | 28 +- src/decoders/wat.rs | 34 +- src/encoders/binary.rs | 17 +- src/encoders/wat.rs | 12 +- src/errors.rs | 9 + src/interpreter/instructions/argument_get.rs | 2 +- src/interpreter/instructions/arrays.rs | 373 ++++++++++++++++++ src/interpreter/instructions/byte_arrays.rs | 145 ------- src/interpreter/instructions/call_core.rs | 8 +- src/interpreter/instructions/dup.rs | 2 +- src/interpreter/instructions/mod.rs | 41 +- src/interpreter/instructions/numbers.rs | 6 +- src/interpreter/instructions/records.rs | 119 +++--- src/interpreter/instructions/strings.rs | 32 +- src/interpreter/instructions/swap2.rs | 2 +- .../instructions/{records => }/utils.rs | 14 +- src/interpreter/mod.rs | 104 ++--- src/macros.rs | 2 +- src/serde/de.rs | 15 +- src/types.rs | 6 +- src/values.rs | 3 +- 21 files changed, 624 insertions(+), 350 deletions(-) create mode 100644 src/interpreter/instructions/arrays.rs delete mode 100644 src/interpreter/instructions/byte_arrays.rs rename src/interpreter/instructions/{records => }/utils.rs (95%) diff --git a/src/decoders/binary.rs b/src/decoders/binary.rs index a24ce74..914268e 100644 --- a/src/decoders/binary.rs +++ b/src/decoders/binary.rs @@ -118,7 +118,11 @@ fn ty<'input, E: ParseError<&'input [u8]>>( 0x08 => InterfaceType::F32, 0x09 => InterfaceType::F64, 0x0a => InterfaceType::String, - 0x36 => InterfaceType::ByteArray, + 0x36 => { + consume!((input, array_value_type) = ty(input)?); + + InterfaceType::Array(Box::new(array_value_type)) + } 0x0b => InterfaceType::Anyref, 0x0c => InterfaceType::I32, 0x0d => InterfaceType::I64, @@ -288,11 +292,19 @@ fn instruction<'input, E: ParseError<&'input [u8]>>( 0x23 => (input, Instruction::StringLowerMemory), 0x24 => (input, Instruction::StringSize), - 0x37 => (input, Instruction::ByteArrayLiftMemory), - 0x38 => (input, Instruction::ByteArrayLowerMemory), - 0x39 => (input, Instruction::ByteArraySize), + 0x37 => { + consume!((input, value_type) = ty(input)?); + (input, Instruction::ArrayLiftMemory { value_type }) + } + 0x38 => { + consume!((input, value_type) = ty(input)?); + + (input, Instruction::ArrayLowerMemory { value_type }) + } /* + 0x39 => (input, Instruction::ArraySize), + 0x25 => { consume!((input, argument_0) = uleb(input)?); @@ -315,22 +327,22 @@ fn instruction<'input, E: ParseError<&'input [u8]>>( } */ 0x3A => { - consume!((input, argument_0) = uleb(input)?); + consume!((input, record_type_id) = uleb(input)?); ( input, Instruction::RecordLiftMemory { - record_type_id: argument_0 as u32, + record_type_id: record_type_id as u32, }, ) } 0x3B => { - consume!((input, argument_0) = uleb(input)?); + consume!((input, record_type_id) = uleb(input)?); ( input, Instruction::RecordLowerMemory { - record_type_id: argument_0 as u32, + record_type_id: record_type_id as u32, }, ) } diff --git a/src/decoders/wat.rs b/src/decoders/wat.rs index 2cffa78..c2a130d 100644 --- a/src/decoders/wat.rs +++ b/src/decoders/wat.rs @@ -31,7 +31,7 @@ mod keyword { custom_keyword!(u32); custom_keyword!(u64); custom_keyword!(string); - custom_keyword!(byte_array); + custom_keyword!(Array); // Instructions. custom_keyword!(argument_get = "arg.get"); @@ -71,9 +71,9 @@ mod keyword { custom_keyword!(string_lift_memory = "string.lift_memory"); custom_keyword!(string_lower_memory = "string.lower_memory"); custom_keyword!(string_size = "string.size"); - custom_keyword!(byte_array_lift_memory = "byte_array.lift_memory"); - custom_keyword!(byte_array_lower_memory = "byte_array.lower_memory"); - custom_keyword!(byte_array_size = "byte_array.size"); + custom_keyword!(array_lift_memory = "array.lift_memory"); + custom_keyword!(array_lower_memory = "array.lower_memory"); + custom_keyword!(array_size = "array.size"); custom_keyword!(record_lift = "record.lift"); custom_keyword!(record_lower = "record.lower"); custom_keyword!(record_lift_memory = "record.lift_memory"); @@ -130,10 +130,10 @@ impl Parse<'_> for InterfaceType { parser.parse::()?; Ok(InterfaceType::String) - } else if lookahead.peek::() { - parser.parse::()?; + } else if lookahead.peek::() { + parser.parse::()?; - Ok(InterfaceType::ByteArray) + Ok(InterfaceType::Array(Box::new(parser.parse()?))) } else if lookahead.peek::() { parser.parse::()?; @@ -352,18 +352,18 @@ impl<'a> Parse<'a> for Instruction { parser.parse::()?; Ok(Instruction::StringSize) - } else if lookahead.peek::() { - parser.parse::()?; + } else if lookahead.peek::() { + parser.parse::()?; - Ok(Instruction::ByteArrayLiftMemory) - } else if lookahead.peek::() { - parser.parse::()?; + Ok(Instruction::ArrayLiftMemory { + value_type: parser.parse()?, + }) + } else if lookahead.peek::() { + parser.parse::()?; - Ok(Instruction::ByteArrayLowerMemory) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::ByteArraySize) + Ok(Instruction::ArrayLowerMemory { + value_type: parser.parse()?, + }) } /* else if lookahead.peek::() { diff --git a/src/encoders/binary.rs b/src/encoders/binary.rs index 65b6a54..991643d 100644 --- a/src/encoders/binary.rs +++ b/src/encoders/binary.rs @@ -123,7 +123,10 @@ where InterfaceType::F32 => 0x08_u8.to_bytes(writer), InterfaceType::F64 => 0x09_u8.to_bytes(writer), InterfaceType::String => 0x0a_u8.to_bytes(writer), - InterfaceType::ByteArray => 0x36_u8.to_bytes(writer), + InterfaceType::Array(ty) => { + 0x36_u8.to_bytes(writer)?; + ty.to_bytes(writer) + } InterfaceType::Anyref => 0x0b_u8.to_bytes(writer), InterfaceType::I32 => 0x0c_u8.to_bytes(writer), InterfaceType::I64 => 0x0d_u8.to_bytes(writer), @@ -378,10 +381,16 @@ where Instruction::StringLowerMemory => 0x23_u8.to_bytes(writer)?, Instruction::StringSize => 0x24_u8.to_bytes(writer)?, - Instruction::ByteArrayLiftMemory => 0x37_u8.to_bytes(writer)?, - Instruction::ByteArrayLowerMemory => 0x38_u8.to_bytes(writer)?, - Instruction::ByteArraySize => 0x39_u8.to_bytes(writer)?, + Instruction::ArrayLiftMemory { value_type } => { + 0x37_u8.to_bytes(writer)?; + value_type.to_bytes(writer)? + } + Instruction::ArrayLowerMemory { value_type } => { + 0x38_u8.to_bytes(writer)?; + value_type.to_bytes(writer)? + } /* + Instruction::ArraySize => 0x39_u8.to_bytes(writer)?, Instruction::RecordLift { type_index } => { 0x25_u8.to_bytes(writer)?; (*type_index as u64).to_bytes(writer)? diff --git a/src/encoders/wat.rs b/src/encoders/wat.rs index 65d3ff0..c7e3bd5 100644 --- a/src/encoders/wat.rs +++ b/src/encoders/wat.rs @@ -73,7 +73,7 @@ impl ToString for &InterfaceType { InterfaceType::F32 => "f32".to_string(), InterfaceType::F64 => "f64".to_string(), InterfaceType::String => "string".to_string(), - InterfaceType::ByteArray => "byte_array".to_string(), + InterfaceType::Array(ty) => format!("Array<{:?}>", ty), InterfaceType::Anyref => "anyref".to_string(), InterfaceType::I32 => "i32".to_string(), InterfaceType::I64 => "i64".to_string(), @@ -144,10 +144,14 @@ impl ToString for &Instruction { Instruction::StringLiftMemory => "string.lift_memory".into(), Instruction::StringLowerMemory => "string.lower_memory".into(), Instruction::StringSize => "string.size".into(), - Instruction::ByteArrayLiftMemory => "byte_array.lift_memory".into(), - Instruction::ByteArrayLowerMemory => "byte_array.lower_memory".into(), - Instruction::ByteArraySize => "byte_array.size".into(), + Instruction::ArrayLiftMemory { value_type } => { + format!("array.lift_memory {:?}", value_type) + } + Instruction::ArrayLowerMemory { value_type } => { + format!("array.lower_memory {:?}", value_type) + } /* + Instruction::ArraySize => "byte_array.size".into(), Instruction::RecordLift { type_index } => format!("record.lift {}", type_index), Instruction::RecordLower { type_index } => format!("record.lower {}", type_index), */ diff --git a/src/errors.rs b/src/errors.rs index efa5d03..4215cff 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -170,6 +170,9 @@ pub enum InstructionErrorKind { record_type_id: u64, }, + /// Corrupted array's been popped from the stack. + CorruptedArray(String), + /// Corrupted record's been popped from the stack. CorruptedRecord(String), @@ -278,6 +281,12 @@ impl Display for InstructionErrorKind { type_name ), + Self::CorruptedArray(err) => write!( + formatter, + "{}", + err + ), + Self::CorruptedRecord(err) => write!( formatter, "{}", diff --git a/src/interpreter/instructions/argument_get.rs b/src/interpreter/instructions/argument_get.rs index 87cbc52..d42895c 100644 --- a/src/interpreter/instructions/argument_get.rs +++ b/src/interpreter/instructions/argument_get.rs @@ -10,7 +10,7 @@ executable_instruction!( if (index as usize) >= invocation_inputs.len() { return Err(InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::InvocationInputIsMissing { index }, )); } diff --git a/src/interpreter/instructions/arrays.rs b/src/interpreter/instructions/arrays.rs new file mode 100644 index 0000000..05210aa --- /dev/null +++ b/src/interpreter/instructions/arrays.rs @@ -0,0 +1,373 @@ +use super::deallocate; +use super::read_from_instance_mem; +use super::write_to_instance_mem; + +use crate::interpreter::instructions::to_native; +use crate::{ + errors::{InstructionError, InstructionErrorKind}, + interpreter::Instruction, + types::InterfaceType, + values::InterfaceValue, +}; + +use std::convert::TryInto; + +pub(super) fn array_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>( + instance: &'instance Instance, + value_type: &InterfaceType, + offset: usize, + size: usize, + instruction: Instruction, +) -> Result, InstructionError> +where + Export: crate::interpreter::wasm::structures::Export, + LocalImport: crate::interpreter::wasm::structures::LocalImport, + Memory: crate::interpreter::wasm::structures::Memory, + MemoryView: crate::interpreter::wasm::structures::MemoryView, + Instance: crate::interpreter::wasm::structures::Instance + + 'instance, +{ + if size == 0 { + return Ok(vec![]); + } + + let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?; + + let result_array = match value_type { + InterfaceType::S8 => { + let data = safe_transmute::transmute_vec::(data).unwrap(); + data.into_iter().map(InterfaceValue::S8).collect::>() + } + InterfaceType::S16 => { + let data = safe_transmute::transmute_vec::(data).unwrap(); + data.into_iter() + .map(InterfaceValue::S16) + .collect::>() + } + InterfaceType::S32 => { + let data = safe_transmute::transmute_vec::(data).unwrap(); + data.into_iter() + .map(InterfaceValue::S32) + .collect::>() + } + InterfaceType::S64 => { + let data = safe_transmute::transmute_vec::(data).unwrap(); + data.into_iter() + .map(InterfaceValue::S64) + .collect::>() + } + InterfaceType::I32 => { + let data = safe_transmute::transmute_vec::(data).unwrap(); + data.into_iter() + .map(InterfaceValue::I32) + .collect::>() + } + InterfaceType::I64 => { + let data = safe_transmute::transmute_vec::(data).unwrap(); + data.into_iter() + .map(InterfaceValue::I64) + .collect::>() + } + InterfaceType::U8 => data.into_iter().map(InterfaceValue::U8).collect::>(), + InterfaceType::U16 => { + let data = safe_transmute::transmute_vec::(data).unwrap(); + data.into_iter() + .map(InterfaceValue::U16) + .collect::>() + } + InterfaceType::U32 => { + let data = safe_transmute::transmute_vec::(data).unwrap(); + data.into_iter() + .map(InterfaceValue::U32) + .collect::>() + } + InterfaceType::U64 => { + let data = safe_transmute::transmute_vec::(data).unwrap(); + data.into_iter() + .map(InterfaceValue::U64) + .collect::>() + } + InterfaceType::F32 => { + let data = safe_transmute::transmute_vec::(data).unwrap(); + data.into_iter() + .map(|v| InterfaceValue::F32(v as _)) + .collect::>() + } + InterfaceType::F64 => { + let data = safe_transmute::transmute_vec::(data).unwrap(); + data.into_iter() + .map(|v| InterfaceValue::F64(f64::from_bits(v))) + .collect::>() + } + InterfaceType::Anyref => unimplemented!(), + InterfaceType::String => { + let data = safe_transmute::transmute_vec::(data).unwrap(); + + if data.is_empty() { + return Ok(vec![]); + } + + let mut result = Vec::with_capacity(data.len() / 2); + let mut data = data.into_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(InterfaceValue::String(string)); + } + + result + } + InterfaceType::Array(ty) => { + let data = safe_transmute::transmute_vec::(data).unwrap(); + + if data.is_empty() { + return Ok(vec![]); + } + + let mut result = Vec::with_capacity(data.len() / 2); + let mut data = data.into_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(InterfaceValue::Array(value)); + } + + result + } + InterfaceType::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 = safe_transmute::transmute_vec::(data).unwrap(); + + let mut result = Vec::with_capacity(data.len()); + + for record_offset in data.into_iter() { + result.push(super::record_lift_memory_( + instance, + record_type, + record_offset as _, + instruction.clone(), + )?); + } + result + } + }; + + deallocate(instance, instruction, offset as _, size as _)?; + + Ok(result_array) +} + +pub(crate) fn array_lift_memory( + instruction: Instruction, + value_type: InterfaceType, +) -> crate::interpreter::ExecutableInstruction +where + Export: crate::interpreter::wasm::structures::Export, + LocalImport: crate::interpreter::wasm::structures::LocalImport, + Memory: crate::interpreter::wasm::structures::Memory, + MemoryView: crate::interpreter::wasm::structures::MemoryView, + Instance: + crate::interpreter::wasm::structures::Instance, +{ + #[allow(unused_imports)] + use crate::interpreter::stack::Stackable; + Box::new({ + move |runtime| -> _ { + let inputs = runtime.stack.pop(2).ok_or_else(|| { + InstructionError::new( + instruction.clone(), + InstructionErrorKind::StackIsTooSmall { needed: 1 }, + ) + })?; + + let offset: usize = to_native::(&inputs[0], instruction.clone())? + .try_into() + .map_err(|e| (e, "offset").into()) + .map_err(|k| InstructionError::new(instruction.clone(), k))?; + + let size: usize = to_native::(&inputs[1], instruction.clone())? + .try_into() + .map_err(|e| (e, "offset").into()) + .map_err(|k| InstructionError::new(instruction.clone(), k))?; + + log::trace!( + "array.lift_memory: lifting memory for value type: {:?}", + value_type + ); + + let instance = &mut runtime.wasm_instance; + let array = array_lift_memory_( + *instance, + &value_type, + offset as _, + size as _, + instruction.clone(), + )?; + + log::trace!("array.lift_memory: pushing {:?} on the stack", array); + runtime.stack.push(InterfaceValue::Array(array)); + + Ok(()) + } + }) +} + +pub(super) fn array_lower_memory_( + instance: &mut Instance, + instruction: Instruction, + array_values: Vec, +) -> Result<(usize, usize), InstructionError> +where + Export: crate::interpreter::wasm::structures::Export, + LocalImport: crate::interpreter::wasm::structures::LocalImport, + Memory: crate::interpreter::wasm::structures::Memory, + MemoryView: crate::interpreter::wasm::structures::MemoryView, + Instance: + crate::interpreter::wasm::structures::Instance, +{ + let mut result: Vec = Vec::with_capacity(array_values.len()); + + for value in array_values { + match value { + InterfaceValue::S8(value) => result.push(value as _), + InterfaceValue::S16(value) => result.push(value as _), + InterfaceValue::S32(value) => result.push(value as _), + InterfaceValue::S64(value) => result.push(value as _), + InterfaceValue::U8(value) => result.push(value as _), + InterfaceValue::U16(value) => result.push(value as _), + InterfaceValue::U32(value) => result.push(value as _), + InterfaceValue::U64(value) => result.push(value as _), + InterfaceValue::I32(value) => result.push(value as _), + InterfaceValue::I64(value) => result.push(value as _), + InterfaceValue::F32(value) => result.push(value as _), + InterfaceValue::F64(value) => result.push(value.to_bits()), + InterfaceValue::String(value) => { + let string_pointer = if !value.is_empty() { + write_to_instance_mem(instance, instruction.clone(), value.as_bytes())? + } else { + 0 + }; + + result.push(string_pointer as _); + result.push(value.len() as _); + } + + InterfaceValue::Array(values) => { + let (array_offset, array_size) = if !values.is_empty() { + array_lower_memory_(instance, instruction.clone(), values)? + } else { + (0, 0) + }; + + result.push(array_offset as _); + result.push(array_size as _); + } + + InterfaceValue::Record(values) => { + let record_offset = + super::record_lower_memory_(instance, instruction.clone(), values)?; + result.push(record_offset as _); + } + } + } + + let result = safe_transmute::transmute_to_bytes::(&result); + let result_pointer = write_to_instance_mem(instance, instruction, &result)?; + + Ok((result_pointer as _, result.len() as _)) +} + +pub(crate) fn array_lower_memory( + instruction: Instruction, + value_type: InterfaceType, +) -> crate::interpreter::ExecutableInstruction +where + Export: crate::interpreter::wasm::structures::Export, + LocalImport: crate::interpreter::wasm::structures::LocalImport, + Memory: crate::interpreter::wasm::structures::Memory, + MemoryView: crate::interpreter::wasm::structures::MemoryView, + Instance: + crate::interpreter::wasm::structures::Instance, +{ + #[allow(unused_imports)] + use crate::interpreter::stack::Stackable; + Box::new({ + move |runtime| -> _ { + let instance = &mut runtime.wasm_instance; + let stack_value = runtime.stack.pop1().ok_or_else(|| { + InstructionError::new( + instruction.clone(), + InstructionErrorKind::StackIsTooSmall { needed: 1 }, + ) + })?; + + super::is_value_compatible_to_type( + &**instance, + &value_type, + &stack_value, + instruction.clone(), + )?; + + match stack_value { + InterfaceValue::Array(values) => { + log::trace!("array.lower_memory: obtained {:?} values on the stack for interface type = {:?}", values, value_type); + + let (offset, size) = + array_lower_memory_(*instance, instruction.clone(), values)?; + + log::trace!( + "array.lower_memory: pushing {}, {} on the stack", + offset, + size + ); + runtime.stack.push(InterfaceValue::I32(offset as _)); + runtime.stack.push(InterfaceValue::I32(size as _)); + + Ok(()) + } + _ => panic!("is_value_compatible_to_type should invoked previously"), + } + } + }) +} diff --git a/src/interpreter/instructions/byte_arrays.rs b/src/interpreter/instructions/byte_arrays.rs deleted file mode 100644 index c4f4ede..0000000 --- a/src/interpreter/instructions/byte_arrays.rs +++ /dev/null @@ -1,145 +0,0 @@ -use super::to_native; -use crate::{ - errors::{InstructionError, InstructionErrorKind}, - interpreter::Instruction, - types::InterfaceType, - values::InterfaceValue, -}; -use std::{cell::Cell, convert::TryInto}; - -executable_instruction!( - byte_array_lift_memory(instruction: Instruction) -> _ { - move |runtime| -> _ { - let inputs = runtime.stack.pop(2).ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::StackIsTooSmall { needed: 2 }, - ) - })?; - - let memory_index: u32 = 0; - let memory = runtime - .wasm_instance - .memory(memory_index as usize) - .ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::MemoryIsMissing { memory_index }, - ) - })?; - - let pointer: usize = to_native::(&inputs[0], instruction)? - .try_into() - .map_err(|e| (e, "pointer").into()) - .map_err(|k| InstructionError::new(instruction, k))?; - let length: usize = to_native::(&inputs[1], instruction)? - .try_into() - .map_err(|e| (e, "length").into()) - .map_err(|k| InstructionError::new(instruction, k))?; - let memory_view = memory.view(); - - if length == 0 { - runtime.stack.push(InterfaceValue::ByteArray(vec![])); - - return Ok(()) - } - - if memory_view.len() < pointer + length { - return Err(InstructionError::new( - instruction, - InstructionErrorKind::MemoryOutOfBoundsAccess { - index: pointer + length, - length: memory_view.len(), - }, - )); - } - - let data: Vec = (&memory_view[pointer..pointer + length]) - .iter() - .map(Cell::get) - .collect(); - - log::trace!("bytearray.lift_memory: pushing {:?} on the stack", data); - - runtime.stack.push(InterfaceValue::ByteArray(data)); - - Ok(()) - } - } -); - -executable_instruction!( - byte_array_lower_memory(instruction: Instruction) -> _ { - move |runtime| -> _ { - let inputs = runtime.stack.pop(2).ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::StackIsTooSmall { needed: 2 }, - ) - })?; - - let byte_array_pointer: usize = to_native::(&inputs[0], instruction)? - .try_into() - .map_err(|e| (e, "pointer").into()) - .map_err(|k| InstructionError::new(instruction, k))?; - let byte_array: Vec = to_native(&inputs[1], instruction)?; - let byte_array_length: i32 = byte_array.len().try_into().map_err(|_| { - InstructionError::new( - instruction, - InstructionErrorKind::NegativeValue { subject: "string_length" }, - ) - })?; - - let instance = &mut runtime.wasm_instance; - let memory_index: u32 = 0; - let memory_view = instance - .memory(memory_index as usize) - .ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::MemoryIsMissing { memory_index }, - ) - })? - .view(); - - for (nth, byte) in byte_array.iter().enumerate() { - memory_view[byte_array_pointer as usize + nth].set(*byte); - } - - log::trace!("bytearray.lower_memory: pushing {}, {} on the stack", byte_array_pointer, byte_array_length); - - runtime.stack.push(InterfaceValue::I32(byte_array_pointer as i32)); - runtime.stack.push(InterfaceValue::I32(byte_array_length)); - - Ok(()) - } - } -); - -executable_instruction!( - byte_array_size(instruction: Instruction) -> _ { - move |runtime| -> _ { - match runtime.stack.pop1() { - Some(InterfaceValue::ByteArray(byte_array)) => { - let length = byte_array.len() as i32; - runtime.stack.push(InterfaceValue::I32(length)); - - Ok(()) - }, - - Some(value) => Err(InstructionError::new( - instruction, - InstructionErrorKind::InvalidValueOnTheStack { - expected_type: InterfaceType::ByteArray, - received_value: value, - }, - )), - - None => Err(InstructionError::new( - instruction, - InstructionErrorKind::StackIsTooSmall { needed: 1 }, - )), - } - } - } -); diff --git a/src/interpreter/instructions/call_core.rs b/src/interpreter/instructions/call_core.rs index 0f54912..04f168d 100644 --- a/src/interpreter/instructions/call_core.rs +++ b/src/interpreter/instructions/call_core.rs @@ -12,7 +12,7 @@ executable_instruction!( let local_or_import = instance.local_or_import(index).ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::LocalOrImportIsMissing { function_index, }, @@ -22,20 +22,20 @@ executable_instruction!( let inputs = runtime.stack.pop(inputs_cardinality).ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: inputs_cardinality, }, ) })?; - super::check_function_signature(&**instance, local_or_import, &inputs, instruction)?; + super::check_function_signature(&**instance, local_or_import, &inputs, instruction.clone())?; log::trace!("call-core: calling {} with arguments: {:?}", function_index, inputs); let outputs = local_or_import.call(&inputs).map_err(|_| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::LocalOrImportCall { function_index, }, diff --git a/src/interpreter/instructions/dup.rs b/src/interpreter/instructions/dup.rs index 4d455c3..cc4c996 100644 --- a/src/interpreter/instructions/dup.rs +++ b/src/interpreter/instructions/dup.rs @@ -8,7 +8,7 @@ executable_instruction!( move |runtime| -> _ { let value = runtime.stack.peek1().ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, ) })?; diff --git a/src/interpreter/instructions/mod.rs b/src/interpreter/instructions/mod.rs index 518850b..6107889 100644 --- a/src/interpreter/instructions/mod.rs +++ b/src/interpreter/instructions/mod.rs @@ -1,11 +1,12 @@ mod argument_get; -mod byte_arrays; +mod arrays; mod call_core; mod dup; mod numbers; mod records; mod strings; mod swap2; +mod utils; use crate::interpreter::wasm; use crate::types::InterfaceType; @@ -15,7 +16,7 @@ use crate::{ values::{InterfaceValue, NativeType}, }; pub(crate) use argument_get::argument_get; -pub(crate) use byte_arrays::*; +pub(crate) use arrays::*; pub(crate) use call_core::call_core; pub(crate) use dup::dup; pub(crate) use numbers::*; @@ -23,12 +24,13 @@ pub(crate) use records::*; use std::convert::TryFrom; pub(crate) use strings::*; pub(crate) use swap2::swap2; +pub(self) use utils::*; pub(self) const ALLOCATE_FUNC_INDEX: u32 = 0; pub(self) const DEALLOCATE_FUNC_INDEX: u32 = 1; /// Represents all the possible WIT instructions. -#[derive(PartialEq, Debug, Clone, Copy)] +#[derive(PartialEq, Debug, Clone)] pub enum Instruction { /// The `arg.get` instruction. ArgumentGet { @@ -147,14 +149,17 @@ pub enum Instruction { /// The `string.size` instruction. StringSize, - /// The `byte_array.lift_memory` instruction. - ByteArrayLiftMemory, + /// The `array.lift_memory` instruction. + ArrayLiftMemory { + /// Array value type. + value_type: InterfaceType, + }, - /// The `byte_array.lower_memory` instruction. - ByteArrayLowerMemory, - - /// The `string.size` instruction. - ByteArraySize, + /// The `array.lower_memory` instruction. + ArrayLowerMemory { + /// Array value type. + value_type: InterfaceType, + }, /* /// The `record.lift` instruction. @@ -225,7 +230,7 @@ where let func_inputs = local_import.arguments(); for (func_input_arg, value) in func_inputs.iter().zip(values.iter()) { - is_value_compatible_to_type(instance, &func_input_arg.ty, value, instruction)?; + is_value_compatible_to_type(instance, &func_input_arg.ty, value, instruction.clone())?; } Ok(()) @@ -266,7 +271,13 @@ where (InterfaceType::F32, InterfaceValue::F32(_)) => Ok(()), (InterfaceType::F64, InterfaceValue::F64(_)) => Ok(()), (InterfaceType::String, InterfaceValue::String(_)) => Ok(()), - (InterfaceType::ByteArray, InterfaceValue::ByteArray(_)) => Ok(()), + (InterfaceType::Array(ty), InterfaceValue::Array(values)) => { + for value in values { + is_value_compatible_to_type(instance, ty, value, instruction.clone())? + } + + Ok(()) + } (InterfaceType::Record(ref record_type_id), InterfaceValue::Record(record_fields)) => { is_record_fields_compatible_to_type( instance, @@ -309,14 +320,14 @@ where { let record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id }, ) })?; if record_fields.len() != record_type.fields.len() { return Err(InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::InvalidValueOnTheStack { expected_type: InterfaceType::Record(record_type_id), // unwrap is safe here - len's been already checked @@ -332,7 +343,7 @@ where instance, &record_type_field.ty, record_value_field, - instruction, + instruction.clone(), )?; } diff --git a/src/interpreter/instructions/numbers.rs b/src/interpreter/instructions/numbers.rs index 53e4ad3..0d3d0f7 100644 --- a/src/interpreter/instructions/numbers.rs +++ b/src/interpreter/instructions/numbers.rs @@ -19,7 +19,7 @@ macro_rules! lowering_lifting { let converted_value = InterfaceValue::$to_variant(value.try_into().map_err( |_| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::LoweringLifting { from: InterfaceType::$from_variant, to: InterfaceType::$to_variant @@ -35,7 +35,7 @@ macro_rules! lowering_lifting { } Some(wrong_value) => { return Err(InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::InvalidValueOnTheStack { expected_type: InterfaceType::$from_variant, received_value: wrong_value, @@ -45,7 +45,7 @@ macro_rules! lowering_lifting { None => { return Err(InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, )) } diff --git a/src/interpreter/instructions/records.rs b/src/interpreter/instructions/records.rs index c32d85e..a5a5b88 100644 --- a/src/interpreter/instructions/records.rs +++ b/src/interpreter/instructions/records.rs @@ -1,7 +1,5 @@ -mod utils; - -use utils::read_from_instance_mem; -use utils::write_to_instance_mem; +use super::read_from_instance_mem; +use super::write_to_instance_mem; use crate::interpreter::instructions::{is_record_fields_compatible_to_type, to_native}; use crate::{ @@ -12,7 +10,6 @@ use crate::{ vec1::Vec1, }; -use std::collections::VecDeque; use std::convert::TryInto; /* @@ -78,14 +75,14 @@ where let instance = &runtime.wasm_instance; let record_type = match instance.wit_type(type_index).ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::TypeIsMissing { type_index }, ) })? { Type::Record(record_type) => record_type, Type::Function { .. } => { return Err(InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::InvalidTypeKind { expected_kind: TypeKind::Record, received_kind: TypeKind::Function, @@ -94,7 +91,7 @@ where } }; let record = record_lift_(&mut runtime.stack, &record_type) - .map_err(|k| InstructionError::new(instruction, k))?; + .map_err(|k| InstructionError::new(instruction.clone(), k))?; runtime.stack.push(record); Ok(()) } @@ -102,7 +99,7 @@ where } */ -fn record_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>( +pub(super) fn record_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>( instance: &'instance Instance, record_type: &RecordType, offset: usize, @@ -121,7 +118,7 @@ where for field_type in record_type.fields.iter() { let params_count = match field_type.ty { - InterfaceType::String | InterfaceType::ByteArray => 2, + InterfaceType::String | InterfaceType::Array(_) => 2, _ => 1, }; @@ -132,9 +129,9 @@ where } let length = record_type.fields.len(); - let mut values = VecDeque::with_capacity(length); + let mut values = Vec::with_capacity(length); let size = record_size(record_type); - let data = read_from_instance_mem(instance, instruction, offset, size)?; + let data = read_from_instance_mem(instance, instruction.clone(), offset, size)?; // TODO: add error handling let data = safe_transmute::transmute_many::(&data).unwrap(); @@ -144,39 +141,39 @@ where let value = data[field_id]; match &field.ty { InterfaceType::S8 => { - values.push_back(InterfaceValue::S8(value as _)); + values.push(InterfaceValue::S8(value as _)); } InterfaceType::S16 => { - values.push_back(InterfaceValue::S16(value as _)); + values.push(InterfaceValue::S16(value as _)); } InterfaceType::S32 => { - values.push_back(InterfaceValue::S32(value as _)); + values.push(InterfaceValue::S32(value as _)); } InterfaceType::S64 => { - values.push_back(InterfaceValue::S64(value as _)); + values.push(InterfaceValue::S64(value as _)); } InterfaceType::I32 => { - values.push_back(InterfaceValue::I32(value as _)); + values.push(InterfaceValue::I32(value as _)); } InterfaceType::I64 => { - values.push_back(InterfaceValue::I64(value as _)); + values.push(InterfaceValue::I64(value as _)); } InterfaceType::U8 => { - values.push_back(InterfaceValue::U8(value as _)); + values.push(InterfaceValue::U8(value as _)); } InterfaceType::U16 => { - values.push_back(InterfaceValue::U16(value as _)); + values.push(InterfaceValue::U16(value as _)); } InterfaceType::U32 => { - values.push_back(InterfaceValue::U32(value as _)); + values.push(InterfaceValue::U32(value as _)); } InterfaceType::U64 => { - values.push_back(InterfaceValue::U64(value as _)); + values.push(InterfaceValue::U64(value as _)); } InterfaceType::F32 => { - values.push_back(InterfaceValue::F32(value as _)); + values.push(InterfaceValue::F32(value as _)); } - InterfaceType::F64 => values.push_back(InterfaceValue::F64(f64::from_bits(value))), + InterfaceType::F64 => values.push(InterfaceValue::F64(f64::from_bits(value))), InterfaceType::Anyref => {} InterfaceType::String => { let string_offset = value; @@ -186,34 +183,34 @@ where if string_size != 0 { let string_mem = read_from_instance_mem( instance, - instruction, + instruction.clone(), string_offset as _, string_size as _, )?; // TODO: check let string = String::from_utf8(string_mem).unwrap(); - values.push_back(InterfaceValue::String(string)); + values.push(InterfaceValue::String(string)); } else { - values.push_back(InterfaceValue::String(String::new())); + values.push(InterfaceValue::String(String::new())); } } - InterfaceType::ByteArray => { + InterfaceType::Array(ty) => { let array_offset = value; field_id += 1; let array_size = data[field_id]; if array_size != 0 { - let byte_array = read_from_instance_mem( + let array = super::array_lift_memory_( instance, - instruction, + &**ty, array_offset as _, array_size as _, + instruction.clone(), )?; - - values.push_back(InterfaceValue::ByteArray(byte_array)); + values.push(InterfaceValue::Array(array)); } else { - values.push_back(InterfaceValue::ByteArray(vec![])); + values.push(InterfaceValue::Array(vec![])); } } InterfaceType::Record(record_type_id) => { @@ -221,25 +218,25 @@ where let record_type = instance.wit_record_by_id(*record_type_id).ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id: *record_type_id, }, ) })?; - values.push_back(record_lift_memory_( + values.push(record_lift_memory_( instance, record_type, offset as _, - instruction, + instruction.clone(), )?) } } field_id += 1; } - utils::deallocate(instance, instruction, offset as _, size as _)?; + super::deallocate(instance, instruction, offset as _, size as _)?; Ok(InterfaceValue::Record( Vec1::new(values.into_iter().collect()) @@ -265,21 +262,21 @@ where move |runtime| -> _ { let inputs = runtime.stack.pop(1).ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, ) })?; - let offset: usize = to_native::(&inputs[0], instruction)? + let offset: usize = to_native::(&inputs[0], instruction.clone())? .try_into() .map_err(|e| (e, "offset").into()) - .map_err(|k| InstructionError::new(instruction, k))?; + .map_err(|k| InstructionError::new(instruction.clone(), k))?; // TODO: size = 0 let instance = &runtime.wasm_instance; let record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id }, ) })?; @@ -290,7 +287,8 @@ where record_type_id ); - let record = record_lift_memory_(&**instance, record_type, offset, instruction)?; + let record = + record_lift_memory_(&**instance, record_type, offset, instruction.clone())?; log::trace!("record.lift_memory: pushing {:?} on the stack", record); runtime.stack.push(record); @@ -300,7 +298,7 @@ where }) } -fn record_lower_memory_( +pub(super) fn record_lower_memory_( instance: &mut Instance, instruction: Instruction, values: Vec1, @@ -331,7 +329,7 @@ where InterfaceValue::F64(value) => result.push(value.to_bits()), InterfaceValue::String(value) => { let string_pointer = if !value.is_empty() { - write_to_instance_mem(instance, instruction, value.as_bytes())? + write_to_instance_mem(instance, instruction.clone(), value.as_bytes())? } else { 0 }; @@ -340,19 +338,19 @@ where result.push(value.len() as _); } - InterfaceValue::ByteArray(value) => { - let byte_array_pointer = if !value.is_empty() { - write_to_instance_mem(instance, instruction, &value)? + InterfaceValue::Array(values) => { + let (offset, size) = if !values.is_empty() { + super::array_lower_memory_(instance, instruction.clone(), values)? } else { - 0 + (0, 0) }; - result.push(byte_array_pointer as _); - result.push(value.len() as _); + result.push(offset as _); + result.push(size as _); } InterfaceValue::Record(values) => { - let record_ptr = record_lower_memory_(instance, instruction, values)?; + let record_ptr = record_lower_memory_(instance, instruction.clone(), values)?; result.push(record_ptr as _); } @@ -389,27 +387,28 @@ where &**instance, record_type_id, &record_fields, - instruction, + instruction.clone(), )?; log::trace!("record.lower_memory: obtained {:?} values on the stack for record type = {}", record_fields, record_type_id); - let offset = record_lower_memory_(*instance, instruction, record_fields)?; + let offset = + record_lower_memory_(*instance, instruction.clone(), record_fields)?; - log::trace!("record.lower_memory: pushing {:?} on the stack", offset); + log::trace!("record.lower_memory: pushing {} on the stack", offset); runtime.stack.push(InterfaceValue::I32(offset)); Ok(()) } Some(value) => Err(InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::InvalidValueOnTheStack { expected_type: InterfaceType::Record(record_type_id), received_value: value, }, )), None => Err(InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, )), } @@ -437,14 +436,14 @@ where let instance = &runtime.wasm_instance; let record_type = match instance.wit_type(type_index).ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::TypeIsMissing { type_index }, ) })? { Type::Record(record_type) => record_type, Type::Function { .. } => { return Err(InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::InvalidTypeKind { expected_kind: TypeKind::Record, received_kind: TypeKind::Function, @@ -463,14 +462,14 @@ where Ok(()) } Some(value) => Err(InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::InvalidValueOnTheStack { expected_type: InterfaceType::Record(record_type.clone()), received_type: (&value).into(), }, )), None => Err(InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, )), } diff --git a/src/interpreter/instructions/strings.rs b/src/interpreter/instructions/strings.rs index 93876bd..f30dd85 100644 --- a/src/interpreter/instructions/strings.rs +++ b/src/interpreter/instructions/strings.rs @@ -12,7 +12,7 @@ executable_instruction!( move |runtime| -> _ { let inputs = runtime.stack.pop(2).ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 2 }, ) })?; @@ -23,19 +23,19 @@ executable_instruction!( .memory(memory_index as usize) .ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::MemoryIsMissing { memory_index }, ) })?; - let pointer: usize = to_native::(&inputs[0], instruction)? + let pointer: usize = to_native::(&inputs[0], instruction.clone())? .try_into() .map_err(|e| (e, "pointer").into()) - .map_err(|k| InstructionError::new(instruction, k))?; - let length: usize = to_native::(&inputs[1], instruction)? + .map_err(|k| InstructionError::new(instruction.clone(), k))?; + let length: usize = to_native::(&inputs[1], instruction.clone())? .try_into() .map_err(|e| (e, "length").into()) - .map_err(|k| InstructionError::new(instruction, k))?; + .map_err(|k| InstructionError::new(instruction.clone(), k))?; let memory_view = memory.view(); if length == 0 { @@ -46,7 +46,7 @@ executable_instruction!( if memory_view.len() < pointer + length { return Err(InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::MemoryOutOfBoundsAccess { index: pointer + length, length: memory_view.len(), @@ -60,7 +60,7 @@ executable_instruction!( .collect(); let string = String::from_utf8(data) - .map_err(|error| InstructionError::new(instruction, InstructionErrorKind::String(error)))?; + .map_err(|error| InstructionError::new(instruction.clone(), InstructionErrorKind::String(error)))?; log::trace!("string.lift_memory: pushing {:?} on the stack", string); runtime.stack.push(InterfaceValue::String(string)); @@ -75,20 +75,20 @@ executable_instruction!( move |runtime| -> _ { let inputs = runtime.stack.pop(2).ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 2 }, ) })?; - let string_pointer: usize = to_native::(&inputs[0], instruction)? + let string_pointer: usize = to_native::(&inputs[0], instruction.clone())? .try_into() .map_err(|e| (e, "pointer").into()) - .map_err(|k| InstructionError::new(instruction, k))?; - let string: String = to_native(&inputs[1], instruction)?; + .map_err(|k| InstructionError::new(instruction.clone(), k))?; + let string: String = to_native(&inputs[1], instruction.clone())?; let string_bytes = string.as_bytes(); let string_length: i32 = string_bytes.len().try_into().map_err(|_| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::NegativeValue { subject: "string_length" }, ) })?; @@ -99,7 +99,7 @@ executable_instruction!( .memory(memory_index as usize) .ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::MemoryIsMissing { memory_index }, ) })? @@ -132,7 +132,7 @@ executable_instruction!( }, Some(value) => Err(InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::InvalidValueOnTheStack { expected_type: InterfaceType::String, received_value: (&value).clone(), @@ -140,7 +140,7 @@ executable_instruction!( )), None => Err(InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, )), } diff --git a/src/interpreter/instructions/swap2.rs b/src/interpreter/instructions/swap2.rs index 6a487c5..ad08bea 100644 --- a/src/interpreter/instructions/swap2.rs +++ b/src/interpreter/instructions/swap2.rs @@ -8,7 +8,7 @@ executable_instruction!( move |runtime| -> _ { let mut values = runtime.stack.pop(2).ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::StackIsTooSmall { needed: 1 }, ) })?; diff --git a/src/interpreter/instructions/records/utils.rs b/src/interpreter/instructions/utils.rs similarity index 95% rename from src/interpreter/instructions/records/utils.rs rename to src/interpreter/instructions/utils.rs index 9791463..6ebd4ca 100644 --- a/src/interpreter/instructions/records/utils.rs +++ b/src/interpreter/instructions/utils.rs @@ -29,7 +29,7 @@ where .memory(memory_index as usize) .ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::MemoryIsMissing { memory_index }, ) })? @@ -66,14 +66,14 @@ where MemoryView: wasm::structures::MemoryView, Instance: wasm::structures::Instance, { - let offset = allocate(instance, instruction, bytes.len() as _)?; + let offset = allocate(instance, instruction.clone(), bytes.len() as _)?; let memory_index: u32 = 0; let memory_view = instance .memory(memory_index as usize) .ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::MemoryIsMissing { memory_index }, ) })? @@ -114,7 +114,7 @@ where let values = call_core( instance, ALLOCATE_FUNC_INDEX, - instruction, + instruction.clone(), vec![InterfaceValue::I32(size as _)], )?; if values.len() != 1 { @@ -169,7 +169,7 @@ where let index = FunctionIndex::new(function_index as usize); let local_or_import = instance.local_or_import(index).ok_or_else(|| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::LocalOrImportIsMissing { function_index }, ) })?; @@ -178,12 +178,12 @@ where instance, local_or_import, &inputs, - instruction, + instruction.clone(), )?; let outputs = local_or_import.call(&inputs).map_err(|_| { InstructionError::new( - instruction, + instruction.clone(), InstructionErrorKind::LocalOrImportCall { function_index }, ) })?; diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 5ff7bd4..37a106e 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -177,7 +177,7 @@ where } /// Transforms a `Vec` into an `Interpreter`. -impl TryFrom<&Vec> +impl TryFrom> for Interpreter where Export: wasm::structures::Export, @@ -188,79 +188,79 @@ where { type Error = (); - fn try_from(instructions: &Vec) -> Result { + fn try_from(instructions: Vec) -> Result { let executable_instructions = instructions - .iter() + .into_iter() .map(|instruction| match instruction { Instruction::ArgumentGet { index } => { - instructions::argument_get(*index, *instruction) + instructions::argument_get(index, instruction) } Instruction::CallCore { function_index } => { - instructions::call_core(*function_index, *instruction) + instructions::call_core(function_index, instruction) } - Instruction::S8FromI32 => instructions::s8_from_i32(*instruction), - Instruction::S8FromI64 => instructions::s8_from_i64(*instruction), - Instruction::S16FromI32 => instructions::s16_from_i32(*instruction), - Instruction::S16FromI64 => instructions::s16_from_i64(*instruction), - Instruction::S32FromI32 => instructions::s32_from_i32(*instruction), - Instruction::S32FromI64 => instructions::s32_from_i64(*instruction), - Instruction::S64FromI32 => instructions::s64_from_i32(*instruction), - Instruction::S64FromI64 => instructions::s64_from_i64(*instruction), - Instruction::I32FromS8 => instructions::i32_from_s8(*instruction), - Instruction::I32FromS16 => instructions::i32_from_s16(*instruction), - Instruction::I32FromS32 => instructions::i32_from_s32(*instruction), - Instruction::I32FromS64 => instructions::i32_from_s64(*instruction), - Instruction::I64FromS8 => instructions::i64_from_s8(*instruction), - Instruction::I64FromS16 => instructions::i64_from_s16(*instruction), - Instruction::I64FromS32 => instructions::i64_from_s32(*instruction), - Instruction::I64FromS64 => instructions::i64_from_s64(*instruction), - Instruction::U8FromI32 => instructions::u8_from_i32(*instruction), - Instruction::U8FromI64 => instructions::u8_from_i64(*instruction), - Instruction::U16FromI32 => instructions::u16_from_i32(*instruction), - Instruction::U16FromI64 => instructions::u16_from_i64(*instruction), - Instruction::U32FromI32 => instructions::u32_from_i32(*instruction), - Instruction::U32FromI64 => instructions::u32_from_i64(*instruction), - Instruction::U64FromI32 => instructions::u64_from_i32(*instruction), - Instruction::U64FromI64 => instructions::u64_from_i64(*instruction), - Instruction::I32FromU8 => instructions::i32_from_u8(*instruction), - Instruction::I32FromU16 => instructions::i32_from_u16(*instruction), - Instruction::I32FromU32 => instructions::i32_from_u32(*instruction), - Instruction::I32FromU64 => instructions::i32_from_u64(*instruction), - Instruction::I64FromU8 => instructions::i64_from_u8(*instruction), - Instruction::I64FromU16 => instructions::i64_from_u16(*instruction), - Instruction::I64FromU32 => instructions::i64_from_u32(*instruction), - Instruction::I64FromU64 => instructions::i64_from_u64(*instruction), + Instruction::S8FromI32 => instructions::s8_from_i32(instruction), + Instruction::S8FromI64 => instructions::s8_from_i64(instruction), + Instruction::S16FromI32 => instructions::s16_from_i32(instruction), + Instruction::S16FromI64 => instructions::s16_from_i64(instruction), + Instruction::S32FromI32 => instructions::s32_from_i32(instruction), + Instruction::S32FromI64 => instructions::s32_from_i64(instruction), + Instruction::S64FromI32 => instructions::s64_from_i32(instruction), + Instruction::S64FromI64 => instructions::s64_from_i64(instruction), + Instruction::I32FromS8 => instructions::i32_from_s8(instruction), + Instruction::I32FromS16 => instructions::i32_from_s16(instruction), + Instruction::I32FromS32 => instructions::i32_from_s32(instruction), + Instruction::I32FromS64 => instructions::i32_from_s64(instruction), + Instruction::I64FromS8 => instructions::i64_from_s8(instruction), + Instruction::I64FromS16 => instructions::i64_from_s16(instruction), + Instruction::I64FromS32 => instructions::i64_from_s32(instruction), + Instruction::I64FromS64 => instructions::i64_from_s64(instruction), + Instruction::U8FromI32 => instructions::u8_from_i32(instruction), + Instruction::U8FromI64 => instructions::u8_from_i64(instruction), + Instruction::U16FromI32 => instructions::u16_from_i32(instruction), + Instruction::U16FromI64 => instructions::u16_from_i64(instruction), + Instruction::U32FromI32 => instructions::u32_from_i32(instruction), + Instruction::U32FromI64 => instructions::u32_from_i64(instruction), + Instruction::U64FromI32 => instructions::u64_from_i32(instruction), + Instruction::U64FromI64 => instructions::u64_from_i64(instruction), + Instruction::I32FromU8 => instructions::i32_from_u8(instruction), + Instruction::I32FromU16 => instructions::i32_from_u16(instruction), + Instruction::I32FromU32 => instructions::i32_from_u32(instruction), + Instruction::I32FromU64 => instructions::i32_from_u64(instruction), + Instruction::I64FromU8 => instructions::i64_from_u8(instruction), + Instruction::I64FromU16 => instructions::i64_from_u16(instruction), + Instruction::I64FromU32 => instructions::i64_from_u32(instruction), + Instruction::I64FromU64 => instructions::i64_from_u64(instruction), - Instruction::StringLiftMemory => instructions::string_lift_memory(*instruction), - Instruction::StringLowerMemory => instructions::string_lower_memory(*instruction), - Instruction::StringSize => instructions::string_size(*instruction), - - Instruction::ByteArrayLiftMemory => { - instructions::byte_array_lift_memory(*instruction) + Instruction::StringLiftMemory => instructions::string_lift_memory(instruction), + Instruction::StringLowerMemory => instructions::string_lower_memory(instruction), + Instruction::StringSize => instructions::string_size(instruction), + Instruction::ArrayLiftMemory { ref value_type } => { + let value_type = value_type.clone(); + instructions::array_lift_memory(instruction, value_type) } - Instruction::ByteArrayLowerMemory => { - instructions::byte_array_lower_memory(*instruction) + Instruction::ArrayLowerMemory { ref value_type } => { + let value_type = value_type.clone(); + instructions::array_lower_memory(instruction, value_type) } - Instruction::ByteArraySize => instructions::byte_array_size(*instruction), /* Instruction::RecordLift { type_index } => { - instructions::record_lift(*type_index, *instruction) + instructions::record_lift(*type_index, instruction) } Instruction::RecordLower { type_index } => { - instructions::record_lower(*type_index, *instruction) + instructions::record_lower(*type_index, instruction) } */ Instruction::RecordLiftMemory { record_type_id } => { - instructions::record_lift_memory(*record_type_id as _, *instruction) + instructions::record_lift_memory(record_type_id as _, instruction) } Instruction::RecordLowerMemory { record_type_id } => { - instructions::record_lower_memory(*record_type_id as _, *instruction) + instructions::record_lower_memory(record_type_id as _, instruction) } - Instruction::Dup => instructions::dup(*instruction), - Instruction::Swap2 => instructions::swap2(*instruction), + Instruction::Dup => instructions::dup(instruction), + Instruction::Swap2 => instructions::swap2(instruction), }) .collect(); diff --git a/src/macros.rs b/src/macros.rs index 88e7674..08f57c9 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -43,7 +43,7 @@ macro_rules! consume { /// /// # Example /// -/// The following example creates a `foo` executable instruction, +/// The following example creates a `foo` executable instruction.clone(), /// which takes 2 arguments (`x` and `y`), and does something /// mysterious by using the `interpreter::Runtime` API. /// diff --git a/src/serde/de.rs b/src/serde/de.rs index 9d901ea..d756ad6 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -129,16 +129,19 @@ impl<'de> Deserializer<'de> { } } - fn next_byte_array(&mut self) -> Result<&'de [u8], DeserializeError> { + fn next_array(&mut self) -> Result<&'de [u8], DeserializeError> { match self.iterator.peek() { - Some(InterfaceValue::ByteArray(v)) => { + Some(InterfaceValue::Array(_)) => { self.iterator.next(); - Ok(v) + // Ok(v) + + unimplemented!() } Some(wrong_value) => Err(DeserializeError::TypeMismatch { - expected_type: InterfaceType::ByteArray, + // TODO: change default + expected_type: InterfaceType::Array(Box::new(InterfaceType::S8)), received_value: (*wrong_value).clone(), }), @@ -217,7 +220,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { Some(InterfaceValue::F32(_)) => self.deserialize_f32(visitor), Some(InterfaceValue::F64(_)) => self.deserialize_f64(visitor), Some(InterfaceValue::String(_)) => self.deserialize_string(visitor), - Some(InterfaceValue::ByteArray(_)) => self.deserialize_bytes(visitor), + Some(InterfaceValue::Array(_)) => self.deserialize_bytes(visitor), Some(InterfaceValue::I32(_)) => self.deserialize_i32(visitor), Some(InterfaceValue::I64(_)) => self.deserialize_i64(visitor), Some(InterfaceValue::Record(..)) => unreachable!("Records should have been flattened."), // already flattened @@ -331,7 +334,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: de::Visitor<'de>, { - visitor.visit_bytes(self.next_byte_array()?) + visitor.visit_bytes(self.next_array()?) } fn deserialize_byte_buf(self, _visitor: V) -> Result diff --git a/src/types.rs b/src/types.rs index 15472ed..95bb2da 100644 --- a/src/types.rs +++ b/src/types.rs @@ -39,8 +39,8 @@ pub enum InterfaceType { /// A string. String, - /// A byte array. - ByteArray, + /// An array of values of the same type. + Array(Box), /// An `any` reference. Anyref, @@ -48,7 +48,7 @@ pub enum InterfaceType { /// A 32-bits integer (as defined in WebAssembly core). I32, - /// A 64-bits integer (as defiend in WebAssembly core). + /// A 64-bits integer (as defined in WebAssembly core). I64, /// A record contains record index from interfaces AST. diff --git a/src/values.rs b/src/values.rs index 4cb952a..1322ae3 100644 --- a/src/values.rs +++ b/src/values.rs @@ -43,7 +43,7 @@ pub enum InterfaceValue { String(String), /// A byte array. - ByteArray(Vec), + Array(Vec), //Anyref(?), /// A 32-bits integer (as defined in WebAssembly core). @@ -107,7 +107,6 @@ native!(u64, U64); native!(f32, F32); native!(f64, F64); native!(String, String); -native!(Vec, ByteArray); /// Iterates over a vector of `InterfaceValues` but flatten all the /// values. So `I32(1), Record([I32(2), I32(3)]), I32(4)` will be