add byte array handler

This commit is contained in:
vms 2020-07-09 02:46:54 +03:00
parent 689c6757fb
commit bb9e4dbdfc
10 changed files with 206 additions and 2 deletions

View File

@ -92,6 +92,7 @@ fn ty<'input, E: ParseError<&'input [u8]>>(
0x08 => InterfaceType::F32,
0x09 => InterfaceType::F64,
0x0a => InterfaceType::String,
0x36 => InterfaceType::ByteArray,
0x0b => InterfaceType::Anyref,
0x0c => InterfaceType::I32,
0x0d => InterfaceType::I64,
@ -235,6 +236,10 @@ 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),
0x25 => {
consume!((input, argument_0) = uleb(input)?);

View File

@ -27,6 +27,7 @@ mod keyword {
custom_keyword!(u32);
custom_keyword!(u64);
custom_keyword!(string);
custom_keyword!(byte_array);
// Instructions.
custom_keyword!(argument_get = "arg.get");
@ -66,6 +67,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!(record_lift = "record.lift");
custom_keyword!(record_lower = "record.lower");
custom_keyword!(dup = "dup");
@ -120,6 +124,10 @@ impl Parse<'_> for InterfaceType {
parser.parse::<keyword::string>()?;
Ok(InterfaceType::String)
} else if lookahead.peek::<keyword::byte_array>() {
parser.parse::<keyword::byte_array>()?;
Ok(InterfaceType::ByteArray)
} else if lookahead.peek::<keyword::anyref>() {
parser.parse::<keyword::anyref>()?;

View File

@ -105,6 +105,7 @@ 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::Anyref => 0x0b_u8.to_bytes(writer),
InterfaceType::I32 => 0x0c_u8.to_bytes(writer),
InterfaceType::I64 => 0x0d_u8.to_bytes(writer),
@ -334,6 +335,10 @@ 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::RecordLift { type_index } => {
0x25_u8.to_bytes(writer)?;
(*type_index as u64).to_bytes(writer)?

View File

@ -73,6 +73,7 @@ impl ToString for &InterfaceType {
InterfaceType::F32 => "f32".to_string(),
InterfaceType::F64 => "f64".to_string(),
InterfaceType::String => "string".to_string(),
InterfaceType::ByteArray => "byteArray".to_string(),
InterfaceType::Anyref => "anyref".to_string(),
InterfaceType::I32 => "i32".to_string(),
InterfaceType::I64 => "i64".to_string(),
@ -138,6 +139,9 @@ 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::RecordLift { type_index } => format!("record.lift {}", type_index),
Instruction::RecordLower { type_index } => format!("record.lower {}", type_index),
Instruction::Dup => "dup".into(),

View File

@ -0,0 +1,141 @@
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::<i32>(&inputs[0], instruction)?
.try_into()
.map_err(|e| (e, "pointer").into())
.map_err(|k| InstructionError::new(instruction, k))?;
let length: usize = to_native::<i32>(&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::String("".into()));
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<u8> = (&memory_view[pointer..pointer + length])
.iter()
.map(Cell::get)
.collect();
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::<i32>(&inputs[0], instruction)?
.try_into()
.map_err(|e| (e, "pointer").into())
.map_err(|k| InstructionError::new(instruction, k))?;
let byte_array: Vec<u8> = 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);
}
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_type: (&value).into(),
},
)),
None => Err(InstructionError::new(
instruction,
InstructionErrorKind::StackIsTooSmall { needed: 1 },
)),
}
}
}
);

View File

@ -1,4 +1,5 @@
mod argument_get;
mod byte_arrays;
mod call_core;
mod numbers;
mod records;
@ -11,6 +12,7 @@ use crate::{
values::{InterfaceValue, NativeType},
};
pub(crate) use argument_get::argument_get;
pub(crate) use byte_arrays::*;
pub(crate) use call_core::call_core;
pub(crate) use numbers::*;
pub(crate) use records::*;
@ -139,6 +141,15 @@ pub enum Instruction {
/// The `string.size` instruction.
StringSize,
/// The `string.lift_memory` instruction.
ByteArrayLiftMemory,
/// The `string.lower_memory` instruction.
ByteArrayLowerMemory,
/// The `string.size` instruction.
ByteArraySize,
/// The `record.lift` instruction.
RecordLift {
/// The type index of the record.

View File

@ -238,6 +238,10 @@ where
Instruction::StringLowerMemory => instructions::string_lower_memory(*instruction),
Instruction::StringSize => instructions::string_size(*instruction),
Instruction::ByteArrayLiftMemory => instructions::byte_array_lift_memory(*instruction),
Instruction::ByteArrayLowerMemory => instructions::byte_array_lower_memory(*instruction),
Instruction::ByteArraySize => instructions::byte_array_size(*instruction),
Instruction::RecordLift { type_index } => {
instructions::record_lift(*type_index, *instruction)
}

View File

@ -129,6 +129,23 @@ impl<'de> Deserializer<'de> {
}
}
fn next_byte_array(&mut self) -> Result<&'de [u8], DeserializeError> {
match self.iterator.peek() {
Some(InterfaceValue::ByteArray(v)) => {
self.iterator.next();
Ok(v)
}
Some(wrong_value) => Err(DeserializeError::TypeMismatch {
expected_type: InterfaceType::ByteArray,
received_type: (*wrong_value).into(),
}),
None => Err(DeserializeError::InputEmpty),
}
}
next!(next_i32, I32, i32);
next!(next_i64, I64, i64);
}
@ -200,6 +217,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::I32(_)) => self.deserialize_i32(visitor),
Some(InterfaceValue::I64(_)) => self.deserialize_i64(visitor),
Some(InterfaceValue::Record(_)) => unreachable!("Records should have been flattened."), // already flattened
@ -309,11 +327,11 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
self.deserialize_str(visitor)
}
fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
todo!("`bytes` is not supported by WIT for the moment.")
visitor.visit_bytes(self.next_byte_array()?)
}
fn deserialize_byte_buf<V>(self, _visitor: V) -> Result<V::Value, Self::Error>

View File

@ -39,6 +39,9 @@ pub enum InterfaceType {
/// A string.
String,
/// A byte array.
ByteArray,
/// An `any` reference.
Anyref,

View File

@ -46,6 +46,9 @@ pub enum InterfaceValue {
/// A string.
String(String),
/// A byte array.
ByteArray(Vec<u8>),
//Anyref(?),
/// A 32-bits integer (as defined in WebAssembly core).
I32(i32),
@ -71,6 +74,7 @@ impl From<&InterfaceValue> for InterfaceType {
InterfaceValue::F32(_) => Self::F32,
InterfaceValue::F64(_) => Self::F64,
InterfaceValue::String(_) => Self::String,
InterfaceValue::ByteArray(_) => Self::ByteArray,
//InterfaceValue::Anyref(_) => Self::Anyref,
InterfaceValue::I32(_) => Self::I32,
InterfaceValue::I64(_) => Self::I64,
@ -139,6 +143,7 @@ native!(u64, U64);
native!(f32, F32);
native!(f64, F64);
native!(String, String);
native!(Vec<u8>, ByteArray);
/// Iterates over a vector of `InterfaceValues` but flatten all the
/// values. So `I32(1), Record([I32(2), I32(3)]), I32(4)` will be