support u128

This commit is contained in:
vms 2021-04-23 10:13:11 +03:00
parent 9095389a5a
commit 34bf8a196a
22 changed files with 264 additions and 32 deletions

View File

@ -37,6 +37,7 @@ pub fn ser_type_size(ty: &IType) -> usize {
// Vec-like types are passed by pointer and size
IType::String | IType::ByteArray | IType::Array(_) => 2 * WASM_POINTER_SIZE,
IType::S64 | IType::U64 | IType::I64 | IType::F64 => 8,
IType::U128 => 16,
}
}
@ -47,6 +48,7 @@ pub fn ser_value_size(value: &IValue) -> usize {
IValue::S16(_) | IValue::U16(_) => 2,
IValue::S32(_) | IValue::U32(_) | IValue::F32(_) | IValue::I32(_) => 4,
IValue::S64(_) | IValue::U64(_) | IValue::F64(_) | IValue::I64(_) => 8,
IValue::U128(_) => 16,
IValue::String(_) | IValue::ByteArray(_) | IValue::Array(_) => 2 * 4,
IValue::Record(_) => 4,
}
@ -70,12 +72,13 @@ pub fn type_tag_form_itype(itype: &IType) -> u32 {
IType::U16 => 2, // u16
IType::U32 => 3, // u32
IType::U64 => 4, // u64
IType::S8 => 5, // i8
IType::S16 => 6, // i16
IType::S32 | IType::I32 => 7, // i32
IType::S64 | IType::I64 => 8, // i64
IType::F32 => 9, // f32
IType::F64 => 10, // f64
IType::U128 => 5, // u128
IType::S8 => 6, // i8
IType::S16 => 7, // i16
IType::S32 | IType::I32 => 8, // i32
IType::S64 | IType::I64 => 9, // i64
IType::F32 => 10, // f32
IType::F64 => 11, // f64
IType::ByteArray | IType::Array(_) | IType::Record(_) | IType::String => POINTER_CODE,
}
}
@ -89,12 +92,13 @@ pub fn type_tag_form_ivalue(itype: &IValue) -> u32 {
IValue::U16(_) => 2, // u16
IValue::U32(_) => 3, // u32
IValue::U64(_) => 4, // u64
IValue::S8(_) => 5, // i8
IValue::S16(_) => 6, // i16
IValue::S32(_) | IValue::I32(_) => 7, // i32
IValue::S64(_) | IValue::I64(_) => 8, // i64
IValue::F32(_) => 9, // f32
IValue::F64(_) => 10, // f64
IValue::U128(_) => 5, // u128
IValue::S8(_) => 6, // i8
IValue::S16(_) => 7, // i16
IValue::S32(_) | IValue::I32(_) => 8, // i32
IValue::S64(_) | IValue::I64(_) => 9, // i64
IValue::F32(_) => 10, // f32
IValue::F64(_) => 11, // f64
IValue::ByteArray(_) | IValue::Array(_) | IValue::Record(_) | IValue::String(_) => {
POINTER_CODE
}

View File

@ -35,6 +35,10 @@ macro_rules! value_der {
($self:expr, $offset:expr, 8) => {
crate::value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7 @seq_end);
};
($self:expr, $offset:expr, 16) => {
crate::value_der!($self, $offset, @seq_start 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 @seq_end);
};
}
#[macro_export]
@ -78,6 +82,16 @@ macro_rules! read_ty {
result
}
};
($func_name:ident, $ty:ty, 16) => {
pub fn $func_name(&self) -> $ty {
let offset = self.offset.get();
let result = <$ty>::from_le_bytes(crate::value_der!(self, offset, 16));
self.offset.set(offset + 16);
result
}
};
}
#[macro_export]

View File

@ -103,6 +103,7 @@ impl<'m> MemoryReader<'m> {
read_array_ty!(read_s64_array, i64, S64);
read_array_ty!(read_i64_array, i64, I64);
read_array_ty!(read_f64_array, f64, F64);
read_array_ty!(read_u128_array, u128, U128);
}
impl<'r, 'm> SequentialReader<'r, 'm> {
@ -129,4 +130,5 @@ impl<'r, 'm> SequentialReader<'r, 'm> {
read_ty!(read_u64, u64, 8);
read_ty!(read_i64, i64, 8);
read_ty!(read_f64, f64, 8);
read_ty!(read_u128, u128, 16);
}

View File

@ -29,6 +29,7 @@ where
IType::U64 => 0x07_u8.to_bytes(writer),
IType::F32 => 0x08_u8.to_bytes(writer),
IType::F64 => 0x09_u8.to_bytes(writer),
IType::U128 => 0x46_u8.to_bytes(writer),
IType::String => 0x0a_u8.to_bytes(writer),
IType::ByteArray => 0x3C_u8.to_bytes(writer),
IType::Array(ty) => {
@ -87,6 +88,7 @@ mod keyword {
custom_keyword!(u16);
custom_keyword!(u32);
custom_keyword!(u64);
custom_keyword!(u128);
custom_keyword!(string);
custom_keyword!(array);
}
@ -138,6 +140,10 @@ impl Parse<'_> for IType {
parser.parse::<keyword::f64>()?;
Ok(IType::F64)
} else if lookahead.peek::<keyword::u128>() {
parser.parse::<keyword::u128>()?;
Ok(IType::U128)
} else if lookahead.peek::<keyword::string>() {
parser.parse::<keyword::string>()?;

View File

@ -22,14 +22,14 @@ macro_rules! native {
}
}
impl TryFrom<&IValue> for $native_type {
impl TryFrom<IValue> for $native_type {
type Error = WasmValueNativeCastError;
fn try_from(w: &IValue) -> Result<Self, Self::Error> {
fn try_from(w: IValue) -> Result<Self, Self::Error> {
match w {
IValue::$variant(n) => Ok(n.clone()),
IValue::$variant(n) => Ok(n),
_ => Err(WasmValueNativeCastError {
from: w.clone(),
from: w,
to: <$native_type>::INTERFACE_TYPE,
}),
}
@ -48,4 +48,6 @@ native!(u32, U32);
native!(u64, U64);
native!(f32, F32);
native!(f64, F64);
native!(u128, U128);
native!(String, String);
native!(Vec<u8>, ByteArray);

View File

@ -41,6 +41,9 @@ pub enum IType {
/// A 64-bits float.
F64,
/// A 128-bit unsigned integer.
U128,
/// A string.
String,
@ -112,6 +115,7 @@ impl ToString for &IType {
IType::U64 => "u64".to_string(),
IType::F32 => "f32".to_string(),
IType::F64 => "f64".to_string(),
IType::U128 => "u128".to_string(),
IType::String => "string".to_string(),
IType::ByteArray => "array (u8)".to_string(),
IType::Array(ty) => format!("array ({})", ty.as_ref().to_string()),

View File

@ -38,6 +38,9 @@ pub enum IValue {
/// A 64-bits float.
F64(f64),
/// A 128-bits integer.
U128(u128),
/// A string.
String(String),

View File

@ -298,6 +298,10 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
0x23 => (input, Instruction::StringLowerMemory),
0x24 => (input, Instruction::StringSize),
0x43 => (input, Instruction::ByteArrayLiftMemory),
0x44 => (input, Instruction::ByteArrayLowerMemory),
0x45 => (input, Instruction::ByteArraySize),
0x37 => {
consume!((input, value_type) = ty(input)?);

View File

@ -80,6 +80,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");
@ -260,6 +263,18 @@ impl<'a> Parse<'a> for Instruction {
} else if lookahead.peek::<keyword::string_size>() {
parser.parse::<keyword::string_size>()?;
Ok(Instruction::StringSize)
} else if lookahead.peek::<keyword::byte_array_lift_memory>() {
parser.parse::<keyword::byte_array_lift_memory>()?;
Ok(Instruction::StringLiftMemory)
} else if lookahead.peek::<keyword::byte_array_lower_memory>() {
parser.parse::<keyword::byte_array_lower_memory>()?;
Ok(Instruction::StringLowerMemory)
} else if lookahead.peek::<keyword::byte_array_size>() {
parser.parse::<keyword::byte_array_size>()?;
Ok(Instruction::StringSize)
} else if lookahead.peek::<keyword::array_lift_memory>() {
parser.parse::<keyword::array_lift_memory>()?;

View File

@ -235,6 +235,10 @@ where
Instruction::StringLowerMemory => 0x23_u8.to_bytes(writer)?,
Instruction::StringSize => 0x24_u8.to_bytes(writer)?,
Instruction::ByteArrayLiftMemory => 0x43_u8.to_bytes(writer)?,
Instruction::ByteArrayLowerMemory => 0x44_u8.to_bytes(writer)?,
Instruction::ByteArraySize => 0x45_u8.to_bytes(writer)?,
Instruction::ArrayLiftMemory { value_type } => {
0x37_u8.to_bytes(writer)?;
value_type.to_bytes(writer)?

View File

@ -102,6 +102,11 @@ 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.to_string())
}

View File

@ -33,19 +33,19 @@ where
use crate::interpreter::stack::Stackable;
Box::new({
move |runtime| -> _ {
let inputs = runtime.stack.pop(2).ok_or_else(|| {
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
InstructionError::from_error_kind(
instruction.clone(),
InstructionErrorKind::StackIsTooSmall { needed: 1 },
)
})?;
let offset: usize = to_native::<i32>(&inputs[0], instruction.clone())?
let offset: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
.try_into()
.map_err(|e| (e, "offset").into())
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
let size: usize = to_native::<i32>(&inputs[1], instruction.clone())?
let size: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
.try_into()
.map_err(|e| (e, "size").into())
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;

View File

@ -30,6 +30,7 @@ pub(crate) fn array_lift_memory_impl(
IType::U16 => reader.read_u16_array(offset, elements_count)?,
IType::U32 => reader.read_u32_array(offset, elements_count)?,
IType::U64 => reader.read_u64_array(offset, elements_count)?,
IType::U128 => reader.read_u128_array(offset, elements_count)?,
IType::F32 => reader.read_f32_array(offset, elements_count)?,
IType::F64 => reader.read_f64_array(offset, elements_count)?,
IType::String => read_string_array(li_helper, offset, elements_count)?,

View File

@ -40,6 +40,7 @@ pub(crate) fn array_lower_memory_impl(
IValue::U16(value) => seq_writer.write_array(value.to_le_bytes()),
IValue::U32(value) => seq_writer.write_array(value.to_le_bytes()),
IValue::U64(value) => seq_writer.write_array(value.to_le_bytes()),
IValue::U128(value) => seq_writer.write_array(value.to_le_bytes()),
IValue::I32(value) => seq_writer.write_array(value.to_le_bytes()),
IValue::I64(value) => seq_writer.write_array(value.to_le_bytes()),
IValue::F32(value) => seq_writer.write_array(value.to_le_bytes()),

View File

@ -0,0 +1,147 @@
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!(
byte_array_lift_memory(instruction: Instruction) -> _ {
move |runtime| -> _ {
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
InstructionError::from_error_kind(
instruction.clone(),
InstructionErrorKind::StackIsTooSmall { needed: 2 },
)
})?;
let memory_index = 0;
let memory = runtime
.wasm_instance
.memory(memory_index)
.ok_or_else(|| {
InstructionError::from_error_kind(
instruction.clone(),
InstructionErrorKind::MemoryIsMissing { memory_index },
)
})?;
let pointer: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
.try_into()
.map_err(|e| (e, "pointer").into())
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
let length: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
.try_into()
.map_err(|e| (e, "length").into())
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
let memory_view = memory.view();
if length == 0 {
runtime.stack.push(IValue::String("".into()));
return Ok(())
}
if memory_view.len() < pointer + length {
return instr_error!(
instruction.clone(),
InstructionErrorKind::MemoryOutOfBoundsAccess {
index: pointer + length,
length: memory_view.len(),
}
);
}
let data: Vec<u8> = (&memory_view[pointer..pointer + length])
.iter()
.map(Cell::get)
.collect();
log::debug!("byte_array.lift_memory: pushing {:?} on the stack", data);
runtime.stack.push(IValue::ByteArray(data));
Ok(())
}
}
);
executable_instruction!(
byte_array_lower_memory(instruction: Instruction) -> _ {
move |runtime| -> _ {
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
InstructionError::from_error_kind(
instruction.clone(),
InstructionErrorKind::StackIsTooSmall { needed: 2 },
)
})?;
let array_pointer: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
.try_into()
.map_err(|e| (e, "pointer").into())
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
let array: Vec<u8> = to_native(inputs.remove(0), instruction.clone())?;
let length: i32 = array.len().try_into().map_err(|_| {
InstructionError::from_error_kind(
instruction.clone(),
InstructionErrorKind::NegativeValue { subject: "array_length" },
)
})?;
let instance = &mut runtime.wasm_instance;
let memory_index = 0;
let memory_view = instance
.memory(memory_index)
.ok_or_else(|| {
InstructionError::from_error_kind(
instruction.clone(),
InstructionErrorKind::MemoryIsMissing { memory_index },
)
})?
.view();
for (nth, byte) in array.iter().enumerate() {
memory_view[array_pointer as usize + nth].set(*byte);
}
log::debug!("string.lower_memory: pushing {}, {} on the stack", array_pointer, length);
runtime.stack.push(IValue::I32(array_pointer as i32));
runtime.stack.push(IValue::I32(length));
Ok(())
}
}
);
executable_instruction!(
byte_array_size(instruction: Instruction) -> _ {
move |runtime| -> _ {
match runtime.stack.pop1() {
Some(IValue::ByteArray(array)) => {
let length = array.len() as i32;
log::debug!("byte_array.size: pushing {} on the stack", length);
runtime.stack.push(IValue::I32(length));
Ok(())
},
Some(value) => instr_error!(
instruction.clone(),
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: IType::String,
received_value: (&value).clone(),
}
),
None => instr_error!(
instruction.clone(),
InstructionErrorKind::StackIsTooSmall { needed: 1 }
),
}
}
}
);

View File

@ -1,5 +1,6 @@
mod argument_get;
mod arrays;
mod byte_arrays;
mod call_core;
mod dup;
pub(self) mod lilo;
@ -19,6 +20,7 @@ use crate::NEVec;
pub(crate) use argument_get::argument_get;
pub(crate) use arrays::*;
pub(crate) use byte_arrays::*;
pub(crate) use call_core::call_core;
pub(crate) use dup::dup;
pub(crate) use numbers::*;
@ -158,6 +160,15 @@ pub enum Instruction {
/// The `string.lower_memory` instruction.
StringLowerMemory,
/// The `byte_array.size` instruction.
ByteArraySize,
/// The `byte_array.lift_memory` instruction.
ByteArrayLiftMemory,
/// The `byte_array.lower_memory` instruction.
ByteArrayLowerMemory,
/// The `string.size` instruction.
StringSize,
@ -206,12 +217,9 @@ pub enum Instruction {
/// Just a short helper to map the error of a cast from an
/// `IValue` to a native value.
pub(crate) fn to_native<'a, T>(
wit_value: &'a IValue,
instruction: Instruction,
) -> InstructionResult<T>
pub(crate) fn to_native<'a, T>(wit_value: IValue, instruction: Instruction) -> InstructionResult<T>
where
T: NativeType + TryFrom<&'a IValue, Error = WasmValueNativeCastError>,
T: NativeType + TryFrom<IValue, Error = WasmValueNativeCastError>,
{
T::try_from(wit_value).map_err(|error| {
InstructionError::from_error_kind(instruction, InstructionErrorKind::ToNative(error))

View File

@ -32,14 +32,14 @@ where
use crate::interpreter::stack::Stackable;
Box::new({
move |runtime| -> _ {
let inputs = runtime.stack.pop(1).ok_or_else(|| {
let mut inputs = runtime.stack.pop(1).ok_or_else(|| {
InstructionError::from_error_kind(
instruction.clone(),
InstructionErrorKind::StackIsTooSmall { needed: 1 },
)
})?;
let offset: usize = to_native::<i32>(&inputs[0], instruction.clone())?
let offset: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
.try_into()
.map_err(|e| (e, "offset").into())
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;

View File

@ -33,6 +33,7 @@ pub(crate) fn record_lift_memory_impl(
IType::U16 => values.push(IValue::U16(seq_reader.read_u16())),
IType::U32 => values.push(IValue::U32(seq_reader.read_u32())),
IType::U64 => values.push(IValue::U64(seq_reader.read_u64())),
IType::U128 => values.push(IValue::U128(seq_reader.read_u128())),
IType::F32 => values.push(IValue::F32(seq_reader.read_f32())),
IType::F64 => values.push(IValue::F64(seq_reader.read_f64())),
IType::String => values.push(IValue::String(read_string(reader, &seq_reader)?)),

View File

@ -21,6 +21,7 @@ pub(crate) fn record_lower_memory_impl(
IValue::U16(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::U32(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::U64(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::U128(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::I32(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::I64(value) => result.extend_from_slice(&value.to_le_bytes()),
IValue::F32(value) => result.extend_from_slice(&value.to_le_bytes()),

View File

@ -12,7 +12,7 @@ use std::{cell::Cell, convert::TryInto};
executable_instruction!(
string_lift_memory(instruction: Instruction) -> _ {
move |runtime| -> _ {
let inputs = runtime.stack.pop(2).ok_or_else(|| {
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
InstructionError::from_error_kind(
instruction.clone(),
InstructionErrorKind::StackIsTooSmall { needed: 2 },
@ -30,11 +30,11 @@ executable_instruction!(
)
})?;
let pointer: usize = to_native::<i32>(&inputs[0], instruction.clone())?
let pointer: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
.try_into()
.map_err(|e| (e, "pointer").into())
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
let length: usize = to_native::<i32>(&inputs[1], instruction.clone())?
let length: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
.try_into()
.map_err(|e| (e, "length").into())
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
@ -75,18 +75,18 @@ executable_instruction!(
executable_instruction!(
string_lower_memory(instruction: Instruction) -> _ {
move |runtime| -> _ {
let inputs = runtime.stack.pop(2).ok_or_else(|| {
let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
InstructionError::from_error_kind(
instruction.clone(),
InstructionErrorKind::StackIsTooSmall { needed: 2 },
)
})?;
let string_pointer: usize = to_native::<i32>(&inputs[0], instruction.clone())?
let string_pointer: usize = to_native::<i32>(inputs.remove(0), instruction.clone())?
.try_into()
.map_err(|e| (e, "pointer").into())
.map_err(|k| InstructionError::from_error_kind(instruction.clone(), k))?;
let string: String = to_native(&inputs[1], instruction.clone())?;
let string: String = to_native(inputs.remove(0), instruction.clone())?;
let string_bytes = string.as_bytes();
let string_length: i32 = string_bytes.len().try_into().map_err(|_| {
InstructionError::from_error_kind(

View File

@ -239,6 +239,15 @@ where
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::ByteArrayLowerMemory => {
instructions::byte_array_lower_memory(instruction)
}
Instruction::ByteArraySize => instructions::byte_array_size(instruction),
Instruction::ArrayLiftMemory { ref value_type } => {
let value_type = value_type.clone();
instructions::array_lift_memory(instruction, value_type)

View File

@ -215,6 +215,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
Some(IValue::U16(_)) => self.deserialize_u16(visitor),
Some(IValue::U32(_)) => self.deserialize_u32(visitor),
Some(IValue::U64(_)) => self.deserialize_u64(visitor),
Some(IValue::U128(_)) => self.deserialize_u64(visitor),
Some(IValue::F32(_)) => self.deserialize_f32(visitor),
Some(IValue::F64(_)) => self.deserialize_f64(visitor),
Some(IValue::String(_)) => self.deserialize_string(visitor),