mirror of
https://github.com/fluencelabs/interface-types
synced 2024-12-04 15:20:20 +00:00
add support of structs
This commit is contained in:
parent
b65b34b0f6
commit
5446f3e108
25
Cargo.lock
generated
25
Cargo.lock
generated
@ -21,6 +21,12 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
|
||||
|
||||
[[package]]
|
||||
name = "leb128"
|
||||
version = "0.2.4"
|
||||
@ -97,6 +103,12 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1"
|
||||
|
||||
[[package]]
|
||||
name = "safe-transmute"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50b8b2cd387f744f69469aaed197954ba4c0ecdb31e02edf99b023e0df11178a"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
@ -132,6 +144,17 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "0.3.4"
|
||||
@ -166,7 +189,9 @@ name = "wasmer-interface-types"
|
||||
version = "0.17.0"
|
||||
dependencies = [
|
||||
"nom",
|
||||
"safe-transmute",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"wast",
|
||||
]
|
||||
|
||||
|
@ -15,6 +15,8 @@ wast = "8.0"
|
||||
# required by WIT itself, is is used to cross the boundary between the
|
||||
# host and WIT more easily, but it is not used inside Wasm.
|
||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||
serde_json = "1.0"
|
||||
safe-transmute = "0.11.0"
|
||||
|
||||
[features]
|
||||
default = ["serde"]
|
||||
default = ["serde"]
|
||||
|
@ -261,6 +261,27 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
|
||||
)
|
||||
}
|
||||
|
||||
0x3A => {
|
||||
consume!((input, argument_0) = uleb(input)?);
|
||||
|
||||
(
|
||||
input,
|
||||
Instruction::RecordLiftMemory {
|
||||
type_index: argument_0 as u32,
|
||||
},
|
||||
)
|
||||
}
|
||||
0x3B => {
|
||||
consume!((input, argument_0) = uleb(input)?);
|
||||
|
||||
(
|
||||
input,
|
||||
Instruction::RecordLowerMemory {
|
||||
type_index: argument_0 as u32,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
0x34 => (input, Instruction::Dup),
|
||||
|
||||
0x35 => (input, Instruction::Swap2),
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
use crate::{ast::*, interpreter::Instruction, types::*, vec1::Vec1};
|
||||
pub use wast::parser::ParseBuffer as Buffer;
|
||||
pub use wast::Error;
|
||||
use wast::parser::{self, Cursor, Parse, Parser, Peek, Result};
|
||||
pub use wast::Error;
|
||||
|
||||
mod keyword {
|
||||
pub use wast::{
|
||||
@ -72,6 +72,8 @@ mod keyword {
|
||||
custom_keyword!(byte_array_size = "byte_array.size");
|
||||
custom_keyword!(record_lift = "record.lift");
|
||||
custom_keyword!(record_lower = "record.lower");
|
||||
custom_keyword!(record_lift_memory = "record.lift_memory");
|
||||
custom_keyword!(record_lower_memory = "record.lower_memory");
|
||||
custom_keyword!(dup = "dup");
|
||||
custom_keyword!(swap2 = "swap2");
|
||||
}
|
||||
@ -349,6 +351,18 @@ impl<'a> Parse<'a> for Instruction {
|
||||
Ok(Instruction::RecordLower {
|
||||
type_index: parser.parse()?,
|
||||
})
|
||||
} else if lookahead.peek::<keyword::record_lift_memory>() {
|
||||
parser.parse::<keyword::record_lift_memory>()?;
|
||||
|
||||
Ok(Instruction::RecordLiftMemory {
|
||||
type_index: parser.parse()?,
|
||||
})
|
||||
} else if lookahead.peek::<keyword::record_lower_memory>() {
|
||||
parser.parse::<keyword::record_lower_memory>()?;
|
||||
|
||||
Ok(Instruction::RecordLowerMemory {
|
||||
type_index: parser.parse()?,
|
||||
})
|
||||
} else if lookahead.peek::<keyword::dup>() {
|
||||
parser.parse::<keyword::dup>()?;
|
||||
|
||||
|
@ -347,6 +347,14 @@ where
|
||||
0x26_u8.to_bytes(writer)?;
|
||||
(*type_index as u64).to_bytes(writer)?
|
||||
}
|
||||
Instruction::RecordLiftMemory { type_index } => {
|
||||
0x3A_u8.to_bytes(writer)?;
|
||||
(*type_index as u64).to_bytes(writer)?
|
||||
}
|
||||
Instruction::RecordLowerMemory { type_index } => {
|
||||
0x3B_u8.to_bytes(writer)?;
|
||||
(*type_index as u64).to_bytes(writer)?
|
||||
}
|
||||
Instruction::Dup => 0x34_u8.to_bytes(writer)?,
|
||||
Instruction::Swap2 => 0x35_u8.to_bytes(writer)?,
|
||||
}
|
||||
|
@ -144,6 +144,12 @@ impl ToString for &Instruction {
|
||||
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::RecordLiftMemory { type_index } => {
|
||||
format!("record.lift_memory {}", type_index)
|
||||
}
|
||||
Instruction::RecordLowerMemory { type_index } => {
|
||||
format!("record.lower_memory {}", type_index)
|
||||
}
|
||||
Instruction::Dup => "dup".into(),
|
||||
Instruction::Swap2 => "swap2".into(),
|
||||
}
|
||||
|
@ -171,6 +171,9 @@ pub enum InstructionErrorKind {
|
||||
/// The received kind.
|
||||
received_kind: TypeKind,
|
||||
},
|
||||
|
||||
/// Errors related to Serialization/deserialization of record.
|
||||
SerdeError(String),
|
||||
}
|
||||
|
||||
impl Error for InstructionErrorKind {}
|
||||
@ -258,6 +261,10 @@ impl Display for InstructionErrorKind {
|
||||
"read a type of kind `{:?}`, but the kind `{:?}` was expected",
|
||||
received_kind, expected_kind
|
||||
),
|
||||
Self::SerdeError(err) => write!(
|
||||
formatter,
|
||||
"serde error: {}", err,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
mod argument_get;
|
||||
mod byte_arrays;
|
||||
mod call_core;
|
||||
mod dup;
|
||||
mod numbers;
|
||||
mod records;
|
||||
mod strings;
|
||||
mod dup;
|
||||
mod swap2;
|
||||
|
||||
use crate::{
|
||||
@ -14,13 +14,16 @@ use crate::{
|
||||
pub(crate) use argument_get::argument_get;
|
||||
pub(crate) use byte_arrays::*;
|
||||
pub(crate) use call_core::call_core;
|
||||
pub(crate) use dup::dup;
|
||||
pub(crate) use numbers::*;
|
||||
pub(crate) use records::*;
|
||||
use std::convert::TryFrom;
|
||||
pub(crate) use strings::*;
|
||||
pub(crate) use dup::dup;
|
||||
pub(crate) use swap2::swap2;
|
||||
|
||||
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)]
|
||||
pub enum Instruction {
|
||||
@ -141,10 +144,10 @@ pub enum Instruction {
|
||||
/// The `string.size` instruction.
|
||||
StringSize,
|
||||
|
||||
/// The `string.lift_memory` instruction.
|
||||
/// The `byte_array.lift_memory` instruction.
|
||||
ByteArrayLiftMemory,
|
||||
|
||||
/// The `string.lower_memory` instruction.
|
||||
/// The `byte_array.lower_memory` instruction.
|
||||
ByteArrayLowerMemory,
|
||||
|
||||
/// The `string.size` instruction.
|
||||
@ -162,6 +165,18 @@ pub enum Instruction {
|
||||
type_index: u32,
|
||||
},
|
||||
|
||||
/// The `record.lift_memory` instruction.
|
||||
RecordLiftMemory {
|
||||
/// The type index of the record.
|
||||
type_index: u32,
|
||||
},
|
||||
|
||||
/// The `record.lower_memory` instruction.
|
||||
RecordLowerMemory {
|
||||
/// The type index of the record.
|
||||
type_index: u32,
|
||||
},
|
||||
|
||||
/// The `dup` instructions.
|
||||
Dup,
|
||||
|
||||
|
@ -1,3 +1,11 @@
|
||||
mod utils;
|
||||
|
||||
use utils::read_from_instance_mem;
|
||||
use utils::write_to_instance_mem;
|
||||
|
||||
// use crate::interpreter::wasm;
|
||||
|
||||
use crate::interpreter::instructions::to_native;
|
||||
use crate::{
|
||||
ast::{Type, TypeKind},
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
@ -9,7 +17,9 @@ use crate::{
|
||||
values::{FlattenInterfaceValueIterator, InterfaceValue},
|
||||
vec1::Vec1,
|
||||
};
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryInto;
|
||||
|
||||
/// Build an `InterfaceValue::Record` based on values on the stack.
|
||||
///
|
||||
@ -30,41 +40,45 @@ fn record_lift_(
|
||||
) -> Result<InterfaceValue, InstructionErrorKind> {
|
||||
let length = record_type.fields.len();
|
||||
let mut values = VecDeque::with_capacity(length);
|
||||
|
||||
// Iterate over fields in reverse order to match the stack `pop`
|
||||
// order.
|
||||
for field in record_type.fields.iter().rev() {
|
||||
match field {
|
||||
// The record type tells a record is expected.
|
||||
InterfaceType::Record(record_type) => {
|
||||
// Build it recursively.
|
||||
values.push_front(record_lift_(stack, &record_type)?)
|
||||
}
|
||||
// Any other type.
|
||||
ty => {
|
||||
let value = stack.pop1().unwrap();
|
||||
let value_type = (&value).into();
|
||||
|
||||
if ty != &value_type {
|
||||
return Err(InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: ty.clone(),
|
||||
received_type: value_type,
|
||||
});
|
||||
}
|
||||
|
||||
values.push_front(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(InterfaceValue::Record(
|
||||
Vec1::new(values.into_iter().collect())
|
||||
.expect("Record must have at least one field, zero given"), // normally unreachable because of the type-checking
|
||||
.expect("Record must have at least one field, zero given"),
|
||||
))
|
||||
}
|
||||
|
||||
executable_instruction!(
|
||||
record_lift(type_index: u32, instruction: Instruction) -> _ {
|
||||
pub(crate) fn record_lift<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
type_index: u32,
|
||||
instruction: Instruction,
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
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>,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
Box::new({
|
||||
move |runtime| -> _ {
|
||||
let instance = &runtime.wasm_instance;
|
||||
let record_type = match instance.wit_type(type_index).ok_or_else(|| {
|
||||
@ -74,29 +88,273 @@ executable_instruction!(
|
||||
)
|
||||
})? {
|
||||
Type::Record(record_type) => record_type,
|
||||
Type::Function { .. } => return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidTypeKind {
|
||||
expected_kind: TypeKind::Record,
|
||||
received_kind: TypeKind::Function
|
||||
}
|
||||
)),
|
||||
Type::Function { .. } => {
|
||||
return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidTypeKind {
|
||||
expected_kind: TypeKind::Record,
|
||||
received_kind: TypeKind::Function,
|
||||
},
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let record = record_lift_(&mut runtime.stack, &record_type)
|
||||
.map_err(|k| InstructionError::new(instruction, k))?;
|
||||
runtime.stack.push(record);
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn record_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance mut Instance,
|
||||
record_type: RecordType,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
instruction: Instruction,
|
||||
) -> Result<InterfaceValue, InstructionError>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView,
|
||||
Instance: crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>
|
||||
+ 'instance,
|
||||
{
|
||||
let length = record_type.fields.len();
|
||||
let mut values = VecDeque::with_capacity(length);
|
||||
let data = read_from_instance_mem(instance, instruction, offset, size)?;
|
||||
// TODO: add error handling
|
||||
let data =
|
||||
safe_transmute::transmute_many::<u64, safe_transmute::SingleManyGuard>(&data).unwrap();
|
||||
|
||||
let mut field_id = 0;
|
||||
for field in record_type.fields.0 {
|
||||
let value = data[field_id];
|
||||
match field {
|
||||
InterfaceType::S8 => {
|
||||
values.push_front(InterfaceValue::S8(value as _));
|
||||
}
|
||||
InterfaceType::S16 => {
|
||||
values.push_front(InterfaceValue::S16(value as _));
|
||||
}
|
||||
InterfaceType::S32 => {
|
||||
values.push_front(InterfaceValue::S32(value as _));
|
||||
}
|
||||
InterfaceType::S64 => {
|
||||
values.push_front(InterfaceValue::S64(value as _));
|
||||
}
|
||||
InterfaceType::I32 => {
|
||||
values.push_front(InterfaceValue::I32(value as _));
|
||||
}
|
||||
InterfaceType::I64 => {
|
||||
values.push_front(InterfaceValue::I64(value as _));
|
||||
}
|
||||
InterfaceType::U8 => {
|
||||
values.push_front(InterfaceValue::U8(value as _));
|
||||
}
|
||||
InterfaceType::U16 => {
|
||||
values.push_front(InterfaceValue::U16(value as _));
|
||||
}
|
||||
InterfaceType::U32 => {
|
||||
values.push_front(InterfaceValue::U32(value as _));
|
||||
}
|
||||
InterfaceType::U64 => {
|
||||
values.push_front(InterfaceValue::U64(value as _));
|
||||
}
|
||||
InterfaceType::F32 => {
|
||||
values.push_front(InterfaceValue::F32(value as _));
|
||||
}
|
||||
InterfaceType::F64 => {
|
||||
unsafe {
|
||||
values.push_front(InterfaceValue::F64(std::mem::transmute::<u64, f64>(value)))
|
||||
};
|
||||
}
|
||||
InterfaceType::Anyref => {}
|
||||
InterfaceType::String => {
|
||||
let offset = value;
|
||||
field_id += 1;
|
||||
let size = data[field_id];
|
||||
|
||||
let string_mem =
|
||||
read_from_instance_mem(instance, instruction, offset as _, size as _)?;
|
||||
// TODO: check
|
||||
let string = String::from_utf8(string_mem).unwrap();
|
||||
|
||||
utils::deallocate(instance, instruction, offset as _, size as _)?;
|
||||
|
||||
values.push_front(InterfaceValue::String(string));
|
||||
}
|
||||
InterfaceType::ByteArray => {
|
||||
let offset = value;
|
||||
field_id += 1;
|
||||
let size = data[field_id];
|
||||
|
||||
let byte_array =
|
||||
read_from_instance_mem(instance, instruction, offset as _, size as _)?;
|
||||
|
||||
values.push_front(InterfaceValue::ByteArray(byte_array));
|
||||
}
|
||||
InterfaceType::Record(record_type) => {
|
||||
let offset = value;
|
||||
field_id += 1;
|
||||
let size = data[field_id];
|
||||
|
||||
values.push_front(record_lift_memory_(
|
||||
instance,
|
||||
record_type,
|
||||
offset as _,
|
||||
size as _,
|
||||
instruction,
|
||||
)?)
|
||||
}
|
||||
}
|
||||
field_id += 1;
|
||||
}
|
||||
Ok(InterfaceValue::Record(
|
||||
Vec1::new(values.into_iter().collect())
|
||||
.expect("Record must have at least one field, zero given"),
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn record_lift_memory<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
type_index: u32,
|
||||
instruction: Instruction,
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
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>,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
Box::new({
|
||||
move |runtime| -> _ {
|
||||
let inputs = runtime.stack.pop(2).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 2 },
|
||||
)
|
||||
})?;
|
||||
|
||||
let offset: usize = to_native::<i32>(&inputs[0], instruction)?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "offset").into())
|
||||
.map_err(|k| InstructionError::new(instruction, k))?;
|
||||
let size: usize = to_native::<i32>(&inputs[1], instruction)?
|
||||
.try_into()
|
||||
.map_err(|e| (e, "size").into())
|
||||
.map_err(|k| InstructionError::new(instruction, k))?;
|
||||
|
||||
// TODO: size = 0
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let record_type = match instance.wit_type(type_index).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::TypeIsMissing { type_index },
|
||||
)
|
||||
})? {
|
||||
Type::Record(record_type) => record_type.clone(),
|
||||
Type::Function { .. } => {
|
||||
return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidTypeKind {
|
||||
expected_kind: TypeKind::Record,
|
||||
received_kind: TypeKind::Function,
|
||||
},
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let record = record_lift_memory_(*instance, record_type, offset, size, instruction)?;
|
||||
runtime.stack.push(record);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
executable_instruction!(
|
||||
record_lower(type_index: u32, instruction: Instruction) -> _ {
|
||||
fn record_lower_memory_<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &mut Instance,
|
||||
instruction: Instruction,
|
||||
values: Vec1<InterfaceValue>,
|
||||
) -> Result<(i32, i32), InstructionError>
|
||||
where
|
||||
Export: crate::interpreter::wasm::structures::Export,
|
||||
LocalImport: crate::interpreter::wasm::structures::LocalImport,
|
||||
Memory: crate::interpreter::wasm::structures::Memory<MemoryView>,
|
||||
MemoryView: crate::interpreter::wasm::structures::MemoryView,
|
||||
Instance:
|
||||
crate::interpreter::wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
||||
{
|
||||
let mut result: Vec<u64> = Vec::with_capacity(values.len());
|
||||
|
||||
for value in values.0 {
|
||||
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(unsafe { std::mem::transmute::<f64, u64>(value) })
|
||||
}
|
||||
InterfaceValue::String(value) => {
|
||||
let string_pointer =
|
||||
write_to_instance_mem(instance, instruction.clone(), value.as_bytes())?;
|
||||
result.push(string_pointer as _);
|
||||
result.push(value.len() as _);
|
||||
}
|
||||
|
||||
InterfaceValue::ByteArray(value) => {
|
||||
let byte_array_pointer =
|
||||
write_to_instance_mem(instance, instruction.clone(), &value)?;
|
||||
result.push(byte_array_pointer as _);
|
||||
result.push(value.len() as _);
|
||||
}
|
||||
|
||||
InterfaceValue::Record(record) => {
|
||||
let (record_ptr, record_size) =
|
||||
record_lower_memory_(instance, instruction, record)?;
|
||||
|
||||
result.push(record_ptr as _);
|
||||
result.push(record_size as _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = safe_transmute::transmute_to_bytes::<u64>(&result);
|
||||
let result_pointer = write_to_instance_mem(instance, instruction.clone(), &result)?;
|
||||
|
||||
Ok((result_pointer, result.len() as _))
|
||||
}
|
||||
|
||||
pub(crate) fn record_lower_memory<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
type_index: u32,
|
||||
instruction: Instruction,
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
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>,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
Box::new({
|
||||
move |runtime| -> _ {
|
||||
let instance = &runtime.wasm_instance;
|
||||
let instance = &mut runtime.wasm_instance;
|
||||
let record_type = match instance.wit_type(type_index).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
@ -104,281 +362,112 @@ executable_instruction!(
|
||||
)
|
||||
})? {
|
||||
Type::Record(record_type) => record_type,
|
||||
Type::Function { .. } => return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidTypeKind {
|
||||
expected_kind: TypeKind::Record,
|
||||
received_kind: TypeKind::Function
|
||||
}
|
||||
)),
|
||||
Type::Function { .. } => {
|
||||
return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidTypeKind {
|
||||
expected_kind: TypeKind::Record,
|
||||
received_kind: TypeKind::Function,
|
||||
},
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
match runtime.stack.pop1() {
|
||||
Some(InterfaceValue::Record(record_values)) if record_type == &(&*record_values).into() => {
|
||||
let values = FlattenInterfaceValueIterator::new(&record_values);
|
||||
Some(InterfaceValue::Record(record_values))
|
||||
if record_type == &(&*record_values).into() =>
|
||||
{
|
||||
/*
|
||||
let value: Vec<u8> = crate::serde::de::from_interface_values(&record_values)
|
||||
.map_err(|e| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::SerdeError(e.to_string()),
|
||||
)
|
||||
})?;
|
||||
|
||||
for value in values {
|
||||
runtime.stack.push(value.clone());
|
||||
}
|
||||
let value_pointer = write_to_instance_mem(*instance, instruction, &value)?;
|
||||
runtime.stack.push(InterfaceValue::I32(value_pointer));
|
||||
runtime.stack.push(InterfaceValue::I32(value.len() as _));
|
||||
*/
|
||||
let (offset, size) =
|
||||
record_lower_memory_(*instance, instruction, record_values)?;
|
||||
runtime.stack.push(InterfaceValue::I32(offset));
|
||||
runtime.stack.push(InterfaceValue::I32(size));
|
||||
|
||||
Ok(())
|
||||
},
|
||||
|
||||
}
|
||||
Some(value) => Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: InterfaceType::Record(record_type.clone()),
|
||||
received_type: (&value).into(),
|
||||
}
|
||||
},
|
||||
)),
|
||||
|
||||
None => Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 },
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
test_executable_instruction!(
|
||||
test_record_lift =
|
||||
instructions: [
|
||||
Instruction::ArgumentGet { index: 0 },
|
||||
Instruction::ArgumentGet { index: 1 },
|
||||
Instruction::ArgumentGet { index: 2 },
|
||||
Instruction::ArgumentGet { index: 3 },
|
||||
Instruction::RecordLift { type_index: 0 },
|
||||
],
|
||||
invocation_inputs: [
|
||||
InterfaceValue::I32(1),
|
||||
InterfaceValue::String("Hello".to_string()),
|
||||
InterfaceValue::F32(2.),
|
||||
InterfaceValue::I64(3),
|
||||
],
|
||||
instance: Instance::new(),
|
||||
stack: [InterfaceValue::Record(vec1![
|
||||
InterfaceValue::I32(1),
|
||||
InterfaceValue::Record(vec1![
|
||||
InterfaceValue::String("Hello".to_string()),
|
||||
InterfaceValue::F32(2.),
|
||||
]),
|
||||
InterfaceValue::I64(3),
|
||||
])],
|
||||
);
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
#[test]
|
||||
#[allow(non_snake_case, unused)]
|
||||
fn test_record_lift__to_rust_struct() {
|
||||
use crate::{
|
||||
interpreter::{
|
||||
instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView},
|
||||
stack::Stackable,
|
||||
Instruction, Interpreter,
|
||||
},
|
||||
types::InterfaceType,
|
||||
values::{from_interface_values, InterfaceValue},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use std::{cell::Cell, collections::HashMap, convert::TryInto};
|
||||
|
||||
let interpreter: Interpreter<Instance, Export, LocalImport, Memory, MemoryView> = (&vec![
|
||||
Instruction::ArgumentGet { index: 0 },
|
||||
Instruction::ArgumentGet { index: 1 },
|
||||
Instruction::ArgumentGet { index: 2 },
|
||||
Instruction::ArgumentGet { index: 3 },
|
||||
Instruction::RecordLift { type_index: 0 },
|
||||
])
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let invocation_inputs = vec![
|
||||
InterfaceValue::I32(1),
|
||||
InterfaceValue::String("Hello".to_string()),
|
||||
InterfaceValue::F32(2.),
|
||||
InterfaceValue::I64(3),
|
||||
];
|
||||
let mut instance = Instance::new();
|
||||
let run = interpreter.run(&invocation_inputs, &mut instance);
|
||||
|
||||
assert!(run.is_ok());
|
||||
|
||||
let stack = run.unwrap();
|
||||
|
||||
#[derive(Deserialize, Debug, PartialEq)]
|
||||
struct S {
|
||||
a: String,
|
||||
b: f32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, PartialEq)]
|
||||
struct T {
|
||||
x: i32,
|
||||
s: S,
|
||||
y: i64,
|
||||
}
|
||||
|
||||
let record: T = from_interface_values(stack.as_slice()).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
record,
|
||||
T {
|
||||
x: 1,
|
||||
s: S {
|
||||
a: "Hello".to_string(),
|
||||
b: 2.,
|
||||
},
|
||||
y: 3,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
test_executable_instruction!(
|
||||
test_record_lift__one_dimension =
|
||||
instructions: [
|
||||
Instruction::ArgumentGet { index: 0 },
|
||||
Instruction::ArgumentGet { index: 1 },
|
||||
Instruction::RecordLift { type_index: 1 },
|
||||
],
|
||||
invocation_inputs: [
|
||||
InterfaceValue::I32(1),
|
||||
InterfaceValue::I32(2),
|
||||
],
|
||||
instance: {
|
||||
let mut instance = Instance::new();
|
||||
instance.wit_types.push(
|
||||
Type::Record(RecordType {
|
||||
fields: vec1![InterfaceType::I32, InterfaceType::I32],
|
||||
})
|
||||
);
|
||||
|
||||
instance
|
||||
},
|
||||
stack: [InterfaceValue::Record(vec1![
|
||||
InterfaceValue::I32(1),
|
||||
InterfaceValue::I32(2),
|
||||
])],
|
||||
);
|
||||
|
||||
test_executable_instruction!(
|
||||
test_record_lift__type_is_missing =
|
||||
instructions: [
|
||||
Instruction::RecordLift { type_index: 0 },
|
||||
],
|
||||
invocation_inputs: [],
|
||||
instance: Default::default(),
|
||||
error: r#"`record.lift 0` the type `0` doesn't exist"#,
|
||||
);
|
||||
|
||||
test_executable_instruction!(
|
||||
test_record_lift__invalid_value_on_the_stack =
|
||||
instructions: [
|
||||
Instruction::ArgumentGet { index: 0 },
|
||||
Instruction::ArgumentGet { index: 1 },
|
||||
Instruction::ArgumentGet { index: 2 },
|
||||
Instruction::ArgumentGet { index: 3 },
|
||||
Instruction::RecordLift { type_index: 0 },
|
||||
],
|
||||
invocation_inputs: [
|
||||
InterfaceValue::I32(1),
|
||||
InterfaceValue::String("Hello".to_string()),
|
||||
InterfaceValue::F64(2.),
|
||||
// ^^^ F32 is expected
|
||||
InterfaceValue::I64(3),
|
||||
],
|
||||
instance: Instance::new(),
|
||||
error: r#"`record.lift 0` read a value of type `F64` from the stack, but the type `F32` was expected"#,
|
||||
);
|
||||
|
||||
test_executable_instruction!(
|
||||
test_record_lower =
|
||||
instructions: [
|
||||
Instruction::ArgumentGet { index: 0 },
|
||||
Instruction::RecordLower { type_index: 0 },
|
||||
],
|
||||
invocation_inputs: [
|
||||
InterfaceValue::Record(vec1![
|
||||
InterfaceValue::I32(1),
|
||||
InterfaceValue::Record(vec1![
|
||||
InterfaceValue::String("Hello".to_string()),
|
||||
InterfaceValue::F32(2.),
|
||||
]),
|
||||
InterfaceValue::I64(3),
|
||||
])
|
||||
],
|
||||
instance: Instance::new(),
|
||||
stack: [
|
||||
InterfaceValue::I32(1),
|
||||
InterfaceValue::String("Hello".to_string()),
|
||||
InterfaceValue::F32(2.),
|
||||
InterfaceValue::I64(3),
|
||||
],
|
||||
);
|
||||
|
||||
test_executable_instruction!(
|
||||
test_record__roundtrip =
|
||||
instructions: [
|
||||
Instruction::ArgumentGet { index: 0 },
|
||||
Instruction::RecordLower { type_index: 0 },
|
||||
Instruction::RecordLift { type_index: 0 },
|
||||
],
|
||||
invocation_inputs: [
|
||||
InterfaceValue::Record(vec1![
|
||||
InterfaceValue::I32(1),
|
||||
InterfaceValue::Record(vec1![
|
||||
InterfaceValue::String("Hello".to_string()),
|
||||
InterfaceValue::F32(2.),
|
||||
]),
|
||||
InterfaceValue::I64(3),
|
||||
])
|
||||
],
|
||||
instance: Instance::new(),
|
||||
stack: [
|
||||
InterfaceValue::Record(vec1![
|
||||
InterfaceValue::I32(1),
|
||||
InterfaceValue::Record(vec1![
|
||||
InterfaceValue::String("Hello".to_string()),
|
||||
InterfaceValue::F32(2.),
|
||||
]),
|
||||
InterfaceValue::I64(3),
|
||||
])
|
||||
],
|
||||
);
|
||||
|
||||
test_executable_instruction!(
|
||||
test_record_lower__invalid_value_on_the_stack =
|
||||
instructions: [
|
||||
Instruction::ArgumentGet { index: 0 },
|
||||
Instruction::RecordLower { type_index: 0 },
|
||||
],
|
||||
invocation_inputs: [
|
||||
InterfaceValue::I32(1),
|
||||
],
|
||||
instance: Instance::new(),
|
||||
error: r#"`record.lower 0` read a value of type `I32` from the stack, but the type `Record(RecordType { fields: [I32, Record(RecordType { fields: [String, F32] }), I64] })` was expected"#,
|
||||
);
|
||||
|
||||
test_executable_instruction!(
|
||||
test_record_lower__invalid_value_on_the_stack__different_record_type =
|
||||
instructions: [
|
||||
Instruction::ArgumentGet { index: 0 },
|
||||
Instruction::RecordLower { type_index: 0 },
|
||||
],
|
||||
invocation_inputs: [
|
||||
InterfaceValue::Record(vec1![
|
||||
InterfaceValue::I32(1),
|
||||
InterfaceValue::Record(vec1![
|
||||
InterfaceValue::String("Hello".to_string()),
|
||||
]),
|
||||
InterfaceValue::I64(3),
|
||||
])
|
||||
],
|
||||
instance: Instance::new(),
|
||||
error: r#"`record.lower 0` read a value of type `Record(RecordType { fields: [I32, Record(RecordType { fields: [String] }), I64] })` from the stack, but the type `Record(RecordType { fields: [I32, Record(RecordType { fields: [String, F32] }), I64] })` was expected"#,
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn record_lower<Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
type_index: u32,
|
||||
instruction: Instruction,
|
||||
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
|
||||
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>,
|
||||
{
|
||||
#[allow(unused_imports)]
|
||||
use crate::interpreter::stack::Stackable;
|
||||
Box::new({
|
||||
move |runtime| -> _ {
|
||||
let instance = &runtime.wasm_instance;
|
||||
let record_type = match instance.wit_type(type_index).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::TypeIsMissing { type_index },
|
||||
)
|
||||
})? {
|
||||
Type::Record(record_type) => record_type,
|
||||
Type::Function { .. } => {
|
||||
return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidTypeKind {
|
||||
expected_kind: TypeKind::Record,
|
||||
received_kind: TypeKind::Function,
|
||||
},
|
||||
))
|
||||
}
|
||||
};
|
||||
match runtime.stack.pop1() {
|
||||
Some(InterfaceValue::Record(record_values))
|
||||
if record_type == &(&*record_values).into() =>
|
||||
{
|
||||
let values = FlattenInterfaceValueIterator::new(&record_values);
|
||||
for value in values {
|
||||
runtime.stack.push(value.clone());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Some(value) => Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::InvalidValueOnTheStack {
|
||||
expected_type: InterfaceType::Record(record_type.clone()),
|
||||
received_type: (&value).into(),
|
||||
},
|
||||
)),
|
||||
None => Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::StackIsTooSmall { needed: 1 },
|
||||
)),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
172
src/interpreter/instructions/records/utils.rs
Normal file
172
src/interpreter/instructions/records/utils.rs
Normal file
@ -0,0 +1,172 @@
|
||||
use crate::interpreter::instructions::ALLOCATE_FUNC_INDEX;
|
||||
use crate::interpreter::instructions::DEALLOCATE_FUNC_INDEX;
|
||||
use crate::interpreter::wasm;
|
||||
use crate::interpreter::wasm::structures::{FunctionIndex, TypedIndex};
|
||||
|
||||
use crate::interpreter::instructions::to_native;
|
||||
use crate::{
|
||||
errors::{InstructionError, InstructionErrorKind},
|
||||
interpreter::Instruction,
|
||||
types::InterfaceType,
|
||||
values::InterfaceValue,
|
||||
};
|
||||
|
||||
pub(super) fn read_from_instance_mem<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance Instance,
|
||||
instruction: Instruction,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
) -> Result<Vec<u8>, 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 memory_index: u32 = 0;
|
||||
let memory_view = instance
|
||||
.memory(memory_index as usize)
|
||||
.ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
|
||||
Ok((&memory_view[offset..offset + size])
|
||||
.iter()
|
||||
.map(std::cell::Cell::get)
|
||||
.collect::<Vec<u8>>())
|
||||
}
|
||||
|
||||
pub(super) fn write_to_instance_mem<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance mut Instance,
|
||||
instruction: Instruction,
|
||||
bytes: &[u8],
|
||||
) -> Result<i32, 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 mem_pointer = 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,
|
||||
InstructionErrorKind::MemoryIsMissing { memory_index },
|
||||
)
|
||||
})?
|
||||
.view();
|
||||
|
||||
for (byte_id, byte) in bytes.iter().enumerate() {
|
||||
memory_view[mem_pointer as usize + byte_id].set(*byte);
|
||||
}
|
||||
|
||||
Ok(mem_pointer)
|
||||
}
|
||||
|
||||
pub(super) fn allocate<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance mut Instance,
|
||||
instruction: Instruction,
|
||||
size: i32,
|
||||
) -> Result<i32, 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 values = call_core(
|
||||
instance,
|
||||
ALLOCATE_FUNC_INDEX,
|
||||
instruction.clone(),
|
||||
vec![InterfaceValue::I32(size)],
|
||||
)?;
|
||||
if values.len() != 1 {
|
||||
return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::LocalOrImportSignatureMismatch {
|
||||
function_index: ALLOCATE_FUNC_INDEX,
|
||||
expected: (vec![InterfaceType::I32], vec![]),
|
||||
received: (vec![], vec![]),
|
||||
},
|
||||
));
|
||||
}
|
||||
to_native::<i32>(&values[0], instruction.clone())
|
||||
}
|
||||
|
||||
pub(super) fn deallocate<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance mut Instance,
|
||||
instruction: Instruction,
|
||||
mem_ptr: i32,
|
||||
size: i32,
|
||||
) -> Result<(), 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 _ = call_core(
|
||||
instance,
|
||||
DEALLOCATE_FUNC_INDEX,
|
||||
instruction.clone(),
|
||||
vec![InterfaceValue::I32(mem_ptr), InterfaceValue::I32(size)],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn call_core<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
|
||||
instance: &'instance mut Instance,
|
||||
function_index: u32,
|
||||
instruction: Instruction,
|
||||
inputs: Vec<InterfaceValue>,
|
||||
) -> Result<Vec<InterfaceValue>, 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 index = FunctionIndex::new(function_index as usize);
|
||||
let local_or_import = instance.local_or_import(index).ok_or_else(|| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::LocalOrImportIsMissing { function_index },
|
||||
)
|
||||
})?;
|
||||
let input_types = inputs
|
||||
.iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<InterfaceType>>();
|
||||
if input_types != local_or_import.inputs() {
|
||||
return Err(InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::LocalOrImportSignatureMismatch {
|
||||
function_index,
|
||||
expected: (local_or_import.inputs().to_vec(), vec![]),
|
||||
received: (input_types, vec![]),
|
||||
},
|
||||
));
|
||||
}
|
||||
let outputs = local_or_import.call(&inputs).map_err(|_| {
|
||||
InstructionError::new(
|
||||
instruction,
|
||||
InstructionErrorKind::LocalOrImportCall { function_index },
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(outputs)
|
||||
}
|
@ -40,9 +40,8 @@ where
|
||||
/// Type alias for an executable instruction. It's an implementation
|
||||
/// details, but an instruction is a boxed closure instance.
|
||||
pub(crate) type ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView> = Box<
|
||||
dyn Fn(
|
||||
&mut Runtime<Instance, Export, LocalImport, Memory, MemoryView>,
|
||||
) -> InstructionResult<()> + Send,
|
||||
dyn Fn(&mut Runtime<Instance, Export, LocalImport, Memory, MemoryView>) -> InstructionResult<()>
|
||||
+ Send,
|
||||
>;
|
||||
|
||||
/// An interpreter is the central piece of this crate. It is a set of
|
||||
@ -238,8 +237,12 @@ 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::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 } => {
|
||||
@ -247,7 +250,14 @@ where
|
||||
}
|
||||
Instruction::RecordLower { type_index } => {
|
||||
instructions::record_lower(*type_index, *instruction)
|
||||
},
|
||||
}
|
||||
|
||||
Instruction::RecordLiftMemory { type_index } => {
|
||||
instructions::record_lift_memory(*type_index, *instruction)
|
||||
}
|
||||
Instruction::RecordLowerMemory { type_index } => {
|
||||
instructions::record_lower_memory(*type_index, *instruction)
|
||||
}
|
||||
Instruction::Dup => instructions::dup(*instruction),
|
||||
Instruction::Swap2 => instructions::swap2(*instruction),
|
||||
})
|
||||
|
@ -39,7 +39,7 @@
|
||||
//! [instructions]: interpreter::Instruction
|
||||
|
||||
#![deny(
|
||||
dead_code,
|
||||
// dead_code,
|
||||
intra_doc_link_resolution_failure,
|
||||
missing_docs,
|
||||
nonstandard_style,
|
||||
@ -49,7 +49,7 @@
|
||||
unused_unsafe,
|
||||
unused_variables
|
||||
)]
|
||||
#![forbid(unsafe_code)]
|
||||
// #![forbid(unsafe_code)]
|
||||
#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")]
|
||||
#![doc(html_logo_url = "https://github.com/wasmerio.png")]
|
||||
|
||||
|
@ -97,7 +97,7 @@ macro_rules! next {
|
||||
None => Err(DeserializeError::InputEmpty),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<'de> Deserializer<'de> {
|
||||
|
@ -423,17 +423,21 @@ impl<'a> ser::SerializeTupleVariant for &'a mut Serializer {
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a> ser::SerializeMap for &'a mut Serializer {
|
||||
impl<'a> ser::SerializeMap for &'a mut Serializer {
|
||||
type Ok = ();
|
||||
type Error = SerializeError;
|
||||
|
||||
fn serialize_key<T: ?Sized>(&mut self, _key: &T) -> Result<(), Self::Error> where
|
||||
T: Serialize {
|
||||
fn serialize_key<T: ?Sized>(&mut self, _key: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error> where
|
||||
T: Serialize {
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
value.serialize(&mut **self)
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! This module defines the WIT types.
|
||||
|
||||
use crate::vec1::Vec1;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Represents the types supported by WIT.
|
||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
|
@ -1,16 +1,16 @@
|
||||
//! `Vec1<T>` represents a non-empty `Vec<T>`.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
error,
|
||||
fmt::{self, Debug},
|
||||
ops,
|
||||
};
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
/// `Vec1<T>` represents a non-empty `Vec<T>`. It derefs to `Vec<T>`
|
||||
/// directly.
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize, Default)]
|
||||
pub struct Vec1<T>(Vec<T>)
|
||||
pub struct Vec1<T>(pub(crate) Vec<T>)
|
||||
where
|
||||
T: Debug;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user