run 'cargo fmt' again
This commit is contained in:
parent
d5b99afe0b
commit
2824b84381
|
@ -22,9 +22,7 @@ fn main() {
|
|||
// Export section has an entry with a func_name with an index inside a module
|
||||
let export_section = module.export_section().expect("No export section found");
|
||||
// It's a section with function declarations (which are references to the type section entries)
|
||||
let function_section = module
|
||||
.function_section()
|
||||
.expect("No function section found");
|
||||
let function_section = module.function_section().expect("No function section found");
|
||||
// Type section stores function types which are referenced by function_section entries
|
||||
let type_section = module.type_section().expect("No type section found");
|
||||
|
||||
|
@ -59,8 +57,7 @@ fn main() {
|
|||
let function_index_in_section = function_index - import_section_len;
|
||||
|
||||
// Getting a type reference from a function section entry
|
||||
let func_type_ref: usize =
|
||||
function_section.entries()[function_index_in_section].type_ref() as usize;
|
||||
let func_type_ref: usize = function_section.entries()[function_index_in_section].type_ref() as usize;
|
||||
|
||||
// Use the reference to get an actual function type
|
||||
let function_type: &FunctionType = match &type_section.types()[func_type_ref] {
|
||||
|
@ -112,7 +109,6 @@ fn main() {
|
|||
|
||||
println!(
|
||||
"Result: {:?}",
|
||||
main.invoke_export(func_name, &args, &mut NopExternals)
|
||||
.expect("")
|
||||
main.invoke_export(func_name, &args, &mut NopExternals).expect("")
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,9 +5,8 @@ use std::env;
|
|||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use wasmi::{
|
||||
Error as InterpreterError, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder,
|
||||
ModuleImportResolver, ModuleInstance, ModuleRef, RuntimeArgs, RuntimeValue, Signature, Trap,
|
||||
ValueType,
|
||||
Error as InterpreterError, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, ModuleImportResolver,
|
||||
ModuleInstance, ModuleRef, RuntimeArgs, RuntimeValue, Signature, Trap, ValueType,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -140,11 +139,7 @@ const SET_FUNC_INDEX: usize = 0;
|
|||
const GET_FUNC_INDEX: usize = 1;
|
||||
|
||||
impl<'a> Externals for Runtime<'a> {
|
||||
fn invoke_index(
|
||||
&mut self,
|
||||
index: usize,
|
||||
args: RuntimeArgs,
|
||||
) -> Result<Option<RuntimeValue>, Trap> {
|
||||
fn invoke_index(&mut self, index: usize, args: RuntimeArgs) -> Result<Option<RuntimeValue>, Trap> {
|
||||
match index {
|
||||
SET_FUNC_INDEX => {
|
||||
let idx: i32 = args.nth(0);
|
||||
|
@ -164,16 +159,9 @@ impl<'a> Externals for Runtime<'a> {
|
|||
struct RuntimeModuleImportResolver;
|
||||
|
||||
impl<'a> ModuleImportResolver for RuntimeModuleImportResolver {
|
||||
fn resolve_func(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_signature: &Signature,
|
||||
) -> Result<FuncRef, InterpreterError> {
|
||||
fn resolve_func(&self, field_name: &str, _signature: &Signature) -> Result<FuncRef, InterpreterError> {
|
||||
let func_ref = match field_name {
|
||||
"set" => FuncInstance::alloc_host(
|
||||
Signature::new(&[ValueType::I32][..], None),
|
||||
SET_FUNC_INDEX,
|
||||
),
|
||||
"set" => FuncInstance::alloc_host(Signature::new(&[ValueType::I32][..], None), SET_FUNC_INDEX),
|
||||
"get" => FuncInstance::alloc_host(
|
||||
Signature::new(&[ValueType::I32][..], Some(ValueType::I32)),
|
||||
GET_FUNC_INDEX,
|
||||
|
|
|
@ -7,9 +7,9 @@ use std::env::args;
|
|||
use std::fs::File;
|
||||
use wasmi::memory_units::*;
|
||||
use wasmi::{
|
||||
Error, FuncInstance, FuncRef, GlobalDescriptor, GlobalInstance, GlobalRef, ImportsBuilder,
|
||||
MemoryDescriptor, MemoryInstance, MemoryRef, Module, ModuleImportResolver, ModuleInstance,
|
||||
NopExternals, RuntimeValue, Signature, TableDescriptor, TableInstance, TableRef,
|
||||
Error, FuncInstance, FuncRef, GlobalDescriptor, GlobalInstance, GlobalRef, ImportsBuilder, MemoryDescriptor,
|
||||
MemoryInstance, MemoryRef, Module, ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue, Signature,
|
||||
TableDescriptor, TableInstance, TableRef,
|
||||
};
|
||||
|
||||
fn load_from_file(filename: &str) -> Module {
|
||||
|
@ -27,33 +27,21 @@ impl ModuleImportResolver for ResolveAll {
|
|||
Ok(FuncInstance::alloc_host(signature.clone(), 0))
|
||||
}
|
||||
|
||||
fn resolve_global(
|
||||
&self,
|
||||
_field_name: &str,
|
||||
global_type: &GlobalDescriptor,
|
||||
) -> Result<GlobalRef, Error> {
|
||||
fn resolve_global(&self, _field_name: &str, global_type: &GlobalDescriptor) -> Result<GlobalRef, Error> {
|
||||
Ok(GlobalInstance::alloc(
|
||||
RuntimeValue::default(global_type.value_type()),
|
||||
global_type.is_mutable(),
|
||||
))
|
||||
}
|
||||
|
||||
fn resolve_memory(
|
||||
&self,
|
||||
_field_name: &str,
|
||||
memory_type: &MemoryDescriptor,
|
||||
) -> Result<MemoryRef, Error> {
|
||||
fn resolve_memory(&self, _field_name: &str, memory_type: &MemoryDescriptor) -> Result<MemoryRef, Error> {
|
||||
Ok(MemoryInstance::alloc(
|
||||
Pages(memory_type.initial() as usize),
|
||||
memory_type.maximum().map(|m| Pages(m as usize)),
|
||||
).unwrap())
|
||||
}
|
||||
|
||||
fn resolve_table(
|
||||
&self,
|
||||
_field_name: &str,
|
||||
table_type: &TableDescriptor,
|
||||
) -> Result<TableRef, Error> {
|
||||
fn resolve_table(&self, _field_name: &str, table_type: &TableDescriptor) -> Result<TableRef, Error> {
|
||||
Ok(TableInstance::alloc(table_type.initial(), table_type.maximum()).unwrap())
|
||||
}
|
||||
}
|
||||
|
|
21
src/func.rs
21
src/func.rs
|
@ -63,9 +63,7 @@ impl fmt::Debug for FuncInstance {
|
|||
// debug string for function instances and this will lead to infinite loop.
|
||||
write!(f, "Internal {{ signature={:?} }}", signature,)
|
||||
}
|
||||
&FuncInstanceInternal::Host { ref signature, .. } => {
|
||||
write!(f, "Host {{ signature={:?} }}", signature)
|
||||
}
|
||||
&FuncInstanceInternal::Host { ref signature, .. } => write!(f, "Host {{ signature={:?} }}", signature),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,11 +101,7 @@ impl FuncInstance {
|
|||
&self.0
|
||||
}
|
||||
|
||||
pub(crate) fn alloc_internal(
|
||||
module: Weak<ModuleInstance>,
|
||||
signature: Rc<Signature>,
|
||||
body: FuncBody,
|
||||
) -> FuncRef {
|
||||
pub(crate) fn alloc_internal(module: Weak<ModuleInstance>, signature: Rc<Signature>, body: FuncBody) -> FuncRef {
|
||||
let func = FuncInstanceInternal::Internal {
|
||||
signature,
|
||||
module: module,
|
||||
|
@ -144,8 +138,7 @@ impl FuncInstance {
|
|||
interpreter.start_execution(externals)
|
||||
}
|
||||
FuncInstanceInternal::Host {
|
||||
ref host_func_index,
|
||||
..
|
||||
ref host_func_index, ..
|
||||
} => externals.invoke_index(*host_func_index, args.into()),
|
||||
}
|
||||
}
|
||||
|
@ -164,10 +157,7 @@ impl FuncInstance {
|
|||
/// [`Trap`]: #enum.Trap.html
|
||||
/// [`start_execution`]: struct.FuncInvocation.html#method.start_execution
|
||||
/// [`resume_execution`]: struct.FuncInvocation.html#method.resume_execution
|
||||
pub fn invoke_resumable<'args>(
|
||||
func: &FuncRef,
|
||||
args: &'args [RuntimeValue],
|
||||
) -> Result<FuncInvocation<'args>, Trap> {
|
||||
pub fn invoke_resumable<'args>(func: &FuncRef, args: &'args [RuntimeValue]) -> Result<FuncInvocation<'args>, Trap> {
|
||||
check_function_args(func.signature(), &args)?;
|
||||
match *func.as_internal() {
|
||||
FuncInstanceInternal::Internal { .. } => {
|
||||
|
@ -177,8 +167,7 @@ impl FuncInstance {
|
|||
})
|
||||
}
|
||||
FuncInstanceInternal::Host {
|
||||
ref host_func_index,
|
||||
..
|
||||
ref host_func_index, ..
|
||||
} => Ok(FuncInvocation {
|
||||
kind: FuncInvocationKind::Host {
|
||||
args,
|
||||
|
|
|
@ -57,9 +57,7 @@ impl GlobalInstance {
|
|||
/// type of `val` doesn't match global's type.
|
||||
pub fn set(&self, val: RuntimeValue) -> Result<(), Error> {
|
||||
if !self.mutable {
|
||||
return Err(Error::Global(
|
||||
"Attempt to change an immutable variable".into(),
|
||||
));
|
||||
return Err(Error::Global("Attempt to change an immutable variable".into()));
|
||||
}
|
||||
if self.value_type() != val.value_type() {
|
||||
return Err(Error::Global("Attempt to change variable type".into()));
|
||||
|
|
12
src/host.rs
12
src/host.rs
|
@ -208,11 +208,7 @@ impl HostError {
|
|||
/// ```
|
||||
pub trait Externals {
|
||||
/// Perform invoke of a host function by specified `index`.
|
||||
fn invoke_index(
|
||||
&mut self,
|
||||
index: usize,
|
||||
args: RuntimeArgs,
|
||||
) -> Result<Option<RuntimeValue>, Trap>;
|
||||
fn invoke_index(&mut self, index: usize, args: RuntimeArgs) -> Result<Option<RuntimeValue>, Trap>;
|
||||
}
|
||||
|
||||
/// Implementation of [`Externals`] that just traps on [`invoke_index`].
|
||||
|
@ -222,11 +218,7 @@ pub trait Externals {
|
|||
pub struct NopExternals;
|
||||
|
||||
impl Externals for NopExternals {
|
||||
fn invoke_index(
|
||||
&mut self,
|
||||
_index: usize,
|
||||
_args: RuntimeArgs,
|
||||
) -> Result<Option<RuntimeValue>, Trap> {
|
||||
fn invoke_index(&mut self, _index: usize, _args: RuntimeArgs) -> Result<Option<RuntimeValue>, Trap> {
|
||||
Err(TrapKind::Unreachable.into())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,12 +30,7 @@ pub trait ImportResolver {
|
|||
///
|
||||
/// Returned function should match given `signature`, i.e. all parameter types and return value should have exact match.
|
||||
/// Otherwise, link-time error will occur.
|
||||
fn resolve_func(
|
||||
&self,
|
||||
_module_name: &str,
|
||||
field_name: &str,
|
||||
_signature: &Signature,
|
||||
) -> Result<FuncRef, Error>;
|
||||
fn resolve_func(&self, _module_name: &str, field_name: &str, _signature: &Signature) -> Result<FuncRef, Error>;
|
||||
|
||||
/// Resolve a global variable.
|
||||
///
|
||||
|
@ -124,11 +119,7 @@ impl<'a> ImportsBuilder<'a> {
|
|||
}
|
||||
|
||||
/// Register an resolver by a name.
|
||||
pub fn with_resolver<N: Into<String>>(
|
||||
mut self,
|
||||
name: N,
|
||||
resolver: &'a ModuleImportResolver,
|
||||
) -> Self {
|
||||
pub fn with_resolver<N: Into<String>>(mut self, name: N, resolver: &'a ModuleImportResolver) -> Self {
|
||||
self.modules.insert(name.into(), resolver);
|
||||
self
|
||||
}
|
||||
|
@ -146,12 +137,7 @@ impl<'a> ImportsBuilder<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ImportResolver for ImportsBuilder<'a> {
|
||||
fn resolve_func(
|
||||
&self,
|
||||
module_name: &str,
|
||||
field_name: &str,
|
||||
signature: &Signature,
|
||||
) -> Result<FuncRef, Error> {
|
||||
fn resolve_func(&self, module_name: &str, field_name: &str, signature: &Signature) -> Result<FuncRef, Error> {
|
||||
self.resolver(module_name)
|
||||
.ok_or_else(|| Error::Instantiation(format!("Module {} not found", module_name)))?
|
||||
.resolve_func(field_name, signature)
|
||||
|
@ -201,10 +187,7 @@ pub trait ModuleImportResolver {
|
|||
///
|
||||
/// [`ImportResolver::resolve_func`]: trait.ImportResolver.html#tymethod.resolve_func
|
||||
fn resolve_func(&self, field_name: &str, _signature: &Signature) -> Result<FuncRef, Error> {
|
||||
Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
Err(Error::Instantiation(format!("Export {} not found", field_name)))
|
||||
}
|
||||
|
||||
/// Resolve a global variable.
|
||||
|
@ -212,15 +195,8 @@ pub trait ModuleImportResolver {
|
|||
/// See [`ImportResolver::resolve_global`] for details.
|
||||
///
|
||||
/// [`ImportResolver::resolve_global`]: trait.ImportResolver.html#tymethod.resolve_global
|
||||
fn resolve_global(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_global_type: &GlobalDescriptor,
|
||||
) -> Result<GlobalRef, Error> {
|
||||
Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
fn resolve_global(&self, field_name: &str, _global_type: &GlobalDescriptor) -> Result<GlobalRef, Error> {
|
||||
Err(Error::Instantiation(format!("Export {} not found", field_name)))
|
||||
}
|
||||
|
||||
/// Resolve a memory.
|
||||
|
@ -228,15 +204,8 @@ pub trait ModuleImportResolver {
|
|||
/// See [`ImportResolver::resolve_memory`] for details.
|
||||
///
|
||||
/// [`ImportResolver::resolve_memory`]: trait.ImportResolver.html#tymethod.resolve_memory
|
||||
fn resolve_memory(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_memory_type: &MemoryDescriptor,
|
||||
) -> Result<MemoryRef, Error> {
|
||||
Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
fn resolve_memory(&self, field_name: &str, _memory_type: &MemoryDescriptor) -> Result<MemoryRef, Error> {
|
||||
Err(Error::Instantiation(format!("Export {} not found", field_name)))
|
||||
}
|
||||
|
||||
/// Resolve a table.
|
||||
|
@ -244,15 +213,8 @@ pub trait ModuleImportResolver {
|
|||
/// See [`ImportResolver::resolve_table`] for details.
|
||||
///
|
||||
/// [`ImportResolver::resolve_table`]: trait.ImportResolver.html#tymethod.resolve_table
|
||||
fn resolve_table(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_table_type: &TableDescriptor,
|
||||
) -> Result<TableRef, Error> {
|
||||
Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
fn resolve_table(&self, field_name: &str, _table_type: &TableDescriptor) -> Result<TableRef, Error> {
|
||||
Err(Error::Instantiation(format!("Export {} not found", field_name)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,46 +225,28 @@ impl ModuleImportResolver for ModuleRef {
|
|||
.ok_or_else(|| Error::Instantiation(format!("Export {} not found", field_name)))?
|
||||
.as_func()
|
||||
.cloned()
|
||||
.ok_or_else(|| {
|
||||
Error::Instantiation(format!("Export {} is not a function", field_name))
|
||||
})?)
|
||||
.ok_or_else(|| Error::Instantiation(format!("Export {} is not a function", field_name)))?)
|
||||
}
|
||||
|
||||
fn resolve_global(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_global_type: &GlobalDescriptor,
|
||||
) -> Result<GlobalRef, Error> {
|
||||
fn resolve_global(&self, field_name: &str, _global_type: &GlobalDescriptor) -> Result<GlobalRef, Error> {
|
||||
Ok(self
|
||||
.export_by_name(field_name)
|
||||
.ok_or_else(|| Error::Instantiation(format!("Export {} not found", field_name)))?
|
||||
.as_global()
|
||||
.cloned()
|
||||
.ok_or_else(|| {
|
||||
Error::Instantiation(format!("Export {} is not a global", field_name))
|
||||
})?)
|
||||
.ok_or_else(|| Error::Instantiation(format!("Export {} is not a global", field_name)))?)
|
||||
}
|
||||
|
||||
fn resolve_memory(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_memory_type: &MemoryDescriptor,
|
||||
) -> Result<MemoryRef, Error> {
|
||||
fn resolve_memory(&self, field_name: &str, _memory_type: &MemoryDescriptor) -> Result<MemoryRef, Error> {
|
||||
Ok(self
|
||||
.export_by_name(field_name)
|
||||
.ok_or_else(|| Error::Instantiation(format!("Export {} not found", field_name)))?
|
||||
.as_memory()
|
||||
.cloned()
|
||||
.ok_or_else(|| {
|
||||
Error::Instantiation(format!("Export {} is not a memory", field_name))
|
||||
})?)
|
||||
.ok_or_else(|| Error::Instantiation(format!("Export {} is not a memory", field_name)))?)
|
||||
}
|
||||
|
||||
fn resolve_table(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_table_type: &TableDescriptor,
|
||||
) -> Result<TableRef, Error> {
|
||||
fn resolve_table(&self, field_name: &str, _table_type: &TableDescriptor) -> Result<TableRef, Error> {
|
||||
Ok(self
|
||||
.export_by_name(field_name)
|
||||
.ok_or_else(|| Error::Instantiation(format!("Export {} not found", field_name)))?
|
||||
|
|
10
src/isa.rs
10
src/isa.rs
|
@ -371,11 +371,9 @@ impl<'a> Iterator for InstructionIter<'a> {
|
|||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||
self.instructions
|
||||
.get(self.position as usize)
|
||||
.map(|instruction| {
|
||||
self.position += 1;
|
||||
instruction
|
||||
})
|
||||
self.instructions.get(self.position as usize).map(|instruction| {
|
||||
self.position += 1;
|
||||
instruction
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -174,8 +174,7 @@ impl MemoryInstance {
|
|||
/// Get value from memory at given offset.
|
||||
pub fn get_value<T: LittleEndianConvert>(&self, offset: u32) -> Result<T, Error> {
|
||||
let mut buffer = self.buffer.borrow_mut();
|
||||
let region =
|
||||
self.checked_region(&mut buffer, offset as usize, ::core::mem::size_of::<T>())?;
|
||||
let region = self.checked_region(&mut buffer, offset as usize, ::core::mem::size_of::<T>())?;
|
||||
Ok(T::from_little_endian(&buffer[region.range()]).expect("Slice size is checked"))
|
||||
}
|
||||
|
||||
|
@ -209,9 +208,7 @@ impl MemoryInstance {
|
|||
/// Copy data in the memory at given offset.
|
||||
pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> {
|
||||
let mut buffer = self.buffer.borrow_mut();
|
||||
let range = self
|
||||
.checked_region(&mut buffer, offset as usize, value.len())?
|
||||
.range();
|
||||
let range = self.checked_region(&mut buffer, offset as usize, value.len())?.range();
|
||||
|
||||
buffer[range].copy_from_slice(value);
|
||||
|
||||
|
@ -241,9 +238,7 @@ impl MemoryInstance {
|
|||
return Ok(size_before_grow);
|
||||
}
|
||||
if additional > Pages(65536) {
|
||||
return Err(Error::Memory(format!(
|
||||
"Trying to grow memory by more than 65536 pages"
|
||||
)));
|
||||
return Err(Error::Memory(format!("Trying to grow memory by more than 65536 pages")));
|
||||
}
|
||||
|
||||
let new_size: Pages = size_before_grow + additional;
|
||||
|
@ -260,12 +255,7 @@ impl MemoryInstance {
|
|||
Ok(size_before_grow)
|
||||
}
|
||||
|
||||
fn checked_region<B>(
|
||||
&self,
|
||||
buffer: &mut B,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
) -> Result<CheckedRegion, Error>
|
||||
fn checked_region<B>(&self, buffer: &mut B, offset: usize, size: usize) -> Result<CheckedRegion, Error>
|
||||
where
|
||||
B: ::core::ops::DerefMut<Target = Vec<u8>>,
|
||||
{
|
||||
|
@ -365,8 +355,7 @@ impl MemoryInstance {
|
|||
pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> {
|
||||
let mut buffer = self.buffer.borrow_mut();
|
||||
|
||||
let (read_region, write_region) =
|
||||
self.checked_region_pair(&mut buffer, src_offset, len, dst_offset, len)?;
|
||||
let (read_region, write_region) = self.checked_region_pair(&mut buffer, src_offset, len, dst_offset, len)?;
|
||||
|
||||
unsafe {
|
||||
::core::ptr::copy(
|
||||
|
@ -390,16 +379,10 @@ impl MemoryInstance {
|
|||
///
|
||||
/// - either of specified regions is out of bounds,
|
||||
/// - these regions overlaps.
|
||||
pub fn copy_nonoverlapping(
|
||||
&self,
|
||||
src_offset: usize,
|
||||
dst_offset: usize,
|
||||
len: usize,
|
||||
) -> Result<(), Error> {
|
||||
pub fn copy_nonoverlapping(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> {
|
||||
let mut buffer = self.buffer.borrow_mut();
|
||||
|
||||
let (read_region, write_region) =
|
||||
self.checked_region_pair(&mut buffer, src_offset, len, dst_offset, len)?;
|
||||
let (read_region, write_region) = self.checked_region_pair(&mut buffer, src_offset, len, dst_offset, len)?;
|
||||
|
||||
if read_region.intersects(&write_region) {
|
||||
return Err(Error::Memory(format!(
|
||||
|
@ -439,12 +422,8 @@ impl MemoryInstance {
|
|||
let mut src_buffer = src.buffer.borrow_mut();
|
||||
let mut dst_buffer = dst.buffer.borrow_mut();
|
||||
|
||||
let src_range = src
|
||||
.checked_region(&mut src_buffer, src_offset, len)?
|
||||
.range();
|
||||
let dst_range = dst
|
||||
.checked_region(&mut dst_buffer, dst_offset, len)?
|
||||
.range();
|
||||
let src_range = src.checked_region(&mut src_buffer, src_offset, len)?.range();
|
||||
let dst_range = dst.checked_region(&mut dst_buffer, dst_offset, len)?.range();
|
||||
|
||||
dst_buffer[dst_range].copy_from_slice(&src_buffer[src_range]);
|
||||
|
||||
|
@ -588,8 +567,7 @@ mod tests {
|
|||
|
||||
fn create_memory(initial_content: &[u8]) -> MemoryInstance {
|
||||
let mem = MemoryInstance::new(Pages(1), Some(Pages(1)));
|
||||
mem.set(0, initial_content)
|
||||
.expect("Successful initialize the memory");
|
||||
mem.set(0, initial_content).expect("Successful initialize the memory");
|
||||
mem
|
||||
}
|
||||
|
||||
|
@ -641,17 +619,12 @@ mod tests {
|
|||
#[test]
|
||||
fn transfer_works() {
|
||||
let src = MemoryRef(Rc::new(create_memory(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])));
|
||||
let dst = MemoryRef(Rc::new(create_memory(&[
|
||||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
])));
|
||||
let dst = MemoryRef(Rc::new(create_memory(&[10, 11, 12, 13, 14, 15, 16, 17, 18, 19])));
|
||||
|
||||
MemoryInstance::transfer(&src, 4, &dst, 0, 3).unwrap();
|
||||
|
||||
assert_eq!(src.get(0, 10).unwrap(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||
assert_eq!(
|
||||
dst.get(0, 10).unwrap(),
|
||||
&[4, 5, 6, 13, 14, 15, 16, 17, 18, 19]
|
||||
);
|
||||
assert_eq!(dst.get(0, 10).unwrap(), &[4, 5, 6, 13, 14, 15, 16, 17, 18, 19]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -675,25 +648,19 @@ mod tests {
|
|||
#[test]
|
||||
fn transfer_oob_errors() {
|
||||
let src = MemoryRef(Rc::new(create_memory(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])));
|
||||
let dst = MemoryRef(Rc::new(create_memory(&[
|
||||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
])));
|
||||
let dst = MemoryRef(Rc::new(create_memory(&[10, 11, 12, 13, 14, 15, 16, 17, 18, 19])));
|
||||
|
||||
assert!(MemoryInstance::transfer(&src, 65535, &dst, 0, 3).is_err());
|
||||
|
||||
// Check that memories content left untouched
|
||||
assert_eq!(src.get(0, 10).unwrap(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||
assert_eq!(
|
||||
dst.get(0, 10).unwrap(),
|
||||
&[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
|
||||
);
|
||||
assert_eq!(dst.get(0, 10).unwrap(), &[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clear() {
|
||||
let mem = create_memory(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||
mem.clear(0, 0x4A, 10)
|
||||
.expect("To successfully clear the memory");
|
||||
mem.clear(0, 0x4A, 10).expect("To successfully clear the memory");
|
||||
let result = mem.get(0, 10).expect("To successfully retrieve the result");
|
||||
assert_eq!(result, &[0x4A; 10]);
|
||||
}
|
||||
|
@ -701,12 +668,10 @@ mod tests {
|
|||
#[test]
|
||||
fn get_into() {
|
||||
let mem = MemoryInstance::new(Pages(1), None);
|
||||
mem.set(6, &[13, 17, 129])
|
||||
.expect("memory set should not fail");
|
||||
mem.set(6, &[13, 17, 129]).expect("memory set should not fail");
|
||||
|
||||
let mut data = [0u8; 2];
|
||||
mem.get_into(7, &mut data[..])
|
||||
.expect("get_into should not fail");
|
||||
mem.get_into(7, &mut data[..]).expect("get_into should not fail");
|
||||
|
||||
assert_eq!(data, [17, 129]);
|
||||
}
|
||||
|
|
|
@ -298,46 +298,36 @@ impl ModuleInstance {
|
|||
|
||||
let code = loaded_module.code();
|
||||
{
|
||||
let funcs = module
|
||||
.function_section()
|
||||
.map(|fs| fs.entries())
|
||||
.unwrap_or(&[]);
|
||||
let funcs = module.function_section().map(|fs| fs.entries()).unwrap_or(&[]);
|
||||
let bodies = module.code_section().map(|cs| cs.bodies()).unwrap_or(&[]);
|
||||
debug_assert!(
|
||||
funcs.len() == bodies.len(),
|
||||
"Due to validation func and body counts must match"
|
||||
);
|
||||
|
||||
for (index, (ty, body)) in
|
||||
Iterator::zip(funcs.into_iter(), bodies.into_iter()).enumerate()
|
||||
{
|
||||
for (index, (ty, body)) in Iterator::zip(funcs.into_iter(), bodies.into_iter()).enumerate() {
|
||||
let signature = instance
|
||||
.signature_by_index(ty.type_ref())
|
||||
.expect("Due to validation type should exists");
|
||||
let code = code.get(index).expect(
|
||||
"At func validation time labels are collected; Collected labels are added by index; qed",
|
||||
).clone();
|
||||
let code = code
|
||||
.get(index)
|
||||
.expect("At func validation time labels are collected; Collected labels are added by index; qed")
|
||||
.clone();
|
||||
let func_body = FuncBody {
|
||||
locals: body.locals().to_vec(),
|
||||
code: code,
|
||||
};
|
||||
let func_instance =
|
||||
FuncInstance::alloc_internal(Rc::downgrade(&instance.0), signature, func_body);
|
||||
let func_instance = FuncInstance::alloc_internal(Rc::downgrade(&instance.0), signature, func_body);
|
||||
instance.push_func(func_instance);
|
||||
}
|
||||
}
|
||||
|
||||
for table_type in module.table_section().map(|ts| ts.entries()).unwrap_or(&[]) {
|
||||
let table =
|
||||
TableInstance::alloc(table_type.limits().initial(), table_type.limits().maximum())?;
|
||||
let table = TableInstance::alloc(table_type.limits().initial(), table_type.limits().maximum())?;
|
||||
instance.push_table(table);
|
||||
}
|
||||
|
||||
for memory_type in module
|
||||
.memory_section()
|
||||
.map(|ms| ms.entries())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
for memory_type in module.memory_section().map(|ms| ms.entries()).unwrap_or(&[]) {
|
||||
let initial: Pages = Pages(memory_type.limits().initial() as usize);
|
||||
let maximum: Option<Pages> = memory_type.limits().maximum().map(|m| Pages(m as usize));
|
||||
|
||||
|
@ -346,21 +336,13 @@ impl ModuleInstance {
|
|||
instance.push_memory(memory);
|
||||
}
|
||||
|
||||
for global_entry in module
|
||||
.global_section()
|
||||
.map(|gs| gs.entries())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
for global_entry in module.global_section().map(|gs| gs.entries()).unwrap_or(&[]) {
|
||||
let init_val = eval_init_expr(global_entry.init_expr(), &*instance);
|
||||
let global = GlobalInstance::alloc(init_val, global_entry.global_type().is_mutable());
|
||||
instance.push_global(global);
|
||||
}
|
||||
|
||||
for export in module
|
||||
.export_section()
|
||||
.map(|es| es.entries())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
for export in module.export_section().map(|es| es.entries()).unwrap_or(&[]) {
|
||||
let field = export.field();
|
||||
let extern_val: ExternVal = match *export.internal() {
|
||||
Internal::Function(idx) => {
|
||||
|
@ -408,11 +390,7 @@ impl ModuleInstance {
|
|||
|
||||
let module_ref = ModuleInstance::alloc_module(loaded_module, extern_vals)?;
|
||||
|
||||
for element_segment in module
|
||||
.elements_section()
|
||||
.map(|es| es.entries())
|
||||
.unwrap_or(&[])
|
||||
{
|
||||
for element_segment in module.elements_section().map(|es| es.entries()).unwrap_or(&[]) {
|
||||
let offset_val = match eval_init_expr(element_segment.offset(), &module_ref) {
|
||||
RuntimeValue::I32(v) => v as u32,
|
||||
_ => panic!("Due to validation elem segment offset should evaluate to i32"),
|
||||
|
@ -424,12 +402,8 @@ impl ModuleInstance {
|
|||
|
||||
// This check is not only for bailing out early, but also to check the case when
|
||||
// segment consist of 0 members.
|
||||
if offset_val as u64 + element_segment.members().len() as u64
|
||||
> table_inst.current_size() as u64
|
||||
{
|
||||
return Err(Error::Instantiation(
|
||||
"elements segment does not fit".to_string(),
|
||||
));
|
||||
if offset_val as u64 + element_segment.members().len() as u64 > table_inst.current_size() as u64 {
|
||||
return Err(Error::Instantiation("elements segment does not fit".to_string()));
|
||||
}
|
||||
|
||||
for (j, func_idx) in element_segment.members().into_iter().enumerate() {
|
||||
|
@ -541,20 +515,17 @@ impl ModuleInstance {
|
|||
}
|
||||
External::Table(ref table_type) => {
|
||||
let table_descriptor = TableDescriptor::from_elements(table_type);
|
||||
let table =
|
||||
imports.resolve_table(module_name, field_name, &table_descriptor)?;
|
||||
let table = imports.resolve_table(module_name, field_name, &table_descriptor)?;
|
||||
ExternVal::Table(table)
|
||||
}
|
||||
External::Memory(ref memory_type) => {
|
||||
let memory_descriptor = MemoryDescriptor::from_elements(memory_type);
|
||||
let memory =
|
||||
imports.resolve_memory(module_name, field_name, &memory_descriptor)?;
|
||||
let memory = imports.resolve_memory(module_name, field_name, &memory_descriptor)?;
|
||||
ExternVal::Memory(memory)
|
||||
}
|
||||
External::Global(ref global_type) => {
|
||||
let global_descriptor = GlobalDescriptor::from_elements(global_type);
|
||||
let global =
|
||||
imports.resolve_global(module_name, field_name, &global_descriptor)?;
|
||||
let global = imports.resolve_global(module_name, field_name, &global_descriptor)?;
|
||||
ExternVal::Global(global)
|
||||
}
|
||||
};
|
||||
|
@ -711,10 +682,7 @@ impl<'a> NotStartedModuleRef<'a> {
|
|||
|
||||
fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance) -> RuntimeValue {
|
||||
let code = init_expr.code();
|
||||
debug_assert!(
|
||||
code.len() == 2,
|
||||
"Due to validation `code`.len() should be 2"
|
||||
);
|
||||
debug_assert!(code.len() == 2, "Due to validation `code`.len() should be 2");
|
||||
match code[0] {
|
||||
Instruction::I32Const(v) => v.into(),
|
||||
Instruction::I64Const(v) => v.into(),
|
||||
|
|
|
@ -12,10 +12,7 @@ macro_rules! impl_binop {
|
|||
type Output = Self;
|
||||
|
||||
fn $func_name(self, other: T) -> Self {
|
||||
$for(
|
||||
$op::$func_name($is::from_bits(self.0), $is::from_bits(other.into().0))
|
||||
.to_bits(),
|
||||
)
|
||||
$for($op::$func_name($is::from_bits(self.0), $is::from_bits(other.into().0)).to_bits())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -23,12 +20,7 @@ macro_rules! impl_binop {
|
|||
|
||||
macro_rules! float {
|
||||
($for:ident, $rep:ident, $is:ident) => {
|
||||
float!(
|
||||
$for,
|
||||
$rep,
|
||||
$is,
|
||||
1 << (::core::mem::size_of::<$is>() * 8 - 1)
|
||||
);
|
||||
float!($for, $rep, $is, 1 << (::core::mem::size_of::<$is>() * 8 - 1));
|
||||
};
|
||||
($for:ident, $rep:ident, $is:ident, $sign_bit:expr) => {
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
230
src/runner.rs
230
src/runner.rs
|
@ -13,8 +13,8 @@ use module::ModuleRef;
|
|||
use nan_preserving_float::{F32, F64};
|
||||
use parity_wasm::elements::Local;
|
||||
use value::{
|
||||
ArithmeticOps, ExtendInto, Float, Integer, LittleEndianConvert, RuntimeValue, TransmuteInto,
|
||||
TryTruncateInto, WrapInto,
|
||||
ArithmeticOps, ExtendInto, Float, Integer, LittleEndianConvert, RuntimeValue, TransmuteInto, TryTruncateInto,
|
||||
WrapInto,
|
||||
};
|
||||
use {Signature, Trap, TrapKind, ValueType};
|
||||
|
||||
|
@ -211,9 +211,7 @@ impl Interpreter {
|
|||
self.state = InterpreterState::Started;
|
||||
self.run_interpreter_loop(externals)?;
|
||||
|
||||
let opt_return_value = self
|
||||
.return_type
|
||||
.map(|vt| self.value_stack.pop().with_type(vt));
|
||||
let opt_return_value = self.return_type.map(|vt| self.value_stack.pop().with_type(vt));
|
||||
|
||||
// Ensure that stack is empty after the execution. This is guaranteed by the validation properties.
|
||||
assert!(self.value_stack.len() == 0);
|
||||
|
@ -235,16 +233,12 @@ impl Interpreter {
|
|||
swap(&mut self.state, &mut resumable_state);
|
||||
|
||||
if let Some(return_val) = return_val {
|
||||
self.value_stack
|
||||
.push(return_val.into())
|
||||
.map_err(Trap::new)?;
|
||||
self.value_stack.push(return_val.into()).map_err(Trap::new)?;
|
||||
}
|
||||
|
||||
self.run_interpreter_loop(externals)?;
|
||||
|
||||
let opt_return_value = self
|
||||
.return_type
|
||||
.map(|vt| self.value_stack.pop().with_type(vt));
|
||||
let opt_return_value = self.return_type.map(|vt| self.value_stack.pop().with_type(vt));
|
||||
|
||||
// Ensure that stack is empty after the execution. This is guaranteed by the validation properties.
|
||||
assert!(self.value_stack.len() == 0);
|
||||
|
@ -252,20 +246,16 @@ impl Interpreter {
|
|||
Ok(opt_return_value)
|
||||
}
|
||||
|
||||
fn run_interpreter_loop<'a, E: Externals + 'a>(
|
||||
&mut self,
|
||||
externals: &'a mut E,
|
||||
) -> Result<(), Trap> {
|
||||
fn run_interpreter_loop<'a, E: Externals + 'a>(&mut self, externals: &'a mut E) -> Result<(), Trap> {
|
||||
loop {
|
||||
let mut function_context = self.call_stack.pop().expect(
|
||||
"on loop entry - not empty; on loop continue - checking for emptiness; qed",
|
||||
);
|
||||
let mut function_context = self
|
||||
.call_stack
|
||||
.pop()
|
||||
.expect("on loop entry - not empty; on loop continue - checking for emptiness; qed");
|
||||
let function_ref = function_context.function.clone();
|
||||
let function_body = function_ref
|
||||
.body()
|
||||
.expect(
|
||||
"Host functions checked in function_return below; Internal functions always have a body; qed"
|
||||
);
|
||||
.expect("Host functions checked in function_return below; Internal functions always have a body; qed");
|
||||
|
||||
if !function_context.is_initialized() {
|
||||
// Initialize stack frame for the function call.
|
||||
|
@ -300,18 +290,15 @@ impl Interpreter {
|
|||
// We push the function context first. If the VM is not resumable, it does no harm. If it is, we then save the context here.
|
||||
self.call_stack.push(function_context);
|
||||
|
||||
let return_val =
|
||||
match FuncInstance::invoke(&nested_func, &args, externals) {
|
||||
Ok(val) => val,
|
||||
Err(trap) => {
|
||||
if trap.kind().is_host() {
|
||||
self.state = InterpreterState::Resumable(
|
||||
nested_func.signature().return_type(),
|
||||
);
|
||||
}
|
||||
return Err(trap);
|
||||
let return_val = match FuncInstance::invoke(&nested_func, &args, externals) {
|
||||
Ok(val) => val,
|
||||
Err(trap) => {
|
||||
if trap.kind().is_host() {
|
||||
self.state = InterpreterState::Resumable(nested_func.signature().return_type());
|
||||
}
|
||||
};
|
||||
return Err(trap);
|
||||
}
|
||||
};
|
||||
|
||||
// Check if `return_val` matches the signature.
|
||||
let value_ty = return_val.as_ref().map(|val| val.value_type());
|
||||
|
@ -321,9 +308,7 @@ impl Interpreter {
|
|||
}
|
||||
|
||||
if let Some(return_val) = return_val {
|
||||
self.value_stack
|
||||
.push(return_val.into())
|
||||
.map_err(Trap::new)?;
|
||||
self.value_stack.push(return_val.into()).map_err(Trap::new)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -392,52 +377,26 @@ impl Interpreter {
|
|||
&isa::Instruction::I64Load(offset) => self.run_load::<i64>(context, offset),
|
||||
&isa::Instruction::F32Load(offset) => self.run_load::<F32>(context, offset),
|
||||
&isa::Instruction::F64Load(offset) => self.run_load::<F64>(context, offset),
|
||||
&isa::Instruction::I32Load8S(offset) => {
|
||||
self.run_load_extend::<i8, i32>(context, offset)
|
||||
}
|
||||
&isa::Instruction::I32Load8U(offset) => {
|
||||
self.run_load_extend::<u8, i32>(context, offset)
|
||||
}
|
||||
&isa::Instruction::I32Load16S(offset) => {
|
||||
self.run_load_extend::<i16, i32>(context, offset)
|
||||
}
|
||||
&isa::Instruction::I32Load16U(offset) => {
|
||||
self.run_load_extend::<u16, i32>(context, offset)
|
||||
}
|
||||
&isa::Instruction::I64Load8S(offset) => {
|
||||
self.run_load_extend::<i8, i64>(context, offset)
|
||||
}
|
||||
&isa::Instruction::I64Load8U(offset) => {
|
||||
self.run_load_extend::<u8, i64>(context, offset)
|
||||
}
|
||||
&isa::Instruction::I64Load16S(offset) => {
|
||||
self.run_load_extend::<i16, i64>(context, offset)
|
||||
}
|
||||
&isa::Instruction::I64Load16U(offset) => {
|
||||
self.run_load_extend::<u16, i64>(context, offset)
|
||||
}
|
||||
&isa::Instruction::I64Load32S(offset) => {
|
||||
self.run_load_extend::<i32, i64>(context, offset)
|
||||
}
|
||||
&isa::Instruction::I64Load32U(offset) => {
|
||||
self.run_load_extend::<u32, i64>(context, offset)
|
||||
}
|
||||
&isa::Instruction::I32Load8S(offset) => self.run_load_extend::<i8, i32>(context, offset),
|
||||
&isa::Instruction::I32Load8U(offset) => self.run_load_extend::<u8, i32>(context, offset),
|
||||
&isa::Instruction::I32Load16S(offset) => self.run_load_extend::<i16, i32>(context, offset),
|
||||
&isa::Instruction::I32Load16U(offset) => self.run_load_extend::<u16, i32>(context, offset),
|
||||
&isa::Instruction::I64Load8S(offset) => self.run_load_extend::<i8, i64>(context, offset),
|
||||
&isa::Instruction::I64Load8U(offset) => self.run_load_extend::<u8, i64>(context, offset),
|
||||
&isa::Instruction::I64Load16S(offset) => self.run_load_extend::<i16, i64>(context, offset),
|
||||
&isa::Instruction::I64Load16U(offset) => self.run_load_extend::<u16, i64>(context, offset),
|
||||
&isa::Instruction::I64Load32S(offset) => self.run_load_extend::<i32, i64>(context, offset),
|
||||
&isa::Instruction::I64Load32U(offset) => self.run_load_extend::<u32, i64>(context, offset),
|
||||
|
||||
&isa::Instruction::I32Store(offset) => self.run_store::<i32>(context, offset),
|
||||
&isa::Instruction::I64Store(offset) => self.run_store::<i64>(context, offset),
|
||||
&isa::Instruction::F32Store(offset) => self.run_store::<F32>(context, offset),
|
||||
&isa::Instruction::F64Store(offset) => self.run_store::<F64>(context, offset),
|
||||
&isa::Instruction::I32Store8(offset) => self.run_store_wrap::<i32, i8>(context, offset),
|
||||
&isa::Instruction::I32Store16(offset) => {
|
||||
self.run_store_wrap::<i32, i16>(context, offset)
|
||||
}
|
||||
&isa::Instruction::I32Store16(offset) => self.run_store_wrap::<i32, i16>(context, offset),
|
||||
&isa::Instruction::I64Store8(offset) => self.run_store_wrap::<i64, i8>(context, offset),
|
||||
&isa::Instruction::I64Store16(offset) => {
|
||||
self.run_store_wrap::<i64, i16>(context, offset)
|
||||
}
|
||||
&isa::Instruction::I64Store32(offset) => {
|
||||
self.run_store_wrap::<i64, i32>(context, offset)
|
||||
}
|
||||
&isa::Instruction::I64Store16(offset) => self.run_store_wrap::<i64, i16>(context, offset),
|
||||
&isa::Instruction::I64Store32(offset) => self.run_store_wrap::<i64, i32>(context, offset),
|
||||
|
||||
&isa::Instruction::CurrentMemory => self.run_current_memory(context),
|
||||
&isa::Instruction::GrowMemory => self.run_grow_memory(context),
|
||||
|
@ -582,18 +541,11 @@ impl Interpreter {
|
|||
}
|
||||
}
|
||||
|
||||
fn run_unreachable(
|
||||
&mut self,
|
||||
_context: &mut FunctionContext,
|
||||
) -> Result<InstructionOutcome, TrapKind> {
|
||||
fn run_unreachable(&mut self, _context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
||||
Err(TrapKind::Unreachable)
|
||||
}
|
||||
|
||||
fn run_br(
|
||||
&mut self,
|
||||
_context: &mut FunctionContext,
|
||||
target: isa::Target,
|
||||
) -> Result<InstructionOutcome, TrapKind> {
|
||||
fn run_br(&mut self, _context: &mut FunctionContext, target: isa::Target) -> Result<InstructionOutcome, TrapKind> {
|
||||
Ok(InstructionOutcome::Branch(target))
|
||||
}
|
||||
|
||||
|
@ -633,11 +585,7 @@ impl Interpreter {
|
|||
Ok(InstructionOutcome::Return(drop_keep))
|
||||
}
|
||||
|
||||
fn run_call(
|
||||
&mut self,
|
||||
context: &mut FunctionContext,
|
||||
func_idx: u32,
|
||||
) -> Result<InstructionOutcome, TrapKind> {
|
||||
fn run_call(&mut self, context: &mut FunctionContext, func_idx: u32) -> Result<InstructionOutcome, TrapKind> {
|
||||
let func = context
|
||||
.module()
|
||||
.func_by_index(func_idx)
|
||||
|
@ -707,11 +655,7 @@ impl Interpreter {
|
|||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_get_global(
|
||||
&mut self,
|
||||
context: &mut FunctionContext,
|
||||
index: u32,
|
||||
) -> Result<InstructionOutcome, TrapKind> {
|
||||
fn run_get_global(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, TrapKind> {
|
||||
let global = context
|
||||
.module()
|
||||
.global_by_index(index)
|
||||
|
@ -721,11 +665,7 @@ impl Interpreter {
|
|||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_set_global(
|
||||
&mut self,
|
||||
context: &mut FunctionContext,
|
||||
index: u32,
|
||||
) -> Result<InstructionOutcome, TrapKind> {
|
||||
fn run_set_global(&mut self, context: &mut FunctionContext, index: u32) -> Result<InstructionOutcome, TrapKind> {
|
||||
let val = self.value_stack.pop();
|
||||
let global = context
|
||||
.module()
|
||||
|
@ -737,23 +677,15 @@ impl Interpreter {
|
|||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_load<T>(
|
||||
&mut self,
|
||||
context: &mut FunctionContext,
|
||||
offset: u32,
|
||||
) -> Result<InstructionOutcome, TrapKind>
|
||||
fn run_load<T>(&mut self, context: &mut FunctionContext, offset: u32) -> Result<InstructionOutcome, TrapKind>
|
||||
where
|
||||
RuntimeValueInternal: From<T>,
|
||||
T: LittleEndianConvert,
|
||||
{
|
||||
let raw_address = self.value_stack.pop_as();
|
||||
let address = effective_address(offset, raw_address)?;
|
||||
let m = context
|
||||
.memory()
|
||||
.expect("Due to validation memory should exists");
|
||||
let n: T = m
|
||||
.get_value(address)
|
||||
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
||||
let m = context.memory().expect("Due to validation memory should exists");
|
||||
let n: T = m.get_value(address).map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
||||
self.value_stack.push(n.into())?;
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
@ -770,12 +702,8 @@ impl Interpreter {
|
|||
{
|
||||
let raw_address = self.value_stack.pop_as();
|
||||
let address = effective_address(offset, raw_address)?;
|
||||
let m = context
|
||||
.memory()
|
||||
.expect("Due to validation memory should exists");
|
||||
let v: T = m
|
||||
.get_value(address)
|
||||
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
||||
let m = context.memory().expect("Due to validation memory should exists");
|
||||
let v: T = m.get_value(address).map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
||||
let stack_value: U = v.extend_into();
|
||||
self.value_stack
|
||||
.push(stack_value.into())
|
||||
|
@ -783,11 +711,7 @@ impl Interpreter {
|
|||
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_store<T>(
|
||||
&mut self,
|
||||
context: &mut FunctionContext,
|
||||
offset: u32,
|
||||
) -> Result<InstructionOutcome, TrapKind>
|
||||
fn run_store<T>(&mut self, context: &mut FunctionContext, offset: u32) -> Result<InstructionOutcome, TrapKind>
|
||||
where
|
||||
T: FromRuntimeValueInternal,
|
||||
T: LittleEndianConvert,
|
||||
|
@ -796,9 +720,7 @@ impl Interpreter {
|
|||
let raw_address = self.value_stack.pop_as::<u32>();
|
||||
let address = effective_address(offset, raw_address)?;
|
||||
|
||||
let m = context
|
||||
.memory()
|
||||
.expect("Due to validation memory should exists");
|
||||
let m = context.memory().expect("Due to validation memory should exists");
|
||||
m.set_value(address, stack_value)
|
||||
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
|
@ -818,34 +740,22 @@ impl Interpreter {
|
|||
let stack_value = stack_value.wrap_into();
|
||||
let raw_address = self.value_stack.pop_as::<u32>();
|
||||
let address = effective_address(offset, raw_address)?;
|
||||
let m = context
|
||||
.memory()
|
||||
.expect("Due to validation memory should exists");
|
||||
let m = context.memory().expect("Due to validation memory should exists");
|
||||
m.set_value(address, stack_value)
|
||||
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_current_memory(
|
||||
&mut self,
|
||||
context: &mut FunctionContext,
|
||||
) -> Result<InstructionOutcome, TrapKind> {
|
||||
let m = context
|
||||
.memory()
|
||||
.expect("Due to validation memory should exists");
|
||||
fn run_current_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
||||
let m = context.memory().expect("Due to validation memory should exists");
|
||||
let s = m.current_size().0;
|
||||
self.value_stack.push(RuntimeValueInternal(s as _))?;
|
||||
Ok(InstructionOutcome::RunNextInstruction)
|
||||
}
|
||||
|
||||
fn run_grow_memory(
|
||||
&mut self,
|
||||
context: &mut FunctionContext,
|
||||
) -> Result<InstructionOutcome, TrapKind> {
|
||||
fn run_grow_memory(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
||||
let pages: u32 = self.value_stack.pop_as();
|
||||
let m = context
|
||||
.memory()
|
||||
.expect("Due to validation memory should exists");
|
||||
let m = context.memory().expect("Due to validation memory should exists");
|
||||
let m = match m.grow(Pages(pages as usize)) {
|
||||
Ok(Pages(new_size)) => new_size as u32,
|
||||
Err(_) => u32::MAX, // Returns -1 (or 0xFFFFFFFF) in case of error.
|
||||
|
@ -1279,11 +1189,7 @@ impl FunctionContext {
|
|||
self.is_initialized
|
||||
}
|
||||
|
||||
pub fn initialize(
|
||||
&mut self,
|
||||
locals: &[Local],
|
||||
value_stack: &mut ValueStack,
|
||||
) -> Result<(), TrapKind> {
|
||||
pub fn initialize(&mut self, locals: &[Local], value_stack: &mut ValueStack) -> Result<(), TrapKind> {
|
||||
debug_assert!(!self.is_initialized);
|
||||
|
||||
let num_locals = locals.iter().map(|l| l.count() as usize).sum();
|
||||
|
@ -1291,9 +1197,7 @@ impl FunctionContext {
|
|||
|
||||
// TODO: Replace with extend.
|
||||
for local in locals {
|
||||
value_stack
|
||||
.push(local)
|
||||
.map_err(|_| TrapKind::StackOverflow)?;
|
||||
value_stack.push(local).map_err(|_| TrapKind::StackOverflow)?;
|
||||
}
|
||||
|
||||
self.is_initialized = true;
|
||||
|
@ -1322,10 +1226,7 @@ fn effective_address(address: u32, offset: u32) -> Result<u32, TrapKind> {
|
|||
}
|
||||
}
|
||||
|
||||
fn prepare_function_args(
|
||||
signature: &Signature,
|
||||
caller_stack: &mut ValueStack,
|
||||
) -> Vec<RuntimeValue> {
|
||||
fn prepare_function_args(signature: &Signature, caller_stack: &mut ValueStack) -> Vec<RuntimeValue> {
|
||||
let mut out = signature
|
||||
.params()
|
||||
.iter()
|
||||
|
@ -1341,14 +1242,10 @@ pub fn check_function_args(signature: &Signature, args: &[RuntimeValue]) -> Resu
|
|||
return Err(TrapKind::UnexpectedSignature.into());
|
||||
}
|
||||
|
||||
if signature
|
||||
.params()
|
||||
.iter()
|
||||
.zip(args)
|
||||
.any(|(expected_type, param_value)| {
|
||||
let actual_type = param_value.value_type();
|
||||
&actual_type != expected_type
|
||||
}) {
|
||||
if signature.params().iter().zip(args).any(|(expected_type, param_value)| {
|
||||
let actual_type = param_value.value_type();
|
||||
&actual_type != expected_type
|
||||
}) {
|
||||
return Err(TrapKind::UnexpectedSignature.into());
|
||||
}
|
||||
|
||||
|
@ -1405,13 +1302,7 @@ impl ValueStack {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn pop_triple(
|
||||
&mut self,
|
||||
) -> (
|
||||
RuntimeValueInternal,
|
||||
RuntimeValueInternal,
|
||||
RuntimeValueInternal,
|
||||
) {
|
||||
fn pop_triple(&mut self) -> (RuntimeValueInternal, RuntimeValueInternal, RuntimeValueInternal) {
|
||||
let right = self.pop();
|
||||
let mid = self.pop();
|
||||
let left = self.pop();
|
||||
|
@ -1440,10 +1331,7 @@ impl ValueStack {
|
|||
|
||||
#[inline]
|
||||
fn push(&mut self, value: RuntimeValueInternal) -> Result<(), TrapKind> {
|
||||
let cell = self
|
||||
.buf
|
||||
.get_mut(self.sp)
|
||||
.ok_or_else(|| TrapKind::StackOverflow)?;
|
||||
let cell = self.buf.get_mut(self.sp).ok_or_else(|| TrapKind::StackOverflow)?;
|
||||
*cell = value;
|
||||
self.sp += 1;
|
||||
Ok(())
|
||||
|
|
|
@ -109,13 +109,8 @@ impl TableInstance {
|
|||
let new_size = self
|
||||
.current_size()
|
||||
.checked_add(by)
|
||||
.and_then(|new_size| {
|
||||
if maximum_size < new_size {
|
||||
None
|
||||
} else {
|
||||
Some(new_size)
|
||||
}
|
||||
}).ok_or_else(|| {
|
||||
.and_then(|new_size| if maximum_size < new_size { None } else { Some(new_size) })
|
||||
.ok_or_else(|| {
|
||||
Error::Table(format!(
|
||||
"Trying to grow table by {} items when there are already {} items",
|
||||
by,
|
||||
|
|
|
@ -2,9 +2,9 @@ use super::parse_wat;
|
|||
use memory_units::Pages;
|
||||
use types::ValueType;
|
||||
use {
|
||||
Error, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, MemoryDescriptor,
|
||||
MemoryInstance, MemoryRef, ModuleImportResolver, ModuleInstance, ModuleRef, ResumableError,
|
||||
RuntimeArgs, RuntimeValue, Signature, TableDescriptor, TableInstance, TableRef, Trap, TrapKind,
|
||||
Error, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, MemoryDescriptor, MemoryInstance, MemoryRef,
|
||||
ModuleImportResolver, ModuleInstance, ModuleRef, ResumableError, RuntimeArgs, RuntimeValue, Signature,
|
||||
TableDescriptor, TableInstance, TableRef, Trap, TrapKind,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -85,11 +85,7 @@ const RECURSE_FUNC_INDEX: usize = 4;
|
|||
const TRAP_SUB_FUNC_INDEX: usize = 5;
|
||||
|
||||
impl Externals for TestHost {
|
||||
fn invoke_index(
|
||||
&mut self,
|
||||
index: usize,
|
||||
args: RuntimeArgs,
|
||||
) -> Result<Option<RuntimeValue>, Trap> {
|
||||
fn invoke_index(&mut self, index: usize, args: RuntimeArgs) -> Result<Option<RuntimeValue>, Trap> {
|
||||
match index {
|
||||
SUB_FUNC_INDEX => {
|
||||
let a: i32 = args.nth(0);
|
||||
|
@ -131,9 +127,7 @@ impl Externals for TestHost {
|
|||
Ok(Some(RuntimeValue::I32(buf[0] as i32)))
|
||||
}
|
||||
RECURSE_FUNC_INDEX => {
|
||||
let val = args
|
||||
.nth_value_checked(0)
|
||||
.expect("Exactly one argument expected");
|
||||
let val = args.nth_value_checked(0).expect("Exactly one argument expected");
|
||||
|
||||
let instance = self
|
||||
.instance
|
||||
|
@ -146,9 +140,7 @@ impl Externals for TestHost {
|
|||
.expect("expected to be Some");
|
||||
|
||||
if val.value_type() != result.value_type() {
|
||||
return Err(
|
||||
TrapKind::Host(Box::new(HostErrorWithCode { error_code: 123 })).into(),
|
||||
);
|
||||
return Err(TrapKind::Host(Box::new(HostErrorWithCode { error_code: 123 })).into());
|
||||
}
|
||||
Ok(Some(result))
|
||||
}
|
||||
|
@ -198,12 +190,7 @@ impl ModuleImportResolver for TestHost {
|
|||
"get_mem" => GET_MEM_FUNC_INDEX,
|
||||
"recurse" => RECURSE_FUNC_INDEX,
|
||||
"trap_sub" => TRAP_SUB_FUNC_INDEX,
|
||||
_ => {
|
||||
return Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
}
|
||||
_ => return Err(Error::Instantiation(format!("Export {} not found", field_name))),
|
||||
};
|
||||
|
||||
if !self.check_signature(index, signature) {
|
||||
|
@ -216,15 +203,8 @@ impl ModuleImportResolver for TestHost {
|
|||
Ok(FuncInstance::alloc_host(signature.clone(), index))
|
||||
}
|
||||
|
||||
fn resolve_memory(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_memory_type: &MemoryDescriptor,
|
||||
) -> Result<MemoryRef, Error> {
|
||||
Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
fn resolve_memory(&self, field_name: &str, _memory_type: &MemoryDescriptor) -> Result<MemoryRef, Error> {
|
||||
Err(Error::Instantiation(format!("Export {} not found", field_name)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -484,10 +464,7 @@ fn defer_providing_externals() {
|
|||
impl ModuleImportResolver for HostImportResolver {
|
||||
fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result<FuncRef, Error> {
|
||||
if field_name != "inc" {
|
||||
return Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)));
|
||||
return Err(Error::Instantiation(format!("Export {} not found", field_name)));
|
||||
}
|
||||
if signature.params() != &[ValueType::I32] || signature.return_type() != None {
|
||||
return Err(Error::Instantiation(format!(
|
||||
|
@ -499,18 +476,11 @@ fn defer_providing_externals() {
|
|||
Ok(FuncInstance::alloc_host(signature.clone(), INC_FUNC_INDEX))
|
||||
}
|
||||
|
||||
fn resolve_memory(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_memory_type: &MemoryDescriptor,
|
||||
) -> Result<MemoryRef, Error> {
|
||||
fn resolve_memory(&self, field_name: &str, _memory_type: &MemoryDescriptor) -> Result<MemoryRef, Error> {
|
||||
if field_name == "mem" {
|
||||
Ok(self.mem.clone())
|
||||
} else {
|
||||
Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
Err(Error::Instantiation(format!("Export {} not found", field_name)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -522,11 +492,7 @@ fn defer_providing_externals() {
|
|||
}
|
||||
|
||||
impl<'a> Externals for HostExternals<'a> {
|
||||
fn invoke_index(
|
||||
&mut self,
|
||||
index: usize,
|
||||
args: RuntimeArgs,
|
||||
) -> Result<Option<RuntimeValue>, Trap> {
|
||||
fn invoke_index(&mut self, index: usize, args: RuntimeArgs) -> Result<Option<RuntimeValue>, Trap> {
|
||||
match index {
|
||||
INC_FUNC_INDEX => {
|
||||
let a = args.nth::<u32>(0);
|
||||
|
@ -569,12 +535,8 @@ fn defer_providing_externals() {
|
|||
{
|
||||
let mut host_externals = HostExternals { acc: &mut acc };
|
||||
|
||||
instance
|
||||
.invoke_export("test", &[], &mut host_externals)
|
||||
.unwrap(); // acc += 1;
|
||||
instance
|
||||
.invoke_export("test", &[], &mut host_externals)
|
||||
.unwrap(); // acc += 1;
|
||||
instance.invoke_export("test", &[], &mut host_externals).unwrap(); // acc += 1;
|
||||
instance.invoke_export("test", &[], &mut host_externals).unwrap(); // acc += 1;
|
||||
}
|
||||
assert_eq!(acc, 91);
|
||||
}
|
||||
|
@ -587,11 +549,7 @@ fn two_envs_one_externals() {
|
|||
struct HostExternals;
|
||||
|
||||
impl Externals for HostExternals {
|
||||
fn invoke_index(
|
||||
&mut self,
|
||||
index: usize,
|
||||
_args: RuntimeArgs,
|
||||
) -> Result<Option<RuntimeValue>, Trap> {
|
||||
fn invoke_index(&mut self, index: usize, _args: RuntimeArgs) -> Result<Option<RuntimeValue>, Trap> {
|
||||
match index {
|
||||
PRIVILEGED_FUNC_INDEX => {
|
||||
println!("privileged!");
|
||||
|
@ -611,12 +569,7 @@ fn two_envs_one_externals() {
|
|||
let index = match field_name {
|
||||
"ordinary" => ORDINARY_FUNC_INDEX,
|
||||
"privileged" => PRIVILEGED_FUNC_INDEX,
|
||||
_ => {
|
||||
return Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
}
|
||||
_ => return Err(Error::Instantiation(format!("Export {} not found", field_name))),
|
||||
};
|
||||
|
||||
Ok(FuncInstance::alloc_host(signature.clone(), index))
|
||||
|
@ -632,12 +585,7 @@ fn two_envs_one_externals() {
|
|||
"'priveleged' can be imported only in privileged context".into(),
|
||||
))
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
}
|
||||
_ => return Err(Error::Instantiation(format!("Export {} not found", field_name))),
|
||||
};
|
||||
|
||||
Ok(FuncInstance::alloc_host(signature.clone(), index))
|
||||
|
@ -701,11 +649,7 @@ fn dynamically_add_host_func() {
|
|||
}
|
||||
|
||||
impl Externals for HostExternals {
|
||||
fn invoke_index(
|
||||
&mut self,
|
||||
index: usize,
|
||||
_args: RuntimeArgs,
|
||||
) -> Result<Option<RuntimeValue>, Trap> {
|
||||
fn invoke_index(&mut self, index: usize, _args: RuntimeArgs) -> Result<Option<RuntimeValue>, Trap> {
|
||||
match index {
|
||||
ADD_FUNC_FUNC_INDEX => {
|
||||
// Allocate indicies for the new function.
|
||||
|
@ -724,9 +668,7 @@ fn dynamically_add_host_func() {
|
|||
|
||||
Ok(Some(RuntimeValue::I32(table_index as i32)))
|
||||
}
|
||||
index if index as u32 <= self.added_funcs => {
|
||||
Ok(Some(RuntimeValue::I32(index as i32)))
|
||||
}
|
||||
index if index as u32 <= self.added_funcs => Ok(Some(RuntimeValue::I32(index as i32))),
|
||||
_ => panic!("'env' module doesn't provide function at index {}", index),
|
||||
}
|
||||
}
|
||||
|
@ -736,28 +678,16 @@ fn dynamically_add_host_func() {
|
|||
fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result<FuncRef, Error> {
|
||||
let index = match field_name {
|
||||
"add_func" => ADD_FUNC_FUNC_INDEX,
|
||||
_ => {
|
||||
return Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
}
|
||||
_ => return Err(Error::Instantiation(format!("Export {} not found", field_name))),
|
||||
};
|
||||
Ok(FuncInstance::alloc_host(signature.clone(), index))
|
||||
}
|
||||
|
||||
fn resolve_table(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_table_type: &TableDescriptor,
|
||||
) -> Result<TableRef, Error> {
|
||||
fn resolve_table(&self, field_name: &str, _table_type: &TableDescriptor) -> Result<TableRef, Error> {
|
||||
if field_name == "table" {
|
||||
Ok(self.table.clone())
|
||||
} else {
|
||||
Err(Error::Instantiation(format!(
|
||||
"Export {} not found",
|
||||
field_name
|
||||
)))
|
||||
Err(Error::Instantiation(format!("Export {} not found", field_name)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -786,11 +716,9 @@ fn dynamically_add_host_func() {
|
|||
"#,
|
||||
);
|
||||
|
||||
let instance = ModuleInstance::new(
|
||||
&module,
|
||||
&ImportsBuilder::new().with_resolver("env", &host_externals),
|
||||
).expect("Failed to instantiate module")
|
||||
.assert_no_start();
|
||||
let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &host_externals))
|
||||
.expect("Failed to instantiate module")
|
||||
.assert_no_start();
|
||||
|
||||
assert_eq!(
|
||||
instance
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use memory_units::Pages;
|
||||
use std::fs::File;
|
||||
use {
|
||||
Error, FuncRef, GlobalDescriptor, GlobalInstance, GlobalRef, ImportsBuilder, MemoryDescriptor,
|
||||
MemoryInstance, MemoryRef, Module, ModuleImportResolver, ModuleInstance, NopExternals,
|
||||
RuntimeValue, Signature, TableDescriptor, TableInstance, TableRef,
|
||||
Error, FuncRef, GlobalDescriptor, GlobalInstance, GlobalRef, ImportsBuilder, MemoryDescriptor, MemoryInstance,
|
||||
MemoryRef, Module, ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue, Signature, TableDescriptor,
|
||||
TableInstance, TableRef,
|
||||
};
|
||||
|
||||
struct Env {
|
||||
|
@ -26,16 +26,10 @@ impl Env {
|
|||
|
||||
impl ModuleImportResolver for Env {
|
||||
fn resolve_func(&self, _field_name: &str, _func_type: &Signature) -> Result<FuncRef, Error> {
|
||||
Err(Error::Instantiation(
|
||||
"env module doesn't provide any functions".into(),
|
||||
))
|
||||
Err(Error::Instantiation("env module doesn't provide any functions".into()))
|
||||
}
|
||||
|
||||
fn resolve_global(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_global_type: &GlobalDescriptor,
|
||||
) -> Result<GlobalRef, Error> {
|
||||
fn resolve_global(&self, field_name: &str, _global_type: &GlobalDescriptor) -> Result<GlobalRef, Error> {
|
||||
match field_name {
|
||||
"tableBase" => Ok(self.table_base.clone()),
|
||||
"memoryBase" => Ok(self.memory_base.clone()),
|
||||
|
@ -46,11 +40,7 @@ impl ModuleImportResolver for Env {
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_memory(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_memory_type: &MemoryDescriptor,
|
||||
) -> Result<MemoryRef, Error> {
|
||||
fn resolve_memory(&self, field_name: &str, _memory_type: &MemoryDescriptor) -> Result<MemoryRef, Error> {
|
||||
match field_name {
|
||||
"memory" => Ok(self.memory.clone()),
|
||||
_ => Err(Error::Instantiation(format!(
|
||||
|
@ -60,11 +50,7 @@ impl ModuleImportResolver for Env {
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_table(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_table_type: &TableDescriptor,
|
||||
) -> Result<TableRef, Error> {
|
||||
fn resolve_table(&self, field_name: &str, _table_type: &TableDescriptor) -> Result<TableRef, Error> {
|
||||
match field_name {
|
||||
"table" => Ok(self.table.clone()),
|
||||
_ => Err(Error::Instantiation(format!(
|
||||
|
@ -134,10 +120,7 @@ fn interpreter_accumulate_u8() {
|
|||
let _ = env_memory.set(offset, BUF);
|
||||
|
||||
// Set up the function argument list and invoke the function
|
||||
let args = &[
|
||||
RuntimeValue::I32(BUF.len() as i32),
|
||||
RuntimeValue::I32(offset as i32),
|
||||
];
|
||||
let args = &[RuntimeValue::I32(BUF.len() as i32), RuntimeValue::I32(offset as i32)];
|
||||
let retval = instance
|
||||
.invoke_export(FUNCTION_NAME, args, &mut NopExternals)
|
||||
.expect("Failed to execute function");
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use alloc::borrow::Cow;
|
||||
|
||||
use parity_wasm::elements::{
|
||||
FunctionType, GlobalType, MemoryType, TableType, ValueType as EValueType,
|
||||
};
|
||||
use parity_wasm::elements::{FunctionType, GlobalType, MemoryType, TableType, ValueType as EValueType};
|
||||
|
||||
/// Signature of a [function].
|
||||
///
|
||||
|
@ -37,10 +35,7 @@ impl Signature {
|
|||
/// let dynamic_params = vec![ValueType::I64];
|
||||
/// let s3 = Signature::new(dynamic_params, None);
|
||||
/// ```
|
||||
pub fn new<C: Into<Cow<'static, [ValueType]>>>(
|
||||
params: C,
|
||||
return_type: Option<ValueType>,
|
||||
) -> Signature {
|
||||
pub fn new<C: Into<Cow<'static, [ValueType]>>>(params: C, return_type: Option<ValueType>) -> Signature {
|
||||
Signature {
|
||||
params: params.into(),
|
||||
return_type: return_type,
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#[allow(unused_imports)]
|
||||
use alloc::prelude::*;
|
||||
use parity_wasm::elements::{
|
||||
BlockType, FunctionType, GlobalType, MemoryType, TableType, ValueType,
|
||||
};
|
||||
use parity_wasm::elements::{BlockType, FunctionType, GlobalType, MemoryType, TableType, ValueType};
|
||||
use validation::Error;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
|
@ -63,10 +61,7 @@ impl ModuleContext {
|
|||
.ok_or_else(|| Error(format!("Type at index {} doesn't exists", idx)))?;
|
||||
|
||||
let params = ty.params();
|
||||
let return_ty = ty
|
||||
.return_type()
|
||||
.map(BlockType::Value)
|
||||
.unwrap_or(BlockType::NoResult);
|
||||
let return_ty = ty.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult);
|
||||
Ok((params, return_ty))
|
||||
}
|
||||
|
||||
|
|
|
@ -158,11 +158,7 @@ enum Outcome {
|
|||
pub struct FunctionReader;
|
||||
|
||||
impl FunctionReader {
|
||||
pub fn read_function(
|
||||
module: &ModuleContext,
|
||||
func: &Func,
|
||||
body: &FuncBody,
|
||||
) -> Result<isa::Instructions, Error> {
|
||||
pub fn read_function(module: &ModuleContext, func: &Func, body: &FuncBody) -> Result<isa::Instructions, Error> {
|
||||
let (params, result_ty) = module.require_function_type(func.type_ref())?;
|
||||
|
||||
let ins_size_estimate = body.code().elements().len();
|
||||
|
@ -190,10 +186,7 @@ impl FunctionReader {
|
|||
Ok(context.into_code())
|
||||
}
|
||||
|
||||
fn read_function_body(
|
||||
context: &mut FunctionValidationContext,
|
||||
body: &[Instruction],
|
||||
) -> Result<(), Error> {
|
||||
fn read_function_body(context: &mut FunctionValidationContext, body: &[Instruction]) -> Result<(), Error> {
|
||||
let body_len = body.len();
|
||||
if body_len == 0 {
|
||||
return Err(Error("Non-empty function body expected".into()));
|
||||
|
@ -202,19 +195,16 @@ impl FunctionReader {
|
|||
loop {
|
||||
let instruction = &body[context.position];
|
||||
|
||||
let outcome =
|
||||
FunctionReader::read_instruction(context, instruction).map_err(|err| {
|
||||
Error(format!(
|
||||
"At instruction {:?}(@{}): {}",
|
||||
instruction, context.position, err
|
||||
))
|
||||
})?;
|
||||
let outcome = FunctionReader::read_instruction(context, instruction).map_err(|err| {
|
||||
Error(format!(
|
||||
"At instruction {:?}(@{}): {}",
|
||||
instruction, context.position, err
|
||||
))
|
||||
})?;
|
||||
|
||||
match outcome {
|
||||
Outcome::NextInstruction => (),
|
||||
Outcome::Unreachable => {
|
||||
make_top_frame_polymorphic(&mut context.value_stack, &mut context.frame_stack)
|
||||
}
|
||||
Outcome::Unreachable => make_top_frame_polymorphic(&mut context.value_stack, &mut context.frame_stack),
|
||||
}
|
||||
|
||||
context.position += 1;
|
||||
|
@ -224,10 +214,7 @@ impl FunctionReader {
|
|||
}
|
||||
}
|
||||
|
||||
fn read_instruction(
|
||||
context: &mut FunctionValidationContext,
|
||||
instruction: &Instruction,
|
||||
) -> Result<Outcome, Error> {
|
||||
fn read_instruction(context: &mut FunctionValidationContext, instruction: &Instruction) -> Result<Outcome, Error> {
|
||||
use self::Instruction::*;
|
||||
match *instruction {
|
||||
// Nop instruction doesn't do anything. It is safe to just skip it.
|
||||
|
@ -267,11 +254,7 @@ impl FunctionReader {
|
|||
let if_not = context.sink.new_label();
|
||||
let end_label = context.sink.new_label();
|
||||
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
ValueType::I32.into(),
|
||||
)?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||
push_label(
|
||||
BlockFrameType::IfTrue { if_not, end_label },
|
||||
block_type,
|
||||
|
@ -334,9 +317,9 @@ impl FunctionReader {
|
|||
// A `if` without an `else` can't return a result.
|
||||
if block_type != BlockType::NoResult {
|
||||
return Err(Error(format!(
|
||||
"If block without else required to have NoResult block type. But it has {:?} type",
|
||||
block_type
|
||||
)));
|
||||
"If block without else required to have NoResult block type. But it has {:?} type",
|
||||
block_type
|
||||
)));
|
||||
}
|
||||
|
||||
// Resolve `if_not` label. If the `if's` condition doesn't hold the control will jump
|
||||
|
@ -356,19 +339,11 @@ impl FunctionReader {
|
|||
|
||||
// Check the return type.
|
||||
if let BlockType::Value(value_type) = context.return_type()? {
|
||||
tee_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
value_type.into(),
|
||||
)?;
|
||||
tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||
}
|
||||
|
||||
// Emit the return instruction.
|
||||
let drop_keep = drop_keep_return(
|
||||
&context.locals,
|
||||
&context.value_stack,
|
||||
&context.frame_stack,
|
||||
);
|
||||
let drop_keep = drop_keep_return(&context.locals, &context.value_stack, &context.frame_stack);
|
||||
context.sink.emit(isa::Instruction::Return(drop_keep));
|
||||
}
|
||||
|
||||
|
@ -401,23 +376,17 @@ impl FunctionReader {
|
|||
let target = require_target(*depth, &context.value_stack, &context.frame_stack);
|
||||
targets.push(target);
|
||||
}
|
||||
let default_target =
|
||||
require_target(default, &context.value_stack, &context.frame_stack);
|
||||
let default_target = require_target(default, &context.value_stack, &context.frame_stack);
|
||||
context.sink.emit_br_table(&targets, default_target);
|
||||
|
||||
return Ok(Outcome::Unreachable);
|
||||
}
|
||||
Return => {
|
||||
if let BlockType::Value(value_type) = context.return_type()? {
|
||||
tee_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
value_type.into(),
|
||||
)?;
|
||||
tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||
}
|
||||
|
||||
let drop_keep =
|
||||
drop_keep_return(&context.locals, &context.value_stack, &context.frame_stack);
|
||||
let drop_keep = drop_keep_return(&context.locals, &context.value_stack, &context.frame_stack);
|
||||
context.sink.emit(isa::Instruction::Return(drop_keep));
|
||||
|
||||
return Ok(Outcome::Unreachable);
|
||||
|
@ -1098,72 +1067,33 @@ impl FunctionReader {
|
|||
struct Validator;
|
||||
|
||||
impl Validator {
|
||||
fn validate_const(
|
||||
context: &mut FunctionValidationContext,
|
||||
value_type: ValueType,
|
||||
) -> Result<(), Error> {
|
||||
fn validate_const(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> {
|
||||
push_value(&mut context.value_stack, value_type.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_unop(
|
||||
context: &mut FunctionValidationContext,
|
||||
value_type: ValueType,
|
||||
) -> Result<(), Error> {
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
value_type.into(),
|
||||
)?;
|
||||
fn validate_unop(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> {
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||
push_value(&mut context.value_stack, value_type.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_binop(
|
||||
context: &mut FunctionValidationContext,
|
||||
value_type: ValueType,
|
||||
) -> Result<(), Error> {
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
value_type.into(),
|
||||
)?;
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
value_type.into(),
|
||||
)?;
|
||||
fn validate_binop(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> {
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||
push_value(&mut context.value_stack, value_type.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_testop(
|
||||
context: &mut FunctionValidationContext,
|
||||
value_type: ValueType,
|
||||
) -> Result<(), Error> {
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
value_type.into(),
|
||||
)?;
|
||||
fn validate_testop(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> {
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||
push_value(&mut context.value_stack, ValueType::I32.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_relop(
|
||||
context: &mut FunctionValidationContext,
|
||||
value_type: ValueType,
|
||||
) -> Result<(), Error> {
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
value_type.into(),
|
||||
)?;
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
value_type.into(),
|
||||
)?;
|
||||
fn validate_relop(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> {
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||
push_value(&mut context.value_stack, ValueType::I32.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1173,59 +1103,33 @@ impl Validator {
|
|||
value_type1: ValueType,
|
||||
value_type2: ValueType,
|
||||
) -> Result<(), Error> {
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
value_type1.into(),
|
||||
)?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, value_type1.into())?;
|
||||
push_value(&mut context.value_stack, value_type2.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_drop(context: &mut FunctionValidationContext) -> Result<(), Error> {
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
StackValueType::Any,
|
||||
)?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, StackValueType::Any)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_select(context: &mut FunctionValidationContext) -> Result<(), Error> {
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
ValueType::I32.into(),
|
||||
)?;
|
||||
let select_type = pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
StackValueType::Any,
|
||||
)?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||
let select_type = pop_value(&mut context.value_stack, &context.frame_stack, StackValueType::Any)?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, select_type)?;
|
||||
push_value(&mut context.value_stack, select_type)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_get_local(
|
||||
context: &mut FunctionValidationContext,
|
||||
index: u32,
|
||||
) -> Result<(), Error> {
|
||||
fn validate_get_local(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> {
|
||||
let local_type = require_local(&context.locals, index)?;
|
||||
push_value(&mut context.value_stack, local_type.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_set_local(
|
||||
context: &mut FunctionValidationContext,
|
||||
index: u32,
|
||||
) -> Result<(), Error> {
|
||||
fn validate_set_local(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> {
|
||||
let local_type = require_local(&context.locals, index)?;
|
||||
let value_type = pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
StackValueType::Any,
|
||||
)?;
|
||||
let value_type = pop_value(&mut context.value_stack, &context.frame_stack, StackValueType::Any)?;
|
||||
if StackValueType::from(local_type) != value_type {
|
||||
return Err(Error(format!(
|
||||
"Trying to update local {} of type {:?} with value of type {:?}",
|
||||
|
@ -1235,23 +1139,13 @@ impl Validator {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_tee_local(
|
||||
context: &mut FunctionValidationContext,
|
||||
index: u32,
|
||||
) -> Result<(), Error> {
|
||||
fn validate_tee_local(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> {
|
||||
let local_type = require_local(&context.locals, index)?;
|
||||
tee_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
local_type.into(),
|
||||
)?;
|
||||
tee_value(&mut context.value_stack, &context.frame_stack, local_type.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_get_global(
|
||||
context: &mut FunctionValidationContext,
|
||||
index: u32,
|
||||
) -> Result<(), Error> {
|
||||
fn validate_get_global(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> {
|
||||
let global_type: StackValueType = {
|
||||
let global = context.module.require_global(index, None)?;
|
||||
global.content_type().into()
|
||||
|
@ -1260,19 +1154,12 @@ impl Validator {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_set_global(
|
||||
context: &mut FunctionValidationContext,
|
||||
index: u32,
|
||||
) -> Result<(), Error> {
|
||||
fn validate_set_global(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> {
|
||||
let global_type: StackValueType = {
|
||||
let global = context.module.require_global(index, Some(true))?;
|
||||
global.content_type().into()
|
||||
};
|
||||
let value_type = pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
StackValueType::Any,
|
||||
)?;
|
||||
let value_type = pop_value(&mut context.value_stack, &context.frame_stack, StackValueType::Any)?;
|
||||
if global_type != value_type {
|
||||
return Err(Error(format!(
|
||||
"Trying to update global {} of type {:?} with value of type {:?}",
|
||||
|
@ -1295,11 +1182,7 @@ impl Validator {
|
|||
)));
|
||||
}
|
||||
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
ValueType::I32.into(),
|
||||
)?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||
context.module.require_memory(DEFAULT_MEMORY_INDEX)?;
|
||||
push_value(&mut context.value_stack, value_type.into())?;
|
||||
Ok(())
|
||||
|
@ -1319,16 +1202,8 @@ impl Validator {
|
|||
}
|
||||
|
||||
context.module.require_memory(DEFAULT_MEMORY_INDEX)?;
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
value_type.into(),
|
||||
)?;
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
ValueType::I32.into(),
|
||||
)?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1339,22 +1214,14 @@ impl Validator {
|
|||
};
|
||||
if !frame_type.is_loop() {
|
||||
if let BlockType::Value(value_type) = frame_block_type {
|
||||
tee_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
value_type.into(),
|
||||
)?;
|
||||
tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_br_if(context: &mut FunctionValidationContext, depth: u32) -> Result<(), Error> {
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
ValueType::I32.into(),
|
||||
)?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||
|
||||
let (frame_type, frame_block_type) = {
|
||||
let frame = require_label(depth, &context.frame_stack)?;
|
||||
|
@ -1362,21 +1229,13 @@ impl Validator {
|
|||
};
|
||||
if !frame_type.is_loop() {
|
||||
if let BlockType::Value(value_type) = frame_block_type {
|
||||
tee_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
value_type.into(),
|
||||
)?;
|
||||
tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_br_table(
|
||||
context: &mut FunctionValidationContext,
|
||||
table: &[u32],
|
||||
default: u32,
|
||||
) -> Result<(), Error> {
|
||||
fn validate_br_table(context: &mut FunctionValidationContext, table: &[u32], default: u32) -> Result<(), Error> {
|
||||
let required_block_type: BlockType = {
|
||||
let default_block = require_label(default, &context.frame_stack)?;
|
||||
let required_block_type = if !default_block.frame_type.is_loop() {
|
||||
|
@ -1402,17 +1261,9 @@ impl Validator {
|
|||
required_block_type
|
||||
};
|
||||
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
ValueType::I32.into(),
|
||||
)?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||
if let BlockType::Value(value_type) = required_block_type {
|
||||
tee_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
value_type.into(),
|
||||
)?;
|
||||
tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1421,11 +1272,7 @@ impl Validator {
|
|||
fn validate_call(context: &mut FunctionValidationContext, idx: u32) -> Result<(), Error> {
|
||||
let (argument_types, return_type) = context.module.require_function(idx)?;
|
||||
for argument_type in argument_types.iter().rev() {
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
(*argument_type).into(),
|
||||
)?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, (*argument_type).into())?;
|
||||
}
|
||||
if let BlockType::Value(value_type) = return_type {
|
||||
push_value(&mut context.value_stack, value_type.into())?;
|
||||
|
@ -1433,10 +1280,7 @@ impl Validator {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_call_indirect(
|
||||
context: &mut FunctionValidationContext,
|
||||
idx: u32,
|
||||
) -> Result<(), Error> {
|
||||
fn validate_call_indirect(context: &mut FunctionValidationContext, idx: u32) -> Result<(), Error> {
|
||||
{
|
||||
let table = context.module.require_table(DEFAULT_TABLE_INDEX)?;
|
||||
if table.elem_type() != TableElementType::AnyFunc {
|
||||
|
@ -1448,18 +1292,10 @@ impl Validator {
|
|||
}
|
||||
}
|
||||
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
ValueType::I32.into(),
|
||||
)?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||
let (argument_types, return_type) = context.module.require_function_type(idx)?;
|
||||
for argument_type in argument_types.iter().rev() {
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
(*argument_type).into(),
|
||||
)?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, (*argument_type).into())?;
|
||||
}
|
||||
if let BlockType::Value(value_type) = return_type {
|
||||
push_value(&mut context.value_stack, value_type.into())?;
|
||||
|
@ -1475,11 +1311,7 @@ impl Validator {
|
|||
|
||||
fn validate_grow_memory(context: &mut FunctionValidationContext) -> Result<(), Error> {
|
||||
context.module.require_memory(DEFAULT_MEMORY_INDEX)?;
|
||||
pop_value(
|
||||
&mut context.value_stack,
|
||||
&context.frame_stack,
|
||||
ValueType::I32.into(),
|
||||
)?;
|
||||
pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?;
|
||||
push_value(&mut context.value_stack, ValueType::I32.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1543,10 +1375,7 @@ fn make_top_frame_polymorphic(
|
|||
frame.polymorphic_stack = true;
|
||||
}
|
||||
|
||||
fn push_value(
|
||||
value_stack: &mut StackWithLimit<StackValueType>,
|
||||
value_type: StackValueType,
|
||||
) -> Result<(), Error> {
|
||||
fn push_value(value_stack: &mut StackWithLimit<StackValueType>, value_type: StackValueType) -> Result<(), Error> {
|
||||
Ok(value_stack.push(value_type.into())?)
|
||||
}
|
||||
|
||||
|
@ -1564,19 +1393,14 @@ fn pop_value(
|
|||
let actual_value = if stack_is_empty && is_stack_polymorphic {
|
||||
StackValueType::Any
|
||||
} else {
|
||||
let value_stack_min = frame_stack
|
||||
.top()
|
||||
.expect("at least 1 topmost block")
|
||||
.value_stack_len;
|
||||
let value_stack_min = frame_stack.top().expect("at least 1 topmost block").value_stack_len;
|
||||
if value_stack.len() <= value_stack_min {
|
||||
return Err(Error("Trying to access parent frame stack values.".into()));
|
||||
}
|
||||
value_stack.pop()?
|
||||
};
|
||||
match actual_value {
|
||||
StackValueType::Specific(stack_value_type) if stack_value_type == value_type => {
|
||||
Ok(actual_value)
|
||||
}
|
||||
StackValueType::Specific(stack_value_type) if stack_value_type == value_type => Ok(actual_value),
|
||||
StackValueType::Any => Ok(actual_value),
|
||||
stack_value_type @ _ => Err(Error(format!(
|
||||
"Expected value of type {:?} on top of stack. Got {:?}",
|
||||
|
@ -1623,11 +1447,7 @@ fn pop_label(
|
|||
match block_type {
|
||||
BlockType::NoResult => (),
|
||||
BlockType::Value(required_value_type) => {
|
||||
let _ = pop_value(
|
||||
value_stack,
|
||||
frame_stack,
|
||||
StackValueType::Specific(required_value_type),
|
||||
)?;
|
||||
let _ = pop_value(value_stack, frame_stack, StackValueType::Specific(required_value_type))?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1649,10 +1469,7 @@ fn top_label(frame_stack: &StackWithLimit<BlockFrame>) -> &BlockFrame {
|
|||
.expect("this function can't be called with empty frame stack")
|
||||
}
|
||||
|
||||
fn require_label(
|
||||
depth: u32,
|
||||
frame_stack: &StackWithLimit<BlockFrame>,
|
||||
) -> Result<&BlockFrame, Error> {
|
||||
fn require_label(depth: u32, frame_stack: &StackWithLimit<BlockFrame>) -> Result<&BlockFrame, Error> {
|
||||
Ok(frame_stack.get(depth as usize)?)
|
||||
}
|
||||
|
||||
|
@ -1662,8 +1479,7 @@ fn require_target(
|
|||
frame_stack: &StackWithLimit<BlockFrame>,
|
||||
) -> Target {
|
||||
let is_stack_polymorphic = top_label(frame_stack).polymorphic_stack;
|
||||
let frame =
|
||||
require_label(depth, frame_stack).expect("require_target called with a bogus depth");
|
||||
let frame = require_label(depth, frame_stack).expect("require_target called with a bogus depth");
|
||||
|
||||
// Find out how many values we need to keep (copy to the new stack location after the drop).
|
||||
let keep: isa::Keep = match (frame.frame_type, frame.block_type) {
|
||||
|
@ -1727,11 +1543,7 @@ fn require_local(locals: &Locals, idx: u32) -> Result<ValueType, Error> {
|
|||
}
|
||||
|
||||
/// See stack layout definition in mod isa.
|
||||
fn relative_local_depth(
|
||||
idx: u32,
|
||||
locals: &Locals,
|
||||
value_stack: &StackWithLimit<StackValueType>,
|
||||
) -> Result<u32, Error> {
|
||||
fn relative_local_depth(idx: u32, locals: &Locals, value_stack: &StackWithLimit<StackValueType>) -> Result<u32, Error> {
|
||||
let value_stack_height = value_stack.len() as u32;
|
||||
let locals_and_params_count = locals.count();
|
||||
|
||||
|
@ -1779,11 +1591,7 @@ impl Sink {
|
|||
self.ins.current_pc()
|
||||
}
|
||||
|
||||
fn pc_or_placeholder<F: FnOnce() -> isa::Reloc>(
|
||||
&mut self,
|
||||
label: LabelId,
|
||||
reloc_creator: F,
|
||||
) -> u32 {
|
||||
fn pc_or_placeholder<F: FnOnce() -> isa::Reloc>(&mut self, label: LabelId, reloc_creator: F) -> u32 {
|
||||
match self.labels[label.0] {
|
||||
(Label::Resolved(dst_pc), _) => dst_pc,
|
||||
(Label::NotResolved, ref mut unresolved) => {
|
||||
|
@ -1832,17 +1640,14 @@ impl Sink {
|
|||
|
||||
let pc = self.cur_pc();
|
||||
let mut isa_targets = Vec::new();
|
||||
for (idx, &Target { label, drop_keep }) in
|
||||
targets.iter().chain(iter::once(&default)).enumerate()
|
||||
{
|
||||
for (idx, &Target { label, drop_keep }) in targets.iter().chain(iter::once(&default)).enumerate() {
|
||||
let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::BrTable { pc, idx });
|
||||
isa_targets.push(isa::Target {
|
||||
dst_pc,
|
||||
drop_keep: drop_keep.into(),
|
||||
});
|
||||
}
|
||||
self.ins
|
||||
.push(isa::Instruction::BrTable(isa_targets.into_boxed_slice()));
|
||||
self.ins.push(isa::Instruction::BrTable(isa_targets.into_boxed_slice()));
|
||||
}
|
||||
|
||||
/// Create a new unresolved label.
|
||||
|
@ -1879,12 +1684,10 @@ impl Sink {
|
|||
// At this moment all labels should be resolved.
|
||||
assert!(
|
||||
{
|
||||
self.labels
|
||||
.iter()
|
||||
.all(|(state, unresolved)| match (state, unresolved) {
|
||||
(Label::Resolved(_), unresolved) if unresolved.is_empty() => true,
|
||||
_ => false,
|
||||
})
|
||||
self.labels.iter().all(|(state, unresolved)| match (state, unresolved) {
|
||||
(Label::Resolved(_), unresolved) if unresolved.is_empty() => true,
|
||||
_ => false,
|
||||
})
|
||||
},
|
||||
"there are unresolved labels left: {:?}",
|
||||
self.labels
|
||||
|
|
|
@ -15,8 +15,8 @@ use common::stack;
|
|||
use isa;
|
||||
use memory_units::Pages;
|
||||
use parity_wasm::elements::{
|
||||
BlockType, External, GlobalEntry, GlobalType, InitExpr, Instruction, Internal, MemoryType,
|
||||
Module, ResizableLimits, TableType, Type, ValueType,
|
||||
BlockType, External, GlobalEntry, GlobalType, InitExpr, Instruction, Internal, MemoryType, Module, ResizableLimits,
|
||||
TableType, Type, ValueType,
|
||||
};
|
||||
|
||||
mod context;
|
||||
|
@ -194,11 +194,7 @@ pub fn validate_module(module: Module) -> Result<ValidatedModule, Error> {
|
|||
);
|
||||
|
||||
// Fill elements with imported values.
|
||||
for import_entry in module
|
||||
.import_section()
|
||||
.map(|i| i.entries())
|
||||
.unwrap_or_default()
|
||||
{
|
||||
for import_entry in module.import_section().map(|i| i.entries()).unwrap_or_default() {
|
||||
match *import_entry.external() {
|
||||
External::Function(idx) => context_builder.push_func_type_index(idx),
|
||||
External::Table(ref table) => context_builder.push_table(table.clone()),
|
||||
|
@ -237,10 +233,7 @@ pub fn validate_module(module: Module) -> Result<ValidatedModule, Error> {
|
|||
|
||||
let context = context_builder.build();
|
||||
|
||||
let function_section_len = module
|
||||
.function_section()
|
||||
.map(|s| s.entries().len())
|
||||
.unwrap_or(0);
|
||||
let function_section_len = module.function_section().map(|s| s.entries().len()).unwrap_or(0);
|
||||
let code_section_len = module.code_section().map(|s| s.bodies().len()).unwrap_or(0);
|
||||
if function_section_len != code_section_len {
|
||||
return Err(Error(format!(
|
||||
|
@ -252,9 +245,7 @@ pub fn validate_module(module: Module) -> Result<ValidatedModule, Error> {
|
|||
// validate every function body in user modules
|
||||
if function_section_len != 0 {
|
||||
// tests use invalid code
|
||||
let function_section = module
|
||||
.function_section()
|
||||
.expect("function_section_len != 0; qed");
|
||||
let function_section = module.function_section().expect("function_section_len != 0; qed");
|
||||
let code_section = module
|
||||
.code_section()
|
||||
.expect("function_section_len != 0; function_section_len == code_section_len; qed");
|
||||
|
@ -264,14 +255,10 @@ pub fn validate_module(module: Module) -> Result<ValidatedModule, Error> {
|
|||
.bodies()
|
||||
.get(index as usize)
|
||||
.ok_or(Error(format!("Missing body for function {}", index)))?;
|
||||
let code =
|
||||
FunctionReader::read_function(&context, function, function_body).map_err(|e| {
|
||||
let Error(ref msg) = e;
|
||||
Error(format!(
|
||||
"Function #{} reading/validation error: {}",
|
||||
index, msg
|
||||
))
|
||||
})?;
|
||||
let code = FunctionReader::read_function(&context, function, function_body).map_err(|e| {
|
||||
let Error(ref msg) = e;
|
||||
Error(format!("Function #{} reading/validation error: {}", index, msg))
|
||||
})?;
|
||||
code_map.push(code);
|
||||
}
|
||||
}
|
||||
|
@ -280,9 +267,7 @@ pub fn validate_module(module: Module) -> Result<ValidatedModule, Error> {
|
|||
if let Some(start_fn_idx) = module.start_section() {
|
||||
let (params, return_ty) = context.require_function(start_fn_idx)?;
|
||||
if return_ty != BlockType::NoResult || params.len() != 0 {
|
||||
return Err(Error(
|
||||
"start function expected to have type [] -> []".into(),
|
||||
));
|
||||
return Err(Error("start function expected to have type [] -> []".into()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,10 +306,7 @@ pub fn validate_module(module: Module) -> Result<ValidatedModule, Error> {
|
|||
}
|
||||
External::Global(ref global_type) => {
|
||||
if global_type.is_mutable() {
|
||||
return Err(Error(format!(
|
||||
"trying to import mutable global {}",
|
||||
import.field()
|
||||
)));
|
||||
return Err(Error(format!("trying to import mutable global {}", import.field())));
|
||||
}
|
||||
}
|
||||
External::Memory(ref memory_type) => {
|
||||
|
@ -423,9 +405,7 @@ fn validate_global_entry(global_entry: &GlobalEntry, globals: &[GlobalType]) ->
|
|||
fn expr_const_type(init_expr: &InitExpr, globals: &[GlobalType]) -> Result<ValueType, Error> {
|
||||
let code = init_expr.code();
|
||||
if code.len() != 2 {
|
||||
return Err(Error(
|
||||
"Init expression should always be with length 2".into(),
|
||||
));
|
||||
return Err(Error("Init expression should always be with length 2".into()));
|
||||
}
|
||||
let expr_ty: ValueType = match code[0] {
|
||||
Instruction::I32Const(_) => ValueType::I32,
|
||||
|
@ -439,12 +419,7 @@ fn expr_const_type(init_expr: &InitExpr, globals: &[GlobalType]) -> Result<Value
|
|||
}
|
||||
target_global.content_type()
|
||||
}
|
||||
None => {
|
||||
return Err(Error(format!(
|
||||
"Global {} doesn't exists or not yet defined",
|
||||
idx
|
||||
)))
|
||||
}
|
||||
None => return Err(Error(format!("Global {} doesn't exists or not yet defined", idx))),
|
||||
},
|
||||
_ => return Err(Error("Non constant opcode in init expr".into())),
|
||||
};
|
||||
|
|
|
@ -2,8 +2,8 @@ use super::{validate_module, ValidatedModule};
|
|||
use isa;
|
||||
use parity_wasm::builder::module;
|
||||
use parity_wasm::elements::{
|
||||
deserialize_buffer, BlockType, External, GlobalEntry, GlobalType, ImportEntry, InitExpr,
|
||||
Instruction, Instructions, MemoryType, Module, TableType, ValueType,
|
||||
deserialize_buffer, BlockType, External, GlobalEntry, GlobalType, ImportEntry, InitExpr, Instruction, Instructions,
|
||||
MemoryType, Module, TableType, ValueType,
|
||||
};
|
||||
use wabt;
|
||||
|
||||
|
@ -39,12 +39,7 @@ fn limits() {
|
|||
assert_eq!(validate_module(m).is_ok(), is_valid);
|
||||
|
||||
// defined memory
|
||||
let m = module()
|
||||
.memory()
|
||||
.with_min(min)
|
||||
.with_max(max)
|
||||
.build()
|
||||
.build();
|
||||
let m = module().memory().with_min(min).with_max(max).build().build();
|
||||
assert_eq!(validate_module(m).is_ok(), is_valid);
|
||||
|
||||
// imported table
|
||||
|
@ -185,10 +180,8 @@ fn funcs() {
|
|||
.i32()
|
||||
.build()
|
||||
.body()
|
||||
.with_instructions(Instructions::new(vec![
|
||||
Instruction::Call(1),
|
||||
Instruction::End,
|
||||
])).build()
|
||||
.with_instructions(Instructions::new(vec![Instruction::Call(1), Instruction::End]))
|
||||
.build()
|
||||
.build()
|
||||
.function()
|
||||
.signature()
|
||||
|
@ -196,10 +189,8 @@ fn funcs() {
|
|||
.i32()
|
||||
.build()
|
||||
.body()
|
||||
.with_instructions(Instructions::new(vec![
|
||||
Instruction::Call(0),
|
||||
Instruction::End,
|
||||
])).build()
|
||||
.with_instructions(Instructions::new(vec![Instruction::Call(0), Instruction::End]))
|
||||
.build()
|
||||
.build()
|
||||
.build();
|
||||
assert!(validate_module(m).is_ok());
|
||||
|
|
|
@ -590,10 +590,7 @@ impl LittleEndianConvert for u8 {
|
|||
}
|
||||
|
||||
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
||||
buffer
|
||||
.get(0)
|
||||
.cloned()
|
||||
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
|
||||
buffer.get(0).cloned().ok_or_else(|| Error::InvalidLittleEndianBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,10 +6,9 @@ use std::fs::File;
|
|||
use wabt::script::{self, Action, Command, CommandKind, ScriptParser, Value};
|
||||
use wasmi::memory_units::Pages;
|
||||
use wasmi::{
|
||||
Error as InterpreterError, Externals, FuncInstance, FuncRef, GlobalDescriptor, GlobalInstance,
|
||||
GlobalRef, ImportResolver, ImportsBuilder, MemoryDescriptor, MemoryInstance, MemoryRef, Module,
|
||||
ModuleImportResolver, ModuleInstance, ModuleRef, RuntimeArgs, RuntimeValue, Signature,
|
||||
TableDescriptor, TableInstance, TableRef, Trap,
|
||||
Error as InterpreterError, Externals, FuncInstance, FuncRef, GlobalDescriptor, GlobalInstance, GlobalRef,
|
||||
ImportResolver, ImportsBuilder, MemoryDescriptor, MemoryInstance, MemoryRef, Module, ModuleImportResolver,
|
||||
ModuleInstance, ModuleRef, RuntimeArgs, RuntimeValue, Signature, TableDescriptor, TableInstance, TableRef, Trap,
|
||||
};
|
||||
|
||||
fn spec_to_runtime_value(val: Value<u32, u64>) -> RuntimeValue {
|
||||
|
@ -64,11 +63,7 @@ impl SpecModule {
|
|||
const PRINT_FUNC_INDEX: usize = 0;
|
||||
|
||||
impl Externals for SpecModule {
|
||||
fn invoke_index(
|
||||
&mut self,
|
||||
index: usize,
|
||||
args: RuntimeArgs,
|
||||
) -> Result<Option<RuntimeValue>, Trap> {
|
||||
fn invoke_index(&mut self, index: usize, args: RuntimeArgs) -> Result<Option<RuntimeValue>, Trap> {
|
||||
match index {
|
||||
PRINT_FUNC_INDEX => {
|
||||
println!("print: {:?}", args);
|
||||
|
@ -80,11 +75,7 @@ impl Externals for SpecModule {
|
|||
}
|
||||
|
||||
impl ModuleImportResolver for SpecModule {
|
||||
fn resolve_func(
|
||||
&self,
|
||||
field_name: &str,
|
||||
func_type: &Signature,
|
||||
) -> Result<FuncRef, InterpreterError> {
|
||||
fn resolve_func(&self, field_name: &str, func_type: &Signature) -> Result<FuncRef, InterpreterError> {
|
||||
let index = match field_name {
|
||||
"print" => PRINT_FUNC_INDEX,
|
||||
"print_i32" => PRINT_FUNC_INDEX,
|
||||
|
@ -110,11 +101,7 @@ impl ModuleImportResolver for SpecModule {
|
|||
return Ok(func);
|
||||
}
|
||||
|
||||
fn resolve_global(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_global_type: &GlobalDescriptor,
|
||||
) -> Result<GlobalRef, InterpreterError> {
|
||||
fn resolve_global(&self, field_name: &str, _global_type: &GlobalDescriptor) -> Result<GlobalRef, InterpreterError> {
|
||||
match field_name {
|
||||
"global_i32" => Ok(self.global_i32.clone()),
|
||||
"global_f32" => Ok(self.global_f32.clone()),
|
||||
|
@ -126,11 +113,7 @@ impl ModuleImportResolver for SpecModule {
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_memory(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_memory_type: &MemoryDescriptor,
|
||||
) -> Result<MemoryRef, InterpreterError> {
|
||||
fn resolve_memory(&self, field_name: &str, _memory_type: &MemoryDescriptor) -> Result<MemoryRef, InterpreterError> {
|
||||
if field_name == "memory" {
|
||||
return Ok(self.memory.clone());
|
||||
}
|
||||
|
@ -141,11 +124,7 @@ impl ModuleImportResolver for SpecModule {
|
|||
)))
|
||||
}
|
||||
|
||||
fn resolve_table(
|
||||
&self,
|
||||
field_name: &str,
|
||||
_table_type: &TableDescriptor,
|
||||
) -> Result<TableRef, InterpreterError> {
|
||||
fn resolve_table(&self, field_name: &str, _table_type: &TableDescriptor) -> Result<TableRef, InterpreterError> {
|
||||
if field_name == "table" {
|
||||
return Ok(self.table.clone());
|
||||
}
|
||||
|
@ -184,9 +163,10 @@ impl SpecDriver {
|
|||
}
|
||||
|
||||
fn module(&self, name: &str) -> Result<ModuleRef, InterpreterError> {
|
||||
self.instances.get(name).cloned().ok_or_else(|| {
|
||||
InterpreterError::Instantiation(format!("Module not registered {}", name))
|
||||
})
|
||||
self.instances
|
||||
.get(name)
|
||||
.cloned()
|
||||
.ok_or_else(|| InterpreterError::Instantiation(format!("Module not registered {}", name)))
|
||||
}
|
||||
|
||||
fn module_or_last(&self, name: Option<&str>) -> Result<ModuleRef, InterpreterError> {
|
||||
|
@ -210,8 +190,7 @@ impl ImportResolver for SpecDriver {
|
|||
if module_name == "spectest" {
|
||||
self.spec_module.resolve_func(field_name, func_type)
|
||||
} else {
|
||||
self.module(module_name)?
|
||||
.resolve_func(field_name, func_type)
|
||||
self.module(module_name)?.resolve_func(field_name, func_type)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,8 +203,7 @@ impl ImportResolver for SpecDriver {
|
|||
if module_name == "spectest" {
|
||||
self.spec_module.resolve_global(field_name, global_type)
|
||||
} else {
|
||||
self.module(module_name)?
|
||||
.resolve_global(field_name, global_type)
|
||||
self.module(module_name)?.resolve_global(field_name, global_type)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,8 +216,7 @@ impl ImportResolver for SpecDriver {
|
|||
if module_name == "spectest" {
|
||||
self.spec_module.resolve_memory(field_name, memory_type)
|
||||
} else {
|
||||
self.module(module_name)?
|
||||
.resolve_memory(field_name, memory_type)
|
||||
self.module(module_name)?.resolve_memory(field_name, memory_type)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,8 +229,7 @@ impl ImportResolver for SpecDriver {
|
|||
if module_name == "spectest" {
|
||||
self.spec_module.resolve_table(field_name, table_type)
|
||||
} else {
|
||||
self.module(module_name)?
|
||||
.resolve_table(field_name, table_type)
|
||||
self.module(module_name)?.resolve_table(field_name, table_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -271,11 +247,7 @@ fn try_load(wasm: &[u8], spec_driver: &mut SpecDriver) -> Result<(), Error> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn load_module(
|
||||
wasm: &[u8],
|
||||
name: &Option<String>,
|
||||
spec_driver: &mut SpecDriver,
|
||||
) -> Result<ModuleRef, Error> {
|
||||
fn load_module(wasm: &[u8], name: &Option<String>, spec_driver: &mut SpecDriver) -> Result<ModuleRef, Error> {
|
||||
let module = try_load_module(wasm)?;
|
||||
let instance = ModuleInstance::new(&module, spec_driver)
|
||||
.map_err(|e| Error::Load(e.to_string()))?
|
||||
|
@ -288,10 +260,7 @@ fn load_module(
|
|||
Ok(instance)
|
||||
}
|
||||
|
||||
fn run_action(
|
||||
program: &mut SpecDriver,
|
||||
action: &Action<u32, u64>,
|
||||
) -> Result<Option<RuntimeValue>, InterpreterError> {
|
||||
fn run_action(program: &mut SpecDriver, action: &Action<u32, u64>) -> Result<Option<RuntimeValue>, InterpreterError> {
|
||||
match *action {
|
||||
Action::Invoke {
|
||||
ref module,
|
||||
|
@ -300,37 +269,22 @@ fn run_action(
|
|||
} => {
|
||||
let module = program
|
||||
.module_or_last(module.as_ref().map(|x| x.as_ref()))
|
||||
.expect(&format!(
|
||||
"Expected program to have loaded module {:?}",
|
||||
module
|
||||
));
|
||||
let vec_args = args
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(spec_to_runtime_value)
|
||||
.collect::<Vec<_>>();
|
||||
.expect(&format!("Expected program to have loaded module {:?}", module));
|
||||
let vec_args = args.iter().cloned().map(spec_to_runtime_value).collect::<Vec<_>>();
|
||||
module.invoke_export(field, &vec_args, program.spec_module())
|
||||
}
|
||||
Action::Get {
|
||||
ref module,
|
||||
ref field,
|
||||
..
|
||||
ref module, ref field, ..
|
||||
} => {
|
||||
let module = program
|
||||
.module_or_last(module.as_ref().map(|x| x.as_ref()))
|
||||
.expect(&format!(
|
||||
"Expected program to have loaded module {:?}",
|
||||
module
|
||||
));
|
||||
.expect(&format!("Expected program to have loaded module {:?}", module));
|
||||
let global = module
|
||||
.export_by_name(&field)
|
||||
.ok_or_else(|| {
|
||||
InterpreterError::Global(format!("Expected to have export with name {}", field))
|
||||
})?.as_global()
|
||||
.ok_or_else(|| InterpreterError::Global(format!("Expected to have export with name {}", field)))?
|
||||
.as_global()
|
||||
.cloned()
|
||||
.ok_or_else(|| {
|
||||
InterpreterError::Global(format!("Expected export {} to be a global", field))
|
||||
})?;
|
||||
.ok_or_else(|| InterpreterError::Global(format!("Expected export {} to be a global", field)))?;
|
||||
Ok(Some(global.get()))
|
||||
}
|
||||
}
|
||||
|
@ -348,12 +302,10 @@ fn try_spec(name: &str) -> Result<(), Error> {
|
|||
use std::io::Read;
|
||||
let mut spec_source = Vec::new();
|
||||
let mut spec_file = File::open(&spec_script_path).expect("Can't open file");
|
||||
spec_file
|
||||
.read_to_end(&mut spec_source)
|
||||
.expect("Can't read file");
|
||||
spec_file.read_to_end(&mut spec_source).expect("Can't read file");
|
||||
|
||||
let mut parser = ScriptParser::from_source_and_name(&spec_source, &format!("{}.wast", name))
|
||||
.expect("Can't read spec script");
|
||||
let mut parser =
|
||||
ScriptParser::from_source_and_name(&spec_source, &format!("{}.wast", name)).expect("Can't read spec script");
|
||||
let mut errors = vec![];
|
||||
|
||||
while let Some(Command { kind, line }) = parser.next()? {
|
||||
|
@ -377,22 +329,15 @@ fn try_spec(name: &str) -> Result<(), Error> {
|
|||
|
||||
match kind {
|
||||
CommandKind::Module { name, module, .. } => {
|
||||
load_module(&module.into_vec(), &name, &mut spec_driver)
|
||||
.expect("Failed to load module");
|
||||
load_module(&module.into_vec(), &name, &mut spec_driver).expect("Failed to load module");
|
||||
}
|
||||
CommandKind::AssertReturn { action, expected } => {
|
||||
let result = run_action(&mut spec_driver, &action);
|
||||
match result {
|
||||
Ok(result) => {
|
||||
let spec_expected = expected
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(spec_to_runtime_value)
|
||||
.collect::<Vec<_>>();
|
||||
let spec_expected = expected.iter().cloned().map(spec_to_runtime_value).collect::<Vec<_>>();
|
||||
let actual_result = result.into_iter().collect::<Vec<RuntimeValue>>();
|
||||
for (actual_result, spec_expected) in
|
||||
actual_result.iter().zip(spec_expected.iter())
|
||||
{
|
||||
for (actual_result, spec_expected) in actual_result.iter().zip(spec_expected.iter()) {
|
||||
assert_eq!(actual_result.value_type(), spec_expected.value_type());
|
||||
// f32::NAN != f32::NAN
|
||||
match spec_expected {
|
||||
|
@ -413,8 +358,7 @@ fn try_spec(name: &str) -> Result<(), Error> {
|
|||
}
|
||||
}
|
||||
}
|
||||
CommandKind::AssertReturnCanonicalNan { action }
|
||||
| CommandKind::AssertReturnArithmeticNan { action } => {
|
||||
CommandKind::AssertReturnCanonicalNan { action } | CommandKind::AssertReturnArithmeticNan { action } => {
|
||||
let result = run_action(&mut spec_driver, &action);
|
||||
match result {
|
||||
Ok(result) => {
|
||||
|
@ -426,9 +370,7 @@ fn try_spec(name: &str) -> Result<(), Error> {
|
|||
RuntimeValue::F64(val) => if !val.is_nan() {
|
||||
panic!("Expected nan value, got {:?}", val)
|
||||
},
|
||||
val @ _ => {
|
||||
panic!("Expected action to return float value, got {:?}", val)
|
||||
}
|
||||
val @ _ => panic!("Expected action to return float value, got {:?}", val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -448,10 +390,7 @@ fn try_spec(name: &str) -> Result<(), Error> {
|
|||
let result = run_action(&mut spec_driver, &action);
|
||||
match result {
|
||||
Ok(result) => {
|
||||
panic!(
|
||||
"Expected action to result in a trap, got result: {:?}",
|
||||
result
|
||||
);
|
||||
panic!("Expected action to result in a trap, got result: {:?}", result);
|
||||
}
|
||||
Err(_e) => {}
|
||||
}
|
||||
|
@ -465,12 +404,10 @@ fn try_spec(name: &str) -> Result<(), Error> {
|
|||
Err(_e) => {}
|
||||
}
|
||||
}
|
||||
CommandKind::AssertUninstantiable { module, .. } => {
|
||||
match try_load(&module.into_vec(), &mut spec_driver) {
|
||||
Ok(_) => panic!("Expected error running start function at line {}", line),
|
||||
Err(_e) => {}
|
||||
}
|
||||
}
|
||||
CommandKind::AssertUninstantiable { module, .. } => match try_load(&module.into_vec(), &mut spec_driver) {
|
||||
Ok(_) => panic!("Expected error running start function at line {}", line),
|
||||
Err(_e) => {}
|
||||
},
|
||||
CommandKind::Register { name, as_name, .. } => {
|
||||
let module = match spec_driver.module_or_last(name.as_ref().map(|x| x.as_ref())) {
|
||||
Ok(module) => module,
|
||||
|
|
Loading…
Reference in New Issue