diff --git a/benches/build.rs b/benches/build.rs index 9cb9ac1..4977164 100644 --- a/benches/build.rs +++ b/benches/build.rs @@ -1,7 +1,6 @@ use std::env; use std::process; - fn main() { println!("cargo:rerun-if-changed=./wasm-kernel/"); @@ -23,9 +22,9 @@ fn main() { if !output.status.success() { let msg = format!( "status: {status}\nstdout: {stdout}\nstderr: {stderr}\n", - status=output.status, - stdout=String::from_utf8_lossy(&output.stdout), - stderr=String::from_utf8_lossy(&output.stderr), + status = output.status, + stdout = String::from_utf8_lossy(&output.stdout), + stderr = String::from_utf8_lossy(&output.stderr), ); panic!("{}", msg); } diff --git a/examples/interpret.rs b/examples/interpret.rs index 2be3018..d0e17cf 100644 --- a/examples/interpret.rs +++ b/examples/interpret.rs @@ -4,7 +4,7 @@ extern crate wasmi; use std::env::args; use std::fs::File; -use wasmi::{ModuleInstance, NopExternals, RuntimeValue, ImportsBuilder, Module}; +use wasmi::{ImportsBuilder, Module, ModuleInstance, NopExternals, RuntimeValue}; fn load_from_file(filename: &str) -> Module { use std::io::prelude::*; @@ -15,30 +15,33 @@ fn load_from_file(filename: &str) -> Module { } fn main() { - let args: Vec<_> = args().collect(); - if args.len() != 3 { - println!("Usage: {} ", args[0]); - println!(" wasm file should contain exported `_call` function with single I32 argument"); - return; - } + let args: Vec<_> = args().collect(); + if args.len() != 3 { + println!("Usage: {} ", args[0]); + println!(" wasm file should contain exported `_call` function with single I32 argument"); + return; + } - // Here we load module using dedicated for this purpose - // `load_from_file` function (which works only with modules) - let module = load_from_file(&args[1]); + // Here we load module using dedicated for this purpose + // `load_from_file` function (which works only with modules) + let module = load_from_file(&args[1]); - // Intialize deserialized module. It adds module into It expects 3 parameters: - // - a name for the module - // - a module declaration - // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here - // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 - let main = ModuleInstance::new(&module, &ImportsBuilder::default()) - .expect("Failed to instantiate module") - .run_start(&mut NopExternals) - .expect("Failed to run start function in module"); + // Intialize deserialized module. It adds module into It expects 3 parameters: + // - a name for the module + // - a module declaration + // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here + // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 + let main = ModuleInstance::new(&module, &ImportsBuilder::default()) + .expect("Failed to instantiate module") + .run_start(&mut NopExternals) + .expect("Failed to run start function in module"); - // The argument should be parsable as a valid integer - let argument: i32 = args[2].parse().expect("Integer argument required"); + // The argument should be parsable as a valid integer + let argument: i32 = args[2].parse().expect("Integer argument required"); - // "_call" export of function to be executed with an i32 argument and prints the result of execution - println!("Result: {:?}", main.invoke_export("_call", &[RuntimeValue::I32(argument)], &mut NopExternals)); + // "_call" export of function to be executed with an i32 argument and prints the result of execution + println!( + "Result: {:?}", + main.invoke_export("_call", &[RuntimeValue::I32(argument)], &mut NopExternals) + ); } diff --git a/examples/invoke.rs b/examples/invoke.rs index 2b7dd99..f7beb98 100644 --- a/examples/invoke.rs +++ b/examples/invoke.rs @@ -3,83 +3,116 @@ extern crate wasmi; use std::env::args; -use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType}; -use wasmi::{RuntimeValue, ModuleInstance, NopExternals, ImportsBuilder}; - +use parity_wasm::elements::{External, FunctionType, Internal, Type, ValueType}; +use wasmi::{ImportsBuilder, ModuleInstance, NopExternals, RuntimeValue}; fn main() { - let args: Vec<_> = args().collect(); - if args.len() < 3 { - println!("Usage: {} [...]", args[0]); - return; - } - let func_name = &args[2]; - let (_, program_args) = args.split_at(3); + let args: Vec<_> = args().collect(); + if args.len() < 3 { + println!("Usage: {} [...]", args[0]); + return; + } + let func_name = &args[2]; + let (_, program_args) = args.split_at(3); - let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized"); + let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized"); - // Extracts call arguments from command-line arguments - let args = { - // 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"); - // Type section stores function types which are referenced by function_section entries - let type_section = module.type_section().expect("No type section found"); + // Extracts call arguments from command-line arguments + let args = { + // 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"); + // Type section stores function types which are referenced by function_section entries + let type_section = module.type_section().expect("No type section found"); - // Given function name used to find export section entry which contains - // an `internal` field which points to the index in the function index space - let found_entry = export_section.entries().iter() - .find(|entry| func_name == entry.field()).expect(&format!("No export with name {} found", func_name)); + // Given function name used to find export section entry which contains + // an `internal` field which points to the index in the function index space + let found_entry = export_section + .entries() + .iter() + .find(|entry| func_name == entry.field()) + .expect(&format!("No export with name {} found", func_name)); - // Function index in the function index space (internally-defined + imported) - let function_index: usize = match found_entry.internal() { - &Internal::Function(index) => index as usize, - _ => panic!("Founded export is not a function"), - }; + // Function index in the function index space (internally-defined + imported) + let function_index: usize = match found_entry.internal() { + &Internal::Function(index) => index as usize, + _ => panic!("Founded export is not a function"), + }; - // We need to count import section entries (functions only!) to subtract it from function_index - // and obtain the index within the function section - let import_section_len: usize = match module.import_section() { - Some(import) => - import.entries().iter().filter(|entry| match entry.external() { - &External::Function(_) => true, - _ => false, - }).count(), - None => 0, - }; + // We need to count import section entries (functions only!) to subtract it from function_index + // and obtain the index within the function section + let import_section_len: usize = match module.import_section() { + Some(import) => import + .entries() + .iter() + .filter(|entry| match entry.external() { + &External::Function(_) => true, + _ => false, + }).count(), + None => 0, + }; - // Calculates a function index within module's function section - let function_index_in_section = function_index - import_section_len; + // Calculates a function index within module's function section + 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; + // 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; - // Use the reference to get an actual function type - let function_type: &FunctionType = match &type_section.types()[func_type_ref] { - &Type::Function(ref func_type) => func_type, - }; + // Use the reference to get an actual function type + let function_type: &FunctionType = match &type_section.types()[func_type_ref] { + &Type::Function(ref func_type) => func_type, + }; - // Parses arguments and constructs runtime values in correspondence of their types - function_type.params().iter().enumerate().map(|(i, value)| match value { - &ValueType::I32 => RuntimeValue::I32(program_args[i].parse::().expect(&format!("Can't parse arg #{} as i32", program_args[i]))), - &ValueType::I64 => RuntimeValue::I64(program_args[i].parse::().expect(&format!("Can't parse arg #{} as i64", program_args[i]))), - &ValueType::F32 => RuntimeValue::F32(program_args[i].parse::().expect(&format!("Can't parse arg #{} as f32", program_args[i])).into()), - &ValueType::F64 => RuntimeValue::F64(program_args[i].parse::().expect(&format!("Can't parse arg #{} as f64", program_args[i])).into()), - }).collect::>() - }; + // Parses arguments and constructs runtime values in correspondence of their types + function_type + .params() + .iter() + .enumerate() + .map(|(i, value)| match value { + &ValueType::I32 => RuntimeValue::I32( + program_args[i] + .parse::() + .expect(&format!("Can't parse arg #{} as i32", program_args[i])), + ), + &ValueType::I64 => RuntimeValue::I64( + program_args[i] + .parse::() + .expect(&format!("Can't parse arg #{} as i64", program_args[i])), + ), + &ValueType::F32 => RuntimeValue::F32( + program_args[i] + .parse::() + .expect(&format!("Can't parse arg #{} as f32", program_args[i])) + .into(), + ), + &ValueType::F64 => RuntimeValue::F64( + program_args[i] + .parse::() + .expect(&format!("Can't parse arg #{} as f64", program_args[i])) + .into(), + ), + }).collect::>() + }; - let loaded_module = wasmi::Module::from_parity_wasm_module(module).expect("Module to be valid"); + let loaded_module = wasmi::Module::from_parity_wasm_module(module).expect("Module to be valid"); - // Intialize deserialized module. It adds module into It expects 3 parameters: - // - a name for the module - // - a module declaration - // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here - // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 - let main = ModuleInstance::new(&loaded_module, &ImportsBuilder::default()) - .expect("Failed to instantiate module") - .run_start(&mut NopExternals) - .expect("Failed to run start function in module"); + // Intialize deserialized module. It adds module into It expects 3 parameters: + // - a name for the module + // - a module declaration + // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here + // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 + let main = ModuleInstance::new(&loaded_module, &ImportsBuilder::default()) + .expect("Failed to instantiate module") + .run_start(&mut NopExternals) + .expect("Failed to run start function in module"); - println!("Result: {:?}", main.invoke_export(func_name, &args, &mut NopExternals).expect("")); + println!( + "Result: {:?}", + main.invoke_export(func_name, &args, &mut NopExternals) + .expect("") + ); } diff --git a/examples/tictactoe.rs b/examples/tictactoe.rs index 86d7781..0223a6d 100644 --- a/examples/tictactoe.rs +++ b/examples/tictactoe.rs @@ -1,14 +1,13 @@ -extern crate wasmi; extern crate parity_wasm; +extern crate wasmi; use std::env; use std::fmt; use std::fs::File; use wasmi::{ - Error as InterpreterError, ModuleInstance, ModuleRef, - Externals, RuntimeValue, FuncRef, ModuleImportResolver, - FuncInstance, HostError, ImportsBuilder, Signature, ValueType, - RuntimeArgs, Trap, + Error as InterpreterError, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, + ModuleImportResolver, ModuleInstance, ModuleRef, RuntimeArgs, RuntimeValue, Signature, Trap, + ValueType, }; #[derive(Debug)] @@ -64,9 +63,7 @@ mod tictactoe { impl Game { pub fn new() -> Game { - Game { - board: [None; 9], - } + Game { board: [None; 9] } } pub fn set(&mut self, idx: i32, player: Player) -> Result<(), Error> { @@ -96,12 +93,10 @@ mod tictactoe { (0, 1, 2), (3, 4, 5), (6, 7, 8), - // Columns (0, 3, 6), (1, 4, 7), (2, 5, 8), - // Diagonals (0, 4, 8), (2, 4, 6), @@ -161,7 +156,7 @@ impl<'a> Externals for Runtime<'a> { let val: i32 = tictactoe::Player::into_i32(self.game.get(idx)?); Ok(Some(val.into())) } - _ => panic!("unknown function index") + _ => panic!("unknown function index"), } } } @@ -175,15 +170,20 @@ impl<'a> ModuleImportResolver for RuntimeModuleImportResolver { _signature: &Signature, ) -> Result { let func_ref = match field_name { - "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), - _ => return Err( - InterpreterError::Function( - format!("host module doesn't export function with name {}", field_name) - ) - ) + "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, + ), + _ => { + return Err(InterpreterError::Function(format!( + "host module doesn't export function with name {}", + field_name + ))) + } }; Ok(func_ref) } @@ -201,8 +201,7 @@ fn instantiate(path: &str) -> Result { let mut imports = ImportsBuilder::new(); imports.push_resolver("env", &RuntimeModuleImportResolver); - let instance = ModuleInstance::new(&module, &imports)? - .assert_no_start(); + let instance = ModuleInstance::new(&module, &imports)?.assert_no_start(); Ok(instance) } diff --git a/src/bin/instantiate.rs b/src/bin/instantiate.rs index e5042f9..6d92fc3 100644 --- a/src/bin/instantiate.rs +++ b/src/bin/instantiate.rs @@ -5,12 +5,12 @@ extern crate wasmi; use std::env::args; use std::fs::File; -use wasmi::{ - Error, FuncInstance, FuncRef, GlobalDescriptor, GlobalInstance, GlobalRef, - ImportsBuilder, MemoryDescriptor, MemoryInstance, MemoryRef, Module, - ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue, Signature, - TableDescriptor, TableInstance, TableRef}; 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, +}; fn load_from_file(filename: &str) -> Module { use std::io::prelude::*; @@ -76,6 +76,6 @@ fn main() { .with_resolver("asm2wasm", &ResolveAll) .with_resolver("spectest", &ResolveAll), ).expect("Failed to instantiate module") - .run_start(&mut NopExternals) - .expect("Failed to run start function in module"); + .run_start(&mut NopExternals) + .expect("Failed to run start function in module"); } diff --git a/src/common/mod.rs b/src/common/mod.rs index 49ff10c..6fdb382 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -1,4 +1,3 @@ - pub mod stack; /// Index of default linear memory. diff --git a/src/common/stack.rs b/src/common/stack.rs index a96af35..f3c1f60 100644 --- a/src/common/stack.rs +++ b/src/common/stack.rs @@ -1,9 +1,9 @@ #[allow(unused_imports)] use alloc::prelude::*; +use core::fmt; #[cfg(feature = "std")] use std::error; -use core::fmt; #[derive(Debug)] pub struct Error(String); @@ -23,18 +23,24 @@ impl error::Error for Error { /// Stack with limit. #[derive(Debug)] -pub struct StackWithLimit where T: Clone { +pub struct StackWithLimit +where + T: Clone, +{ /// Stack values. values: Vec, /// Stack limit (maximal stack len). limit: usize, } -impl StackWithLimit where T: Clone { +impl StackWithLimit +where + T: Clone, +{ pub fn with_limit(limit: usize) -> Self { StackWithLimit { values: Vec::new(), - limit: limit + limit: limit, } } @@ -60,10 +66,17 @@ impl StackWithLimit where T: Clone { pub fn get(&self, index: usize) -> Result<&T, Error> { if index >= self.values.len() { - return Err(Error(format!("trying to get value at position {} on stack of size {}", index, self.values.len()))); + return Err(Error(format!( + "trying to get value at position {} on stack of size {}", + index, + self.values.len() + ))); } - Ok(self.values.get(self.values.len() - 1 - index).expect("checked couple of lines above")) + Ok(self + .values + .get(self.values.len() - 1 - index) + .expect("checked couple of lines above")) } pub fn push(&mut self, value: T) -> Result<(), Error> { diff --git a/src/func.rs b/src/func.rs index 3df987f..3344d5c 100644 --- a/src/func.rs +++ b/src/func.rs @@ -2,14 +2,14 @@ use alloc::prelude::*; use alloc::rc::{Rc, Weak}; use core::fmt; -use parity_wasm::elements::Local; -use {Trap, Signature}; use host::Externals; -use runner::{check_function_args, Interpreter, InterpreterState}; -use value::RuntimeValue; -use types::ValueType; -use module::ModuleInstance; use isa; +use module::ModuleInstance; +use parity_wasm::elements::Local; +use runner::{check_function_args, Interpreter, InterpreterState}; +use types::ValueType; +use value::RuntimeValue; +use {Signature, Trap}; /// Reference to a function (See [`FuncInstance`] for details). /// @@ -58,17 +58,10 @@ pub(crate) enum FuncInstanceInternal { impl fmt::Debug for FuncInstance { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.as_internal() { - &FuncInstanceInternal::Internal { - ref signature, - .. - } => { + &FuncInstanceInternal::Internal { ref signature, .. } => { // We can't write description of self.module here, because it generate // debug string for function instances and this will lead to infinite loop. - write!( - f, - "Internal {{ signature={:?} }}", - signature, - ) + write!(f, "Internal {{ signature={:?} }}", signature,) } &FuncInstanceInternal::Host { ref signature, .. } => { write!(f, "Host {{ signature={:?} }}", signature) @@ -186,15 +179,13 @@ impl FuncInstance { FuncInstanceInternal::Host { ref host_func_index, .. - } => { - Ok(FuncInvocation { - kind: FuncInvocationKind::Host { - args, - host_func_index: *host_func_index, - finished: false, - }, - }) - }, + } => Ok(FuncInvocation { + kind: FuncInvocationKind::Host { + args, + host_func_index: *host_func_index, + finished: false, + }, + }), } } } @@ -239,7 +230,7 @@ enum FuncInvocationKind<'args> { Host { args: &'args [RuntimeValue], host_func_index: usize, - finished: bool + finished: bool, }, } @@ -255,32 +246,37 @@ impl<'args> FuncInvocation<'args> { /// If the invocation is resumable, the expected return value type to be feed back in. pub fn resumable_value_type(&self) -> Option { match &self.kind { - &FuncInvocationKind::Internal(ref interpreter) => { - match interpreter.state() { - &InterpreterState::Resumable(ref value_type) => value_type.clone(), - _ => None, - } + &FuncInvocationKind::Internal(ref interpreter) => match interpreter.state() { + &InterpreterState::Resumable(ref value_type) => value_type.clone(), + _ => None, }, &FuncInvocationKind::Host { .. } => None, } } /// Start the invocation execution. - pub fn start_execution<'externals, E: Externals + 'externals>(&mut self, externals: &'externals mut E) -> Result, ResumableError> { + pub fn start_execution<'externals, E: Externals + 'externals>( + &mut self, + externals: &'externals mut E, + ) -> Result, ResumableError> { match self.kind { FuncInvocationKind::Internal(ref mut interpreter) => { if interpreter.state() != &InterpreterState::Initialized { return Err(ResumableError::AlreadyStarted); } Ok(interpreter.start_execution(externals)?) - }, - FuncInvocationKind::Host { ref args, ref mut finished, ref host_func_index } => { + } + FuncInvocationKind::Host { + ref args, + ref mut finished, + ref host_func_index, + } => { if *finished { return Err(ResumableError::AlreadyStarted); } *finished = true; Ok(externals.invoke_index(*host_func_index, args.clone().into())?) - }, + } } } @@ -292,17 +288,21 @@ impl<'args> FuncInvocation<'args> { /// /// [`resumable_value_type`]: #method.resumable_value_type /// [`is_resumable`]: #method.is_resumable - pub fn resume_execution<'externals, E: Externals + 'externals>(&mut self, return_val: Option, externals: &'externals mut E) -> Result, ResumableError> { + pub fn resume_execution<'externals, E: Externals + 'externals>( + &mut self, + return_val: Option, + externals: &'externals mut E, + ) -> Result, ResumableError> { match self.kind { FuncInvocationKind::Internal(ref mut interpreter) => { if !interpreter.state().is_resumable() { return Err(ResumableError::AlreadyStarted); } Ok(interpreter.resume_execution(return_val, externals)?) - }, + } FuncInvocationKind::Host { .. } => { return Err(ResumableError::NotResumable); - }, + } } } } diff --git a/src/global.rs b/src/global.rs index fe7e276..9d408c6 100644 --- a/src/global.rs +++ b/src/global.rs @@ -1,9 +1,9 @@ use alloc::rc::Rc; use core::cell::Cell; +use parity_wasm::elements::ValueType as EValueType; +use types::ValueType; use value::RuntimeValue; use Error; -use types::ValueType; -use parity_wasm::elements::{ValueType as EValueType}; /// Reference to a global variable (See [`GlobalInstance`] for details). /// @@ -57,7 +57,9 @@ 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())); diff --git a/src/host.rs b/src/host.rs index 745f207..0501389 100644 --- a/src/host.rs +++ b/src/host.rs @@ -1,6 +1,6 @@ use core::any::TypeId; -use value::{RuntimeValue, FromRuntimeValue}; -use {TrapKind, Trap}; +use value::{FromRuntimeValue, RuntimeValue}; +use {Trap, TrapKind}; /// Wrapper around slice of [`RuntimeValue`] for using it /// as an argument list conveniently. @@ -27,8 +27,14 @@ impl<'a> RuntimeArgs<'a> { /// # Errors /// /// Returns `Err` if cast is invalid or not enough arguments. - pub fn nth_checked(&self, idx: usize) -> Result where T: FromRuntimeValue { - Ok(self.nth_value_checked(idx)?.try_into().ok_or_else(|| TrapKind::UnexpectedSignature)?) + pub fn nth_checked(&self, idx: usize) -> Result + where + T: FromRuntimeValue, + { + Ok(self + .nth_value_checked(idx)? + .try_into() + .ok_or_else(|| TrapKind::UnexpectedSignature)?) } /// Extract argument as a [`RuntimeValue`] by index `idx`. @@ -50,7 +56,10 @@ impl<'a> RuntimeArgs<'a> { /// # Panics /// /// Panics if cast is invalid or not enough arguments. - pub fn nth(&self, idx: usize) -> T where T: FromRuntimeValue { + pub fn nth(&self, idx: usize) -> T + where + T: FromRuntimeValue, + { let value = self.nth_value_checked(idx).expect("Invalid argument index"); value.try_into().expect("Unexpected argument type") } @@ -225,8 +234,8 @@ impl Externals for NopExternals { #[cfg(test)] mod tests { + use super::{HostError, RuntimeArgs}; use value::RuntimeValue; - use super::{RuntimeArgs, HostError}; #[test] fn i32_runtime_args() { @@ -242,6 +251,5 @@ mod tests { } // Tests that `HostError` trait is object safe. - fn _host_error_is_object_safe(_: &HostError) { - } + fn _host_error_is_object_safe(_: &HostError) {} } diff --git a/src/imports.rs b/src/imports.rs index bb52eb4..fce2906 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -1,20 +1,19 @@ #[allow(unused_imports)] use alloc::prelude::*; -#[cfg(feature = "std")] -use std::collections::HashMap; #[cfg(not(feature = "std"))] use hashmap_core::HashMap; +#[cfg(feature = "std")] +use std::collections::HashMap; +use func::FuncRef; use global::GlobalRef; use memory::MemoryRef; -use func::FuncRef; -use table::TableRef; use module::ModuleRef; -use types::{GlobalDescriptor, TableDescriptor, MemoryDescriptor}; +use table::TableRef; +use types::{GlobalDescriptor, MemoryDescriptor, TableDescriptor}; use {Error, Signature}; - /// Resolver of a module's dependencies. /// /// A module have dependencies in a form of a list of imports (i.e. @@ -27,7 +26,6 @@ use {Error, Signature}; /// /// [`ImportsBuilder`]: struct.ImportsBuilder.html pub trait ImportResolver { - /// Resolve a function. /// /// Returned function should match given `signature`, i.e. all parameter types and return value should have exact match. @@ -120,7 +118,9 @@ impl<'a> Default for ImportsBuilder<'a> { impl<'a> ImportsBuilder<'a> { /// Create an empty `ImportsBuilder`. pub fn new() -> ImportsBuilder<'a> { - ImportsBuilder { modules: HashMap::new() } + ImportsBuilder { + modules: HashMap::new(), + } } /// Register an resolver by a name. @@ -152,9 +152,9 @@ impl<'a> ImportResolver for ImportsBuilder<'a> { field_name: &str, signature: &Signature, ) -> Result { - self.resolver(module_name).ok_or_else(|| - Error::Instantiation(format!("Module {} not found", module_name)) - )?.resolve_func(field_name, signature) + self.resolver(module_name) + .ok_or_else(|| Error::Instantiation(format!("Module {} not found", module_name)))? + .resolve_func(field_name, signature) } fn resolve_global( @@ -163,9 +163,9 @@ impl<'a> ImportResolver for ImportsBuilder<'a> { field_name: &str, global_type: &GlobalDescriptor, ) -> Result { - self.resolver(module_name).ok_or_else(|| - Error::Instantiation(format!("Module {} not found", module_name)) - )?.resolve_global(field_name, global_type) + self.resolver(module_name) + .ok_or_else(|| Error::Instantiation(format!("Module {} not found", module_name)))? + .resolve_global(field_name, global_type) } fn resolve_memory( @@ -174,9 +174,9 @@ impl<'a> ImportResolver for ImportsBuilder<'a> { field_name: &str, memory_type: &MemoryDescriptor, ) -> Result { - self.resolver(module_name).ok_or_else(|| - Error::Instantiation(format!("Module {} not found", module_name)) - )?.resolve_memory(field_name, memory_type) + self.resolver(module_name) + .ok_or_else(|| Error::Instantiation(format!("Module {} not found", module_name)))? + .resolve_memory(field_name, memory_type) } fn resolve_table( @@ -185,9 +185,9 @@ impl<'a> ImportResolver for ImportsBuilder<'a> { field_name: &str, table_type: &TableDescriptor, ) -> Result { - self.resolver(module_name).ok_or_else(|| - Error::Instantiation(format!("Module {} not found", module_name)) - )?.resolve_table(field_name, table_type) + self.resolver(module_name) + .ok_or_else(|| Error::Instantiation(format!("Module {} not found", module_name)))? + .resolve_table(field_name, table_type) } } @@ -200,14 +200,11 @@ pub trait ModuleImportResolver { /// See [`ImportResolver::resolve_func`] for details. /// /// [`ImportResolver::resolve_func`]: trait.ImportResolver.html#tymethod.resolve_func - fn resolve_func( - &self, - field_name: &str, - _signature: &Signature, - ) -> Result { - Err(Error::Instantiation( - format!("Export {} not found", field_name), - )) + fn resolve_func(&self, field_name: &str, _signature: &Signature) -> Result { + Err(Error::Instantiation(format!( + "Export {} not found", + field_name + ))) } /// Resolve a global variable. @@ -220,9 +217,10 @@ pub trait ModuleImportResolver { field_name: &str, _global_type: &GlobalDescriptor, ) -> Result { - Err(Error::Instantiation( - format!("Export {} not found", field_name), - )) + Err(Error::Instantiation(format!( + "Export {} not found", + field_name + ))) } /// Resolve a memory. @@ -235,9 +233,10 @@ pub trait ModuleImportResolver { field_name: &str, _memory_type: &MemoryDescriptor, ) -> Result { - Err(Error::Instantiation( - format!("Export {} not found", field_name), - )) + Err(Error::Instantiation(format!( + "Export {} not found", + field_name + ))) } /// Resolve a table. @@ -250,22 +249,18 @@ pub trait ModuleImportResolver { field_name: &str, _table_type: &TableDescriptor, ) -> Result { - Err(Error::Instantiation( - format!("Export {} not found", field_name), - )) + Err(Error::Instantiation(format!( + "Export {} not found", + field_name + ))) } } impl ModuleImportResolver for ModuleRef { - fn resolve_func( - &self, - field_name: &str, - _signature: &Signature, - ) -> Result { - Ok(self.export_by_name(field_name) - .ok_or_else(|| { - Error::Instantiation(format!("Export {} not found", field_name)) - })? + fn resolve_func(&self, field_name: &str, _signature: &Signature) -> Result { + Ok(self + .export_by_name(field_name) + .ok_or_else(|| Error::Instantiation(format!("Export {} not found", field_name)))? .as_func() .cloned() .ok_or_else(|| { @@ -278,10 +273,9 @@ impl ModuleImportResolver for ModuleRef { field_name: &str, _global_type: &GlobalDescriptor, ) -> Result { - Ok(self.export_by_name(field_name) - .ok_or_else(|| { - Error::Instantiation(format!("Export {} not found", field_name)) - })? + Ok(self + .export_by_name(field_name) + .ok_or_else(|| Error::Instantiation(format!("Export {} not found", field_name)))? .as_global() .cloned() .ok_or_else(|| { @@ -294,10 +288,9 @@ impl ModuleImportResolver for ModuleRef { field_name: &str, _memory_type: &MemoryDescriptor, ) -> Result { - Ok(self.export_by_name(field_name) - .ok_or_else(|| { - Error::Instantiation(format!("Export {} not found", field_name)) - })? + Ok(self + .export_by_name(field_name) + .ok_or_else(|| Error::Instantiation(format!("Export {} not found", field_name)))? .as_memory() .cloned() .ok_or_else(|| { @@ -310,14 +303,11 @@ impl ModuleImportResolver for ModuleRef { field_name: &str, _table_type: &TableDescriptor, ) -> Result { - Ok(self.export_by_name(field_name) - .ok_or_else(|| { - Error::Instantiation(format!("Export {} not found", field_name)) - })? + Ok(self + .export_by_name(field_name) + .ok_or_else(|| Error::Instantiation(format!("Export {} not found", field_name)))? .as_table() .cloned() - .ok_or_else(|| { - Error::Instantiation(format!("Export {} is not a table", field_name)) - })?) + .ok_or_else(|| Error::Instantiation(format!("Export {} is not a table", field_name)))?) } } diff --git a/src/isa.rs b/src/isa.rs index b188843..e9a7caf 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -101,15 +101,10 @@ pub struct Target { pub enum Reloc { /// Patch the destination of the branch instruction (br, br_eqz, br_nez) /// at the specified pc. - Br { - pc: u32, - }, + Br { pc: u32 }, /// Patch the specified destination index inside of br_table instruction at /// the specified pc. - BrTable { - pc: u32, - idx: usize, - }, + BrTable { pc: u32, idx: usize }, } #[derive(Debug, Clone, PartialEq)] @@ -347,12 +342,12 @@ impl Instructions { Reloc::BrTable { pc, idx } => match self.vec[pc as usize] { Instruction::BrTable(ref mut targets) => targets[idx].dst_pc = dst_pc, _ => panic!("brtable relocation points to not brtable instruction"), - } + }, } } pub fn iterate_from(&self, position: u32) -> InstructionIter { - InstructionIter{ + InstructionIter { instructions: &self.vec, position, } @@ -376,9 +371,11 @@ impl<'a> Iterator for InstructionIter<'a> { #[inline] fn next(&mut self) -> Option<::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 + }) } } diff --git a/src/lib.rs b/src/lib.rs index eeb72e7..64c0bbb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -95,9 +95,7 @@ //! ``` #![warn(missing_docs)] - #![cfg_attr(not(feature = "std"), no_std)] - //// alloc is required in no_std #![cfg_attr(not(feature = "std"), feature(alloc))] @@ -117,11 +115,11 @@ extern crate wabt; #[macro_use] extern crate assert_matches; -extern crate parity_wasm; extern crate byteorder; #[cfg(not(feature = "std"))] extern crate hashmap_core; extern crate memory_units as memory_units_crate; +extern crate parity_wasm; #[allow(unused_imports)] use alloc::prelude::*; @@ -292,7 +290,7 @@ impl Error { Error::Trap(ref trap) => match *trap.kind() { TrapKind::Host(ref host_err) => Some(&**host_err), _ => None, - } + }, _ => None, } } @@ -347,13 +345,19 @@ impl error::Error for Error { } } -impl From for Error where U: host::HostError + Sized { +impl From for Error +where + U: host::HostError + Sized, +{ fn from(e: U) -> Self { Error::Host(Box::new(e)) } } -impl From for Trap where U: host::HostError + Sized { +impl From for Trap +where + U: host::HostError + Sized, +{ fn from(e: U) -> Self { Trap::new(TrapKind::Host(Box::new(e))) } @@ -377,38 +381,38 @@ impl From for Error { } } -mod validation; mod common; -mod memory; -mod module; -mod runner; -mod table; -mod value; +mod func; +mod global; mod host; mod imports; -mod global; -mod func; -mod types; mod isa; +mod memory; +mod module; pub mod nan_preserving_float; +mod runner; +mod table; +mod types; +mod validation; +mod value; #[cfg(test)] mod tests; -pub use self::memory::{MemoryInstance, MemoryRef, LINEAR_MEMORY_PAGE_SIZE}; -pub use self::table::{TableInstance, TableRef}; -pub use self::value::{RuntimeValue, FromRuntimeValue}; -pub use self::host::{Externals, NopExternals, HostError, RuntimeArgs}; -pub use self::imports::{ModuleImportResolver, ImportResolver, ImportsBuilder}; -pub use self::module::{ModuleInstance, ModuleRef, ExternVal, NotStartedModuleRef}; +pub use self::func::{FuncInstance, FuncInvocation, FuncRef, ResumableError}; pub use self::global::{GlobalInstance, GlobalRef}; -pub use self::func::{FuncInstance, FuncRef, FuncInvocation, ResumableError}; -pub use self::types::{Signature, ValueType, GlobalDescriptor, TableDescriptor, MemoryDescriptor}; +pub use self::host::{Externals, HostError, NopExternals, RuntimeArgs}; +pub use self::imports::{ImportResolver, ImportsBuilder, ModuleImportResolver}; +pub use self::memory::{MemoryInstance, MemoryRef, LINEAR_MEMORY_PAGE_SIZE}; +pub use self::module::{ExternVal, ModuleInstance, ModuleRef, NotStartedModuleRef}; +pub use self::table::{TableInstance, TableRef}; +pub use self::types::{GlobalDescriptor, MemoryDescriptor, Signature, TableDescriptor, ValueType}; +pub use self::value::{FromRuntimeValue, RuntimeValue}; /// WebAssembly-specific sizes and units. pub mod memory_units { pub use memory_units_crate::wasm32::*; - pub use memory_units_crate::{Bytes, ByteSize, RoundUpTo, size_of}; + pub use memory_units_crate::{size_of, ByteSize, Bytes, RoundUpTo}; } /// Deserialized module prepared for instantiation. @@ -452,15 +456,9 @@ impl Module { /// ``` pub fn from_parity_wasm_module(module: parity_wasm::elements::Module) -> Result { use validation::{validate_module, ValidatedModule}; - let ValidatedModule { - code_map, - module, - } = validate_module(module)?; + let ValidatedModule { code_map, module } = validate_module(module)?; - Ok(Module { - code_map, - module, - }) + Ok(Module { code_map, module }) } /// Fail if the module contains any floating-point operations diff --git a/src/memory.rs b/src/memory.rs index c25f335..82fabca 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,15 +1,15 @@ #[allow(unused_imports)] use alloc::prelude::*; use alloc::rc::Rc; -use core::u32; -use core::ops::Range; +use core::cell::{Cell, RefCell}; use core::cmp; use core::fmt; -use core::cell::{Cell, RefCell}; +use core::ops::Range; +use core::u32; +use memory_units::{Bytes, Pages, RoundUpTo}; use parity_wasm::elements::ResizableLimits; -use Error; -use memory_units::{RoundUpTo, Pages, Bytes}; use value::LittleEndianConvert; +use Error; /// Size of a page of [linear memory][`MemoryInstance`] - 64KiB. /// @@ -78,7 +78,7 @@ struct CheckedRegion { impl CheckedRegion { fn range(&self) -> Range { - self.offset..self.offset+self.size + self.offset..self.offset + self.size } fn intersects(&self, other: &Self) -> bool { @@ -174,7 +174,8 @@ impl MemoryInstance { /// Get value from memory at given offset. pub fn get_value(&self, offset: u32) -> Result { let mut buffer = self.buffer.borrow_mut(); - let region = self.checked_region(&mut buffer, offset as usize, ::core::mem::size_of::())?; + let region = + self.checked_region(&mut buffer, offset as usize, ::core::mem::size_of::())?; Ok(T::from_little_endian(&buffer[region.range()]).expect("Slice size is checked")) } @@ -208,7 +209,9 @@ 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); @@ -218,7 +221,9 @@ impl MemoryInstance { /// Copy value in the memory at given offset. pub fn set_value(&self, offset: u32, value: T) -> Result<(), Error> { let mut buffer = self.buffer.borrow_mut(); - let range = self.checked_region(&mut buffer, offset as usize, ::core::mem::size_of::())?.range(); + let range = self + .checked_region(&mut buffer, offset as usize, ::core::mem::size_of::())? + .range(); value.into_little_endian(&mut buffer[range]); Ok(()) } @@ -255,18 +260,33 @@ impl MemoryInstance { Ok(size_before_grow) } - fn checked_region(&self, buffer: &mut B, offset: usize, size: usize) -> Result - where B: ::core::ops::DerefMut> + fn checked_region( + &self, + buffer: &mut B, + offset: usize, + size: usize, + ) -> Result + where + B: ::core::ops::DerefMut>, { - let end = offset.checked_add(size) - .ok_or_else(|| Error::Memory(format!("trying to access memory block of size {} from offset {}", size, offset)))?; + let end = offset.checked_add(size).ok_or_else(|| { + Error::Memory(format!( + "trying to access memory block of size {} from offset {}", + size, offset + )) + })?; if end <= self.current_size.get() && buffer.len() < end { buffer.resize(end, 0); } if end > buffer.len() { - return Err(Error::Memory(format!("trying to access region [{}..{}] in memory [0..{}]", offset, end, buffer.len()))); + return Err(Error::Memory(format!( + "trying to access region [{}..{}] in memory [0..{}]", + offset, + end, + buffer.len() + ))); } Ok(CheckedRegion { @@ -275,15 +295,30 @@ impl MemoryInstance { }) } - fn checked_region_pair(&self, buffer: &mut B, offset1: usize, size1: usize, offset2: usize, size2: usize) - -> Result<(CheckedRegion, CheckedRegion), Error> - where B: ::core::ops::DerefMut> + fn checked_region_pair( + &self, + buffer: &mut B, + offset1: usize, + size1: usize, + offset2: usize, + size2: usize, + ) -> Result<(CheckedRegion, CheckedRegion), Error> + where + B: ::core::ops::DerefMut>, { - let end1 = offset1.checked_add(size1) - .ok_or_else(|| Error::Memory(format!("trying to access memory block of size {} from offset {}", size1, offset1)))?; + let end1 = offset1.checked_add(size1).ok_or_else(|| { + Error::Memory(format!( + "trying to access memory block of size {} from offset {}", + size1, offset1 + )) + })?; - let end2 = offset2.checked_add(size2) - .ok_or_else(|| Error::Memory(format!("trying to access memory block of size {} from offset {}", size2, offset2)))?; + let end2 = offset2.checked_add(size2).ok_or_else(|| { + Error::Memory(format!( + "trying to access memory block of size {} from offset {}", + size2, offset2 + )) + })?; let max = cmp::max(end1, end2); if max <= self.current_size.get() && buffer.len() < max { @@ -291,16 +326,32 @@ impl MemoryInstance { } if end1 > buffer.len() { - return Err(Error::Memory(format!("trying to access region [{}..{}] in memory [0..{}]", offset1, end1, buffer.len()))); + return Err(Error::Memory(format!( + "trying to access region [{}..{}] in memory [0..{}]", + offset1, + end1, + buffer.len() + ))); } if end2 > buffer.len() { - return Err(Error::Memory(format!("trying to access region [{}..{}] in memory [0..{}]", offset2, end2, buffer.len()))); + return Err(Error::Memory(format!( + "trying to access region [{}..{}] in memory [0..{}]", + offset2, + end2, + buffer.len() + ))); } Ok(( - CheckedRegion { offset: offset1, size: size1 }, - CheckedRegion { offset: offset2, size: size2 }, + CheckedRegion { + offset: offset1, + size: size1, + }, + CheckedRegion { + offset: offset2, + size: size2, + }, )) } @@ -314,13 +365,16 @@ 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( - buffer[read_region.range()].as_ptr(), - buffer[write_region.range()].as_mut_ptr(), - len, - )} + unsafe { + ::core::ptr::copy( + buffer[read_region.range()].as_ptr(), + buffer[write_region.range()].as_mut_ptr(), + len, + ) + } Ok(()) } @@ -336,20 +390,30 @@ 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!("non-overlapping copy is used for overlapping regions"))) + return Err(Error::Memory(format!( + "non-overlapping copy is used for overlapping regions" + ))); } - unsafe { ::core::ptr::copy_nonoverlapping( - buffer[read_region.range()].as_ptr(), - buffer[write_region.range()].as_mut_ptr(), - len, - )} + unsafe { + ::core::ptr::copy_nonoverlapping( + buffer[read_region.range()].as_ptr(), + buffer[write_region.range()].as_mut_ptr(), + len, + ) + } Ok(()) } @@ -357,7 +421,13 @@ impl MemoryInstance { /// Copy memory between two (possibly distinct) memory instances. /// /// If the same memory instance passed as `src` and `dst` then usual `copy` will be used. - pub fn transfer(src: &MemoryRef, src_offset: usize, dst: &MemoryRef, dst_offset: usize, len: usize) -> Result<(), Error> { + pub fn transfer( + src: &MemoryRef, + src_offset: usize, + dst: &MemoryRef, + dst_offset: usize, + len: usize, + ) -> Result<(), Error> { if Rc::ptr_eq(&src.0, &dst.0) { // `transfer` is invoked with with same source and destination. Let's assume that regions may // overlap and use `copy`. @@ -369,8 +439,12 @@ 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]); @@ -388,7 +462,9 @@ impl MemoryInstance { let mut buffer = self.buffer.borrow_mut(); let range = self.checked_region(&mut buffer, offset, len)?.range(); - for val in &mut buffer[range] { *val = new_val } + for val in &mut buffer[range] { + *val = new_val + } Ok(()) } @@ -434,19 +510,24 @@ impl MemoryInstance { pub fn validate_memory(initial: Pages, maximum: Option) -> Result<(), String> { if initial > LINEAR_MEMORY_MAX_PAGES { - return Err(format!("initial memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES.0)); + return Err(format!( + "initial memory size must be at most {} pages", + LINEAR_MEMORY_MAX_PAGES.0 + )); } if let Some(maximum) = maximum { if initial > maximum { return Err(format!( "maximum limit {} is less than minimum {}", - maximum.0, - initial.0, + maximum.0, initial.0, )); } if maximum > LINEAR_MEMORY_MAX_PAGES { - return Err(format!("maximum memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES.0)); + return Err(format!( + "maximum memory size must be at most {} pages", + LINEAR_MEMORY_MAX_PAGES.0 + )); } } Ok(()) @@ -455,10 +536,10 @@ pub fn validate_memory(initial: Pages, maximum: Option) -> Result<(), Str #[cfg(test)] mod tests { - use super::{MemoryRef, MemoryInstance, LINEAR_MEMORY_PAGE_SIZE}; + use super::{MemoryInstance, MemoryRef, LINEAR_MEMORY_PAGE_SIZE}; + use memory_units::Pages; use std::rc::Rc; use Error; - use memory_units::Pages; #[test] fn alloc() { @@ -493,11 +574,7 @@ mod tests { if result.is_ok() != expected_ok { panic!( "unexpected error at {}, initial={:?}, max={:?}, expected={}, result={:?}", - index, - initial, - maybe_max, - expected_ok, - result, + index, initial, maybe_max, expected_ok, result, ); } } @@ -511,7 +588,8 @@ 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 } @@ -534,7 +612,8 @@ mod tests { #[test] fn copy_nonoverlapping() { let mem = create_memory(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); - mem.copy_nonoverlapping(0, 10, 10).expect("Successfully copy the elements"); + mem.copy_nonoverlapping(0, 10, 10) + .expect("Successfully copy the elements"); let result = mem.get(10, 10).expect("Successfully retrieve the result"); assert_eq!(result, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); } @@ -544,7 +623,7 @@ mod tests { let mem = create_memory(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); let result = mem.copy_nonoverlapping(0, 4, 6); match result { - Err(Error::Memory(_)) => {}, + Err(Error::Memory(_)) => {} _ => panic!("Expected Error::Memory(_) result, but got {:?}", result), } } @@ -554,7 +633,7 @@ mod tests { let mem = create_memory(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); let result = mem.copy_nonoverlapping(4, 0, 6); match result { - Err(Error::Memory(_)) => {}, + Err(Error::Memory(_)) => {} _ => panic!("Expected Error::Memory(_), but got {:?}", result), } } @@ -562,12 +641,17 @@ 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] @@ -591,19 +675,25 @@ 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]); } @@ -611,10 +701,12 @@ 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]); } diff --git a/src/module.rs b/src/module.rs index 6a52c15..6a5f241 100644 --- a/src/module.rs +++ b/src/module.rs @@ -1,26 +1,26 @@ #[allow(unused_imports)] use alloc::prelude::*; use alloc::rc::Rc; -use Trap; use core::cell::RefCell; use core::fmt; +use Trap; -#[cfg(feature = "std")] -use std::collections::HashMap; #[cfg(not(feature = "std"))] use hashmap_core::HashMap; +#[cfg(feature = "std")] +use std::collections::HashMap; -use parity_wasm::elements::{External, InitExpr, Internal, Instruction, ResizableLimits, Type}; -use {Module, Error, Signature, MemoryInstance, RuntimeValue, TableInstance}; -use imports::ImportResolver; -use global::{GlobalInstance, GlobalRef}; -use func::{FuncRef, FuncBody, FuncInstance}; -use table::TableRef; -use memory::MemoryRef; -use host::Externals; use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; -use types::{GlobalDescriptor, TableDescriptor, MemoryDescriptor}; +use func::{FuncBody, FuncInstance, FuncRef}; +use global::{GlobalInstance, GlobalRef}; +use host::Externals; +use imports::ImportResolver; +use memory::MemoryRef; use memory_units::Pages; +use parity_wasm::elements::{External, InitExpr, Instruction, Internal, ResizableLimits, Type}; +use table::TableRef; +use types::{GlobalDescriptor, MemoryDescriptor, TableDescriptor}; +use {Error, MemoryInstance, Module, RuntimeValue, Signature, TableInstance}; /// Reference to a [`ModuleInstance`]. /// @@ -254,9 +254,9 @@ impl ModuleInstance { match (import.external(), extern_val) { (&External::Function(fn_type_idx), &ExternVal::Func(ref func)) => { - let expected_fn_type = instance.signature_by_index(fn_type_idx).expect( - "Due to validation function type should exists", - ); + let expected_fn_type = instance + .signature_by_index(fn_type_idx) + .expect("Due to validation function type should exists"); let actual_fn_type = func.signature(); if &*expected_fn_type != actual_fn_type { return Err(Error::Instantiation(format!( @@ -289,8 +289,7 @@ impl ModuleInstance { (expected_import, actual_extern_val) => { return Err(Error::Instantiation(format!( "Expected {:?} type, but provided {:?} extern_val", - expected_import, - actual_extern_val + expected_import, actual_extern_val ))); } } @@ -299,9 +298,10 @@ 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(), @@ -311,9 +311,9 @@ impl ModuleInstance { 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 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(); @@ -328,16 +328,15 @@ impl ModuleInstance { } 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 = memory_type.limits().maximum().map(|m| Pages(m as usize)); @@ -347,46 +346,45 @@ 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(), - ); + 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) => { - let func = instance.func_by_index(idx).expect( - "Due to validation func should exists", - ); + let func = instance + .func_by_index(idx) + .expect("Due to validation func should exists"); ExternVal::Func(func) } Internal::Global(idx) => { - let global = instance.global_by_index(idx).expect( - "Due to validation global should exists", - ); + let global = instance + .global_by_index(idx) + .expect("Due to validation global should exists"); ExternVal::Global(global) } Internal::Memory(idx) => { - let memory = instance.memory_by_index(idx).expect( - "Due to validation memory should exists", - ); + let memory = instance + .memory_by_index(idx) + .expect("Due to validation memory should exists"); ExternVal::Memory(memory) } Internal::Table(idx) => { - let table = instance.table_by_index(idx).expect( - "Due to validation table should exists", - ); + let table = instance + .table_by_index(idx) + .expect("Due to validation table should exists"); ExternVal::Table(table) } }; @@ -410,31 +408,34 @@ 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"), }; - let table_inst = module_ref.table_by_index(DEFAULT_TABLE_INDEX).expect( - "Due to validation default table should exists", - ); + let table_inst = module_ref + .table_by_index(DEFAULT_TABLE_INDEX) + .expect("Due to validation default table should exists"); // 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() { - let func = module_ref.func_by_index(*func_idx).expect( - "Due to validation funcs from element segments should exists", - ); + let func = module_ref + .func_by_index(*func_idx) + .expect("Due to validation funcs from element segments should exists"); table_inst.set(offset_val + j as u32, Some(func))?; } @@ -446,9 +447,9 @@ impl ModuleInstance { _ => panic!("Due to validation data segment offset should evaluate to i32"), }; - let memory_inst = module_ref.memory_by_index(DEFAULT_MEMORY_INDEX).expect( - "Due to validation default memory should exists", - ); + let memory_inst = module_ref + .memory_by_index(DEFAULT_MEMORY_INDEX) + .expect("Due to validation default memory should exists"); memory_inst.set(offset_val, data_segment.value())?; } @@ -540,17 +541,20 @@ 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) } }; @@ -614,23 +618,21 @@ impl ModuleInstance { args: &[RuntimeValue], externals: &mut E, ) -> Result, Error> { - let extern_val = self.export_by_name(func_name).ok_or_else(|| { - Error::Function(format!("Module doesn't have export {}", func_name)) - })?; + let extern_val = self + .export_by_name(func_name) + .ok_or_else(|| Error::Function(format!("Module doesn't have export {}", func_name)))?; let func_instance = match extern_val { ExternVal::Func(func_instance) => func_instance, unexpected => { return Err(Error::Function(format!( "Export {} is not a function, but {:?}", - func_name, - unexpected + func_name, unexpected ))); } }; - FuncInstance::invoke(&func_instance, args, externals) - .map_err(|t| Error::Trap(t)) + FuncInstance::invoke(&func_instance, args, externals).map_err(|t| Error::Trap(t)) } /// Find export by a name. @@ -685,9 +687,10 @@ impl<'a> NotStartedModuleRef<'a> { /// Returns `Err` if start function traps. pub fn run_start(self, state: &mut E) -> Result { if let Some(start_fn_idx) = self.loaded_module.module().start_section() { - let start_func = self.instance.func_by_index(start_fn_idx).expect( - "Due to validation start function should exists", - ); + let start_func = self + .instance + .func_by_index(start_fn_idx) + .expect("Due to validation start function should exists"); FuncInstance::invoke(&start_func, &[], state)?; } Ok(self.instance) @@ -718,9 +721,9 @@ fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance) -> RuntimeValue Instruction::F32Const(v) => RuntimeValue::decode_f32(v), Instruction::F64Const(v) => RuntimeValue::decode_f64(v), Instruction::GetGlobal(idx) => { - let global = module.global_by_index(idx).expect( - "Due to validation global should exists in module", - ); + let global = module + .global_by_index(idx) + .expect("Due to validation global should exists in module"); global.get() } _ => panic!("Due to validation init should be a const expr"), @@ -765,14 +768,13 @@ pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> { Ok(()) } - #[cfg(test)] mod tests { - use imports::ImportsBuilder; + use super::{ExternVal, ModuleInstance}; use func::FuncInstance; - use types::{Signature, ValueType}; - use super::{ModuleInstance, ExternVal}; + use imports::ImportsBuilder; use tests::parse_wat; + use types::{Signature, ValueType}; #[should_panic] #[test] @@ -782,12 +784,11 @@ mod tests { (module (func $f) (start $f)) - "# + "#, ); - ModuleInstance::new( - &module_with_start, - &ImportsBuilder::default() - ).unwrap().assert_no_start(); + ModuleInstance::new(&module_with_start, &ImportsBuilder::default()) + .unwrap() + .assert_no_start(); } #[test] @@ -803,9 +804,11 @@ mod tests { assert!( ModuleInstance::with_externvals( &module_with_single_import, - [ - ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 0),) - ].iter(), + [ExternVal::Func(FuncInstance::alloc_host( + Signature::new(&[][..], None), + 0 + ),)] + .iter(), ).is_ok() ); @@ -816,7 +819,8 @@ mod tests { [ ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 0)), ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 1)), - ].iter(), + ] + .iter(), ).is_err() ); @@ -827,12 +831,11 @@ mod tests { assert!( ModuleInstance::with_externvals( &module_with_single_import, - [ - ExternVal::Func(FuncInstance::alloc_host( - Signature::new(&[][..], Some(ValueType::I32)), - 0 - ),) - ].iter(), + [ExternVal::Func(FuncInstance::alloc_host( + Signature::new(&[][..], Some(ValueType::I32)), + 0 + ),)] + .iter(), ).is_err() ); } diff --git a/src/nan_preserving_float.rs b/src/nan_preserving_float.rs index 6579662..cb40c6d 100644 --- a/src/nan_preserving_float.rs +++ b/src/nan_preserving_float.rs @@ -3,210 +3,213 @@ #[cfg(not(feature = "std"))] use libm::{F32Ext, F64Ext}; -use core::ops::{Add, Div, Mul, Neg, Sub, Rem}; use core::cmp::{Ordering, PartialEq, PartialOrd}; +use core::ops::{Add, Div, Mul, Neg, Rem, Sub}; macro_rules! impl_binop { - ($for:ident, $is:ident, $op:ident, $func_name:ident) => { - impl> $op for $for { - type Output = Self; + ($for:ident, $is:ident, $op:ident, $func_name:ident) => { + impl> $op for $for { + 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() - ) - } - } - } + fn $func_name(self, other: T) -> Self { + $for( + $op::$func_name($is::from_bits(self.0), $is::from_bits(other.into().0)) + .to_bits(), + ) + } + } + }; } macro_rules! float { - ($for:ident, $rep:ident, $is:ident) => { - float!($for, $rep, $is, 1 << (::core::mem::size_of::<$is>() * 8 - 1)); - }; - ($for:ident, $rep:ident, $is:ident, $sign_bit:expr) => { - #[derive(Copy, Clone)] - pub struct $for($rep); + ($for:ident, $rep:ident, $is:ident) => { + float!( + $for, + $rep, + $is, + 1 << (::core::mem::size_of::<$is>() * 8 - 1) + ); + }; + ($for:ident, $rep:ident, $is:ident, $sign_bit:expr) => { + #[derive(Copy, Clone)] + pub struct $for($rep); - impl_binop!($for, $is, Add, add); - impl_binop!($for, $is, Sub, sub); - impl_binop!($for, $is, Mul, mul); - impl_binop!($for, $is, Div, div); - impl_binop!($for, $is, Rem, rem); + impl_binop!($for, $is, Add, add); + impl_binop!($for, $is, Sub, sub); + impl_binop!($for, $is, Mul, mul); + impl_binop!($for, $is, Div, div); + impl_binop!($for, $is, Rem, rem); - impl $for { - pub fn from_bits(other: $rep) -> Self { - $for(other) - } + impl $for { + pub fn from_bits(other: $rep) -> Self { + $for(other) + } - pub fn to_bits(self) -> $rep { - self.0 - } + pub fn to_bits(self) -> $rep { + self.0 + } - pub fn from_float(fl: $is) -> Self { - fl.into() - } + pub fn from_float(fl: $is) -> Self { + fl.into() + } - pub fn to_float(self) -> $is { - self.into() - } + pub fn to_float(self) -> $is { + self.into() + } - pub fn is_nan(self) -> bool { - self.to_float().is_nan() - } + pub fn is_nan(self) -> bool { + self.to_float().is_nan() + } - pub fn abs(self) -> Self { - $for(self.0 & !$sign_bit) - } + pub fn abs(self) -> Self { + $for(self.0 & !$sign_bit) + } - pub fn fract(self) -> Self { - self.to_float().fract().into() - } + pub fn fract(self) -> Self { + self.to_float().fract().into() + } - pub fn min(self, other: Self) -> Self { - Self::from(self.to_float().min(other.to_float())) - } + pub fn min(self, other: Self) -> Self { + Self::from(self.to_float().min(other.to_float())) + } - pub fn max(self, other: Self) -> Self { - Self::from(self.to_float().max(other.to_float())) - } - } + pub fn max(self, other: Self) -> Self { + Self::from(self.to_float().max(other.to_float())) + } + } - impl From<$is> for $for { - fn from(other: $is) -> $for { - $for(other.to_bits()) - } - } + impl From<$is> for $for { + fn from(other: $is) -> $for { + $for(other.to_bits()) + } + } - impl From<$for> for $is { - fn from(other: $for) -> $is { - <$is>::from_bits(other.0) - } - } + impl From<$for> for $is { + fn from(other: $for) -> $is { + <$is>::from_bits(other.0) + } + } - impl Neg for $for { - type Output = Self; + impl Neg for $for { + type Output = Self; - fn neg(self) -> Self { - $for(self.0 ^ $sign_bit) - } - } + fn neg(self) -> Self { + $for(self.0 ^ $sign_bit) + } + } - impl + Copy> PartialEq for $for { - fn eq(&self, other: &T) -> bool { - $is::from(*self) == $is::from((*other).into()) - } - } + impl + Copy> PartialEq for $for { + fn eq(&self, other: &T) -> bool { + $is::from(*self) == $is::from((*other).into()) + } + } - impl + Copy> PartialOrd for $for { - fn partial_cmp(&self, other: &T) -> Option { - $is::from(*self).partial_cmp(&$is::from((*other).into())) - } - } + impl + Copy> PartialOrd for $for { + fn partial_cmp(&self, other: &T) -> Option { + $is::from(*self).partial_cmp(&$is::from((*other).into())) + } + } - impl ::core::fmt::Debug for $for { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - $is::from(*self).fmt(f) - } - } - } + impl ::core::fmt::Debug for $for { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + $is::from(*self).fmt(f) + } + } + }; } float!(F32, u32, f32); float!(F64, u64, f64); impl From for F32 { - fn from(other: u32) -> Self { - Self::from_bits(other) - } + fn from(other: u32) -> Self { + Self::from_bits(other) + } } impl From for u32 { - fn from(other: F32) -> Self { - other.to_bits() - } + fn from(other: F32) -> Self { + other.to_bits() + } } impl From for F64 { - fn from(other: u64) -> Self { - Self::from_bits(other) - } + fn from(other: u64) -> Self { + Self::from_bits(other) + } } impl From for u64 { - fn from(other: F64) -> Self { - other.to_bits() - } + fn from(other: F64) -> Self { + other.to_bits() + } } #[cfg(test)] mod tests { - extern crate rand; + extern crate rand; - use self::rand::Rng; + use self::rand::Rng; - use super::{F32, F64}; + use super::{F32, F64}; - use core::ops::{Add, Div, Mul, Neg, Sub}; - use core::fmt::Debug; - use core::iter; + use core::fmt::Debug; + use core::iter; + use core::ops::{Add, Div, Mul, Neg, Sub}; - fn test_ops(iter: I) - where - T: Add - + Div - + Mul - + Sub - + Neg - + Copy - + Debug - + PartialEq, - F: Into - + Add - + Div - + Mul - + Sub - + Neg - + Copy - + Debug, - I: IntoIterator, - { - for (a, b) in iter { - assert_eq!((a + b).into(), a.into() + b.into()); - assert_eq!((a - b).into(), a.into() - b.into()); - assert_eq!((a * b).into(), a.into() * b.into()); - assert_eq!((a / b).into(), a.into() / b.into()); - assert_eq!((-a).into(), -a.into()); - assert_eq!((-b).into(), -b.into()); - } - } + fn test_ops(iter: I) + where + T: Add + + Div + + Mul + + Sub + + Neg + + Copy + + Debug + + PartialEq, + F: Into + + Add + + Div + + Mul + + Sub + + Neg + + Copy + + Debug, + I: IntoIterator, + { + for (a, b) in iter { + assert_eq!((a + b).into(), a.into() + b.into()); + assert_eq!((a - b).into(), a.into() - b.into()); + assert_eq!((a * b).into(), a.into() * b.into()); + assert_eq!((a / b).into(), a.into() / b.into()); + assert_eq!((-a).into(), -a.into()); + assert_eq!((-b).into(), -b.into()); + } + } - #[test] - fn test_ops_f32() { - let mut rng = rand::thread_rng(); - let iter = iter::repeat(()).map(|_| rng.gen()); + #[test] + fn test_ops_f32() { + let mut rng = rand::thread_rng(); + let iter = iter::repeat(()).map(|_| rng.gen()); - test_ops::(iter.take(1000)); - } + test_ops::(iter.take(1000)); + } - #[test] - fn test_ops_f64() { - let mut rng = rand::thread_rng(); - let iter = iter::repeat(()).map(|_| rng.gen()); + #[test] + fn test_ops_f64() { + let mut rng = rand::thread_rng(); + let iter = iter::repeat(()).map(|_| rng.gen()); - test_ops::(iter.take(1000)); - } + test_ops::(iter.take(1000)); + } - #[test] - fn test_neg_nan_f32() { - assert_eq!((-F32(0xff80_3210)).0, 0x7f80_3210); - } + #[test] + fn test_neg_nan_f32() { + assert_eq!((-F32(0xff80_3210)).0, 0x7f80_3210); + } - #[test] - fn test_neg_nan_f64() { - assert_eq!((-F64(0xff80_3210_0000_0000)).0, 0x7f80_3210_0000_0000); - } + #[test] + fn test_neg_nan_f64() { + assert_eq!((-F64(0xff80_3210_0000_0000)).0, 0x7f80_3210_0000_0000); + } } diff --git a/src/table.rs b/src/table.rs index 0e42196..c60af42 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,13 +1,13 @@ #[allow(unused_imports)] use alloc::prelude::*; use alloc::rc::Rc; -use core::u32; -use core::fmt; use core::cell::RefCell; -use parity_wasm::elements::ResizableLimits; -use Error; +use core::fmt; +use core::u32; use func::FuncRef; use module::check_limits; +use parity_wasm::elements::ResizableLimits; +use Error; /// Reference to a table (See [`TableInstance`] for details). /// @@ -106,21 +106,22 @@ impl TableInstance { pub fn grow(&self, by: u32) -> Result<(), Error> { let mut buffer = self.buffer.borrow_mut(); let maximum_size = self.maximum_size().unwrap_or(u32::MAX); - let new_size = self.current_size().checked_add(by) + 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(|| + }).ok_or_else(|| { Error::Table(format!( "Trying to grow table by {} items when there are already {} items", by, self.current_size(), )) - )?; + })?; buffer.resize(new_size as usize, None); Ok(()) } @@ -129,13 +130,12 @@ impl TableInstance { pub fn get(&self, offset: u32) -> Result, Error> { let buffer = self.buffer.borrow(); let buffer_len = buffer.len(); - let table_elem = buffer.get(offset as usize).cloned().ok_or_else(|| + let table_elem = buffer.get(offset as usize).cloned().ok_or_else(|| { Error::Table(format!( "trying to read table item with index {} when there are only {} items", - offset, - buffer_len - )), - )?; + offset, buffer_len + )) + })?; Ok(table_elem) } @@ -143,13 +143,12 @@ impl TableInstance { pub fn set(&self, offset: u32, value: Option) -> Result<(), Error> { let mut buffer = self.buffer.borrow_mut(); let buffer_len = buffer.len(); - let table_elem = buffer.get_mut(offset as usize).ok_or_else(|| + let table_elem = buffer.get_mut(offset as usize).ok_or_else(|| { Error::Table(format!( "trying to update table item with index {} when there are only {} items", - offset, - buffer_len + offset, buffer_len )) - )?; + })?; *table_elem = value; Ok(()) } diff --git a/src/tests/host.rs b/src/tests/host.rs index 4ba09d2..f217f91 100644 --- a/src/tests/host.rs +++ b/src/tests/host.rs @@ -1,11 +1,11 @@ -use { - Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, - MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef, - RuntimeValue, RuntimeArgs, TableDescriptor, MemoryDescriptor, Trap, TrapKind, ResumableError, -}; -use types::ValueType; -use memory_units::Pages; 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, +}; #[derive(Debug, Clone, PartialEq)] struct HostErrorWithCode { @@ -107,9 +107,10 @@ impl Externals for TestHost { INC_MEM_FUNC_INDEX => { let ptr: u32 = args.nth(0); - let memory = self.memory.as_ref().expect( - "Function 'inc_mem' expects attached memory", - ); + let memory = self + .memory + .as_ref() + .expect("Function 'inc_mem' expects attached memory"); let mut buf = [0u8; 1]; memory.get_into(ptr, &mut buf).unwrap(); buf[0] += 1; @@ -120,18 +121,22 @@ impl Externals for TestHost { GET_MEM_FUNC_INDEX => { let ptr: u32 = args.nth(0); - let memory = self.memory.as_ref().expect( - "Function 'get_mem' expects attached memory", - ); + let memory = self + .memory + .as_ref() + .expect("Function 'get_mem' expects attached memory"); let mut buf = [0u8; 1]; memory.get_into(ptr, &mut buf).unwrap(); 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 + let instance = self + .instance .as_ref() .expect("Function 'recurse' expects attached module instance") .clone(); @@ -141,7 +146,9 @@ 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)) } @@ -192,17 +199,17 @@ impl ModuleImportResolver for TestHost { "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) { return Err(Error::Instantiation(format!( "Export `{}` doesnt match expected type {:?}", - field_name, - signature + field_name, signature ))); } @@ -214,9 +221,10 @@ impl ModuleImportResolver for TestHost { field_name: &str, _memory_type: &MemoryDescriptor, ) -> Result { - Err(Error::Instantiation( - format!("Export {} not found", field_name), - )) + Err(Error::Instantiation(format!( + "Export {} not found", + field_name + ))) } } @@ -244,9 +252,9 @@ fn call_host_func() { .assert_no_start(); assert_eq!( - instance.invoke_export("test", &[], &mut env).expect( - "Failed to invoke 'test' function", - ), + instance + .invoke_export("test", &[], &mut env) + .expect("Failed to invoke 'test' function",), Some(RuntimeValue::I32(-2)) ); } @@ -280,16 +288,16 @@ fn resume_call_host_func() { let mut invocation = FuncInstance::invoke_resumable(&func_instance, &[]).unwrap(); let result = invocation.start_execution(&mut env); match result { - Err(ResumableError::Trap(_)) => {}, + Err(ResumableError::Trap(_)) => {} _ => panic!(), } assert!(invocation.is_resumable()); let trap_sub_result = env.trap_sub_result.take(); assert_eq!( - invocation.resume_execution(trap_sub_result, &mut env).expect( - "Failed to invoke 'test' function", - ), + invocation + .resume_execution(trap_sub_result, &mut env) + .expect("Failed to invoke 'test' function",), Some(RuntimeValue::I32(-2)) ); } @@ -316,13 +324,15 @@ fn host_err() { .expect("Failed to instantiate module") .assert_no_start(); - let error = instance.invoke_export("test", &[], &mut env).expect_err( - "`test` expected to return error", - ); + let error = instance + .invoke_export("test", &[], &mut env) + .expect_err("`test` expected to return error"); - let error_with_code = error.as_host_error().expect("Expected host error").downcast_ref::().expect( - "Failed to downcast to expected error type", - ); + let error_with_code = error + .as_host_error() + .expect("Expected host error") + .downcast_ref::() + .expect("Failed to downcast to expected error type"); assert_eq!(error_with_code.error_code, 228); } @@ -351,9 +361,9 @@ fn modify_mem_with_host_funcs() { .expect("Failed to instantiate module") .assert_no_start(); - instance.invoke_export("modify_mem", &[], &mut env).expect( - "Failed to invoke 'test' function", - ); + instance + .invoke_export("modify_mem", &[], &mut env) + .expect("Failed to invoke 'test' function"); // Check contents of memory at address 12. let mut buf = [0u8; 1]; @@ -451,9 +461,9 @@ fn recursion() { env.instance = Some(instance.clone()); assert_eq!( - instance.invoke_export("test", &[], &mut env).expect( - "Failed to invoke 'test' function", - ), + instance + .invoke_export("test", &[], &mut env) + .expect("Failed to invoke 'test' function",), // 363 = 321 + 42 Some(RuntimeValue::I64(363)) ); @@ -472,21 +482,17 @@ fn defer_providing_externals() { } impl ModuleImportResolver for HostImportResolver { - fn resolve_func( - &self, - field_name: &str, - signature: &Signature, - ) -> Result { + fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result { 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!( "Export `{}` doesnt match expected type {:?}", - field_name, - signature + field_name, signature ))); } @@ -501,9 +507,10 @@ fn defer_providing_externals() { 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 + ))) } } } @@ -547,15 +554,16 @@ fn defer_providing_externals() { // Create HostImportResolver with some initialized memory instance. // This memory instance will be provided as 'mem' export. - let host_import_resolver = - HostImportResolver { mem: MemoryInstance::alloc(Pages(1), Some(Pages(1))).unwrap() }; + let host_import_resolver = HostImportResolver { + mem: MemoryInstance::alloc(Pages(1), Some(Pages(1))).unwrap(), + }; // Instantiate module with `host_import_resolver` as import resolver for "host" module. let instance = ModuleInstance::new( &module, &ImportsBuilder::new().with_resolver("host", &host_import_resolver), ).expect("Failed to instantiate module") - .assert_no_start(); + .assert_no_start(); let mut acc = 89; { @@ -599,18 +607,15 @@ fn two_envs_one_externals() { struct OrdinaryResolver; impl ModuleImportResolver for PrivilegedResolver { - fn resolve_func( - &self, - field_name: &str, - signature: &Signature, - ) -> Result { + fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result { 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 + ))) } }; @@ -619,11 +624,7 @@ fn two_envs_one_externals() { } impl ModuleImportResolver for OrdinaryResolver { - fn resolve_func( - &self, - field_name: &str, - signature: &Signature, - ) -> Result { + fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result { let index = match field_name { "ordinary" => ORDINARY_FUNC_INDEX, "privileged" => { @@ -632,9 +633,10 @@ fn two_envs_one_externals() { )) } _ => { - return Err(Error::Instantiation( - format!("Export {} not found", field_name), - )) + return Err(Error::Instantiation(format!( + "Export {} not found", + field_name + ))) } }; @@ -674,7 +676,7 @@ fn two_envs_one_externals() { &trusted_module, &ImportsBuilder::new().with_resolver("env", &PrivilegedResolver), ).expect("Failed to instantiate module") - .assert_no_start(); + .assert_no_start(); let untrusted_instance = ModuleInstance::new( &untrusted_module, @@ -682,7 +684,7 @@ fn two_envs_one_externals() { .with_resolver("env", &OrdinaryResolver) .with_resolver("trusted", &trusted_instance), ).expect("Failed to instantiate module") - .assert_no_start(); + .assert_no_start(); untrusted_instance .invoke_export("test", &[], &mut HostExternals) @@ -716,7 +718,8 @@ fn dynamically_add_host_func() { Signature::new(&[][..], Some(ValueType::I32)), host_func_index as usize, ); - self.table.set(table_index, Some(added_func)) + self.table + .set(table_index, Some(added_func)) .map_err(|_| TrapKind::TableAccessOutOfBounds)?; Ok(Some(RuntimeValue::I32(table_index as i32))) @@ -730,17 +733,14 @@ fn dynamically_add_host_func() { } impl ModuleImportResolver for HostExternals { - fn resolve_func( - &self, - field_name: &str, - signature: &Signature, - ) -> Result { + fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result { 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)) @@ -754,9 +754,10 @@ fn dynamically_add_host_func() { 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 + ))) } } } @@ -789,7 +790,7 @@ fn dynamically_add_host_func() { &module, &ImportsBuilder::new().with_resolver("env", &host_externals), ).expect("Failed to instantiate module") - .assert_no_start(); + .assert_no_start(); assert_eq!( instance diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 193e274..611972d 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,5 +1,5 @@ use wabt; -use {Module}; +use Module; mod host; mod wasm; @@ -24,10 +24,16 @@ fn unsigned_to_runtime_value() { use super::RuntimeValue; let overflow_i32: u32 = ::core::i32::MAX as u32 + 1; - assert_eq!(RuntimeValue::from(overflow_i32).try_into::().unwrap(), overflow_i32); + assert_eq!( + RuntimeValue::from(overflow_i32).try_into::().unwrap(), + overflow_i32 + ); let overflow_i64: u64 = ::core::i64::MAX as u64 + 1; - assert_eq!(RuntimeValue::from(overflow_i64).try_into::().unwrap(), overflow_i64); + assert_eq!( + RuntimeValue::from(overflow_i64).try_into::().unwrap(), + overflow_i64 + ); } pub fn parse_wat(source: &str) -> Module { diff --git a/src/tests/wasm.rs b/src/tests/wasm.rs index c05d5f8..c9b2d25 100644 --- a/src/tests/wasm.rs +++ b/src/tests/wasm.rs @@ -1,10 +1,10 @@ -use { - Error, Signature, FuncRef, GlobalInstance, GlobalRef, ImportsBuilder, MemoryInstance, - MemoryRef, ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue, - TableInstance, TableRef, Module, GlobalDescriptor, TableDescriptor, MemoryDescriptor, -}; 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, +}; struct Env { table_base: GlobalRef, @@ -60,12 +60,17 @@ impl ModuleImportResolver for Env { } } - fn resolve_table(&self, field_name: &str, _table_type: &TableDescriptor) -> Result { + fn resolve_table( + &self, + field_name: &str, + _table_type: &TableDescriptor, + ) -> Result { match field_name { "table" => Ok(self.table.clone()), - _ => Err(Error::Instantiation( - format!("env module doesn't provide table '{}'", field_name), - )), + _ => Err(Error::Instantiation(format!( + "env module doesn't provide table '{}'", + field_name + ))), } } } @@ -90,10 +95,8 @@ fn interpreter_inc_i32() { let env = Env::new(); - let instance = ModuleInstance::new( - &module, - &ImportsBuilder::new().with_resolver("env", &env), - ).expect("Failed to instantiate module") + let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) + .expect("Failed to instantiate module") .assert_no_start(); let i32_val = 42; @@ -109,40 +112,40 @@ fn interpreter_inc_i32() { #[test] fn interpreter_accumulate_u8() { - // Name of function contained in WASM file (note the leading underline) - const FUNCTION_NAME: &'static str = "_accumulate_u8"; - // The WASM file containing the module and function - const WASM_FILE: &str = &"res/fixtures/accumulate_u8.wast"; - // The octet sequence being accumulated - const BUF: &[u8] = &[9,8,7,6,5,4,3,2,1]; + // Name of function contained in WASM file (note the leading underline) + const FUNCTION_NAME: &'static str = "_accumulate_u8"; + // The WASM file containing the module and function + const WASM_FILE: &str = &"res/fixtures/accumulate_u8.wast"; + // The octet sequence being accumulated + const BUF: &[u8] = &[9, 8, 7, 6, 5, 4, 3, 2, 1]; - - // Load the module-structure from wasm-file and add to program + // Load the module-structure from wasm-file and add to program let module = load_from_file(WASM_FILE); let env = Env::new(); - let instance = ModuleInstance::new( - &module, - &ImportsBuilder::new().with_resolver("env", &env), - ).expect("Failed to instantiate module") + let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) + .expect("Failed to instantiate module") .assert_no_start(); - let env_memory = env.memory.clone(); + let env_memory = env.memory.clone(); - // Place the octet-sequence at index 0 in linear memory - let offset: u32 = 0; - let _ = env_memory.set(offset, BUF); + // Place the octet-sequence at index 0 in linear memory + let offset: u32 = 0; + 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 retval = instance - .invoke_export(FUNCTION_NAME, args, &mut NopExternals) - .expect("Failed to execute function"); + // Set up the function argument list and invoke the function + 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"); - // For verification, repeat accumulation using native code - let accu = BUF.into_iter().fold(0 as i32, |a, b| a + *b as i32); - let exp_retval: Option = Some(RuntimeValue::I32(accu)); + // For verification, repeat accumulation using native code + let accu = BUF.into_iter().fold(0 as i32, |a, b| a + *b as i32); + let exp_retval: Option = Some(RuntimeValue::I32(accu)); - // Verify calculation from WebAssembly runtime is identical to expected result - assert_eq!(exp_retval, retval); + // Verify calculation from WebAssembly runtime is identical to expected result + assert_eq!(exp_retval, retval); } diff --git a/src/types.rs b/src/types.rs index 6cf139a..0509bc3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,7 +1,8 @@ use alloc::borrow::Cow; use parity_wasm::elements::{ - FunctionType, ValueType as EValueType, GlobalType, TableType, MemoryType}; + FunctionType, GlobalType, MemoryType, TableType, ValueType as EValueType, +}; /// Signature of a [function]. /// @@ -38,7 +39,7 @@ impl Signature { /// ``` pub fn new>>( params: C, - return_type: Option + return_type: Option, ) -> Signature { Signature { params: params.into(), @@ -58,7 +59,12 @@ impl Signature { pub(crate) fn from_elements(func_type: &FunctionType) -> Signature { Signature { - params: func_type.params().iter().cloned().map(ValueType::from_elements).collect(), + params: func_type + .params() + .iter() + .cloned() + .map(ValueType::from_elements) + .collect(), return_type: func_type.return_type().map(ValueType::from_elements), } } diff --git a/src/validation/context.rs b/src/validation/context.rs index 19805e5..c54923c 100644 --- a/src/validation/context.rs +++ b/src/validation/context.rs @@ -1,6 +1,8 @@ #[allow(unused_imports)] use alloc::prelude::*; -use parity_wasm::elements::{MemoryType, TableType, GlobalType, BlockType, ValueType, FunctionType}; +use parity_wasm::elements::{ + BlockType, FunctionType, GlobalType, MemoryType, TableType, ValueType, +}; use validation::Error; #[derive(Default, Debug)] @@ -47,26 +49,30 @@ impl ModuleContext { } pub fn require_function(&self, idx: u32) -> Result<(&[ValueType], BlockType), Error> { - let ty_idx = self.func_type_indexes() + let ty_idx = self + .func_type_indexes() .get(idx as usize) .ok_or_else(|| Error(format!("Function at index {} doesn't exists", idx)))?; self.require_function_type(*ty_idx) } pub fn require_function_type(&self, idx: u32) -> Result<(&[ValueType], BlockType), Error> { - let ty = self.types() + let ty = self + .types() .get(idx as usize) .ok_or_else(|| Error(format!("Type at index {} doesn't exists", idx)))?; let params = ty.params(); - let return_ty = ty.return_type() + let return_ty = ty + .return_type() .map(BlockType::Value) .unwrap_or(BlockType::NoResult); Ok((params, return_ty)) } pub fn require_global(&self, idx: u32, mutability: Option) -> Result<&GlobalType, Error> { - let global = self.globals() + let global = self + .globals() .get(idx as usize) .ok_or_else(|| Error(format!("Global at index {} doesn't exists", idx)))?; diff --git a/src/validation/func.rs b/src/validation/func.rs index 02ef454..c30f900 100644 --- a/src/validation/func.rs +++ b/src/validation/func.rs @@ -1,12 +1,12 @@ #[allow(unused_imports)] use alloc::prelude::*; -use core::u32; -use parity_wasm::elements::{Instruction, BlockType, ValueType, TableElementType, Func, FuncBody}; use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; +use core::u32; +use parity_wasm::elements::{BlockType, Func, FuncBody, Instruction, TableElementType, ValueType}; use validation::context::ModuleContext; -use validation::Error; use validation::util::Locals; +use validation::Error; use common::stack::StackWithLimit; use isa; @@ -39,13 +39,9 @@ enum BlockFrameType { /// Usual block frame. /// /// Can be used for an implicit function block. - Block { - end_label: LabelId, - }, + Block { end_label: LabelId }, /// Loop frame (branching to the beginning of block). - Loop { - header: LabelId, - }, + Loop { header: LabelId }, /// True-subblock of if expression. IfTrue { /// If jump happens inside the if-true block then control will @@ -58,9 +54,7 @@ enum BlockFrameType { if_not: LabelId, }, /// False-subblock of if expression. - IfFalse { - end_label: LabelId, - } + IfFalse { end_label: LabelId }, } impl BlockFrameType { @@ -183,9 +177,7 @@ impl FunctionReader { let end_label = context.sink.new_label(); push_label( - BlockFrameType::Block { - end_label, - }, + BlockFrameType::Block { end_label }, result_ty, context.position, &context.value_stack, @@ -198,7 +190,10 @@ 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())); @@ -207,15 +202,19 @@ 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; @@ -225,11 +224,14 @@ impl FunctionReader { } } - fn read_instruction(context: &mut FunctionValidationContext, instruction: &Instruction) -> Result { + fn read_instruction( + context: &mut FunctionValidationContext, + instruction: &Instruction, + ) -> Result { use self::Instruction::*; match *instruction { // Nop instruction doesn't do anything. It is safe to just skip it. - Nop => {}, + Nop => {} Unreachable => { context.sink.emit(isa::Instruction::Unreachable); @@ -239,9 +241,7 @@ impl FunctionReader { Block(block_type) => { let end_label = context.sink.new_label(); push_label( - BlockFrameType::Block { - end_label - }, + BlockFrameType::Block { end_label }, block_type, context.position, &context.value_stack, @@ -254,9 +254,7 @@ impl FunctionReader { context.sink.resolve_label(header); push_label( - BlockFrameType::Loop { - header, - }, + BlockFrameType::Loop { header }, block_type, context.position, &context.value_stack, @@ -269,12 +267,13 @@ 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, - }, + BlockFrameType::IfTrue { if_not, end_label }, block_type, context.position, &context.value_stack, @@ -283,14 +282,15 @@ impl FunctionReader { context.sink.emit_br_eqz(Target { label: if_not, - drop_keep: isa::DropKeep { drop: 0, keep: isa::Keep::None, }, + drop_keep: isa::DropKeep { + drop: 0, + keep: isa::Keep::None, + }, }); } Else => { let (block_type, if_not, end_label) = { - let top_frame = top_label( - &context.frame_stack, - ); + let top_frame = top_label(&context.frame_stack); let (if_not, end_label) = match top_frame.frame_type { BlockFrameType::IfTrue { if_not, end_label } => (if_not, end_label), @@ -303,7 +303,10 @@ impl FunctionReader { // to the "end_label" (it will be resolved at End). context.sink.emit_br(Target { label: end_label, - drop_keep: isa::DropKeep { drop: 0, keep: isa::Keep::None, }, + drop_keep: isa::DropKeep { + drop: 0, + keep: isa::Keep::None, + }, }); // Resolve `if_not` to here so when if condition is unsatisfied control flow @@ -312,14 +315,9 @@ impl FunctionReader { // Then, we pop the current label. It discards all values that pushed in the current // frame. - pop_label( - &mut context.value_stack, - &mut context.frame_stack - )?; + pop_label(&mut context.value_stack, &mut context.frame_stack)?; push_label( - BlockFrameType::IfFalse { - end_label, - }, + BlockFrameType::IfFalse { end_label }, block_type, context.position, &context.value_stack, @@ -335,14 +333,10 @@ impl FunctionReader { if let BlockFrameType::IfTrue { if_not, .. } = frame_type { // A `if` without an `else` can't return a result. if block_type != BlockType::NoResult { - return Err( - Error( - format!( + return Err(Error(format!( "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 @@ -365,7 +359,7 @@ impl FunctionReader { tee_value( &mut context.value_stack, &context.frame_stack, - value_type.into() + value_type.into(), )?; } @@ -388,11 +382,7 @@ impl FunctionReader { Br(depth) => { Validator::validate_br(context, depth)?; - let target = require_target( - depth, - &context.value_stack, - &context.frame_stack, - ); + let target = require_target(depth, &context.value_stack, &context.frame_stack); context.sink.emit_br(target); return Ok(Outcome::Unreachable); @@ -400,11 +390,7 @@ impl FunctionReader { BrIf(depth) => { Validator::validate_br_if(context, depth)?; - let target = require_target( - depth, - &context.value_stack, - &context.frame_stack, - ); + let target = require_target(depth, &context.value_stack, &context.frame_stack); context.sink.emit_br_nez(target); } BrTable(ref table, default) => { @@ -412,32 +398,26 @@ impl FunctionReader { let mut targets = Vec::new(); for depth in table.iter() { - let target = require_target( - *depth, - &context.value_stack, - &context.frame_stack, - ); + 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); @@ -464,37 +444,19 @@ impl FunctionReader { GetLocal(index) => { // We need to calculate relative depth before validation since // it will change the value stack size. - let depth = relative_local_depth( - index, - &context.locals, - &context.value_stack, - )?; + let depth = relative_local_depth(index, &context.locals, &context.value_stack)?; Validator::validate_get_local(context, index)?; - context.sink.emit( - isa::Instruction::GetLocal(depth), - ); + context.sink.emit(isa::Instruction::GetLocal(depth)); } SetLocal(index) => { Validator::validate_set_local(context, index)?; - let depth = relative_local_depth( - index, - &context.locals, - &context.value_stack, - )?; - context.sink.emit( - isa::Instruction::SetLocal(depth), - ); + let depth = relative_local_depth(index, &context.locals, &context.value_stack)?; + context.sink.emit(isa::Instruction::SetLocal(depth)); } TeeLocal(index) => { Validator::validate_tee_local(context, index)?; - let depth = relative_local_depth( - index, - &context.locals, - &context.value_stack, - )?; - context.sink.emit( - isa::Instruction::TeeLocal(depth), - ); + let depth = relative_local_depth(index, &context.locals, &context.value_stack)?; + context.sink.emit(isa::Instruction::TeeLocal(depth)); } GetGlobal(index) => { Validator::validate_get_global(context, index)?; @@ -1136,78 +1098,160 @@ 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(()) } - fn validate_cvtop(context: &mut FunctionValidationContext, value_type1: ValueType, value_type2: ValueType) -> Result<(), Error> { - pop_value(&mut context.value_stack, &context.frame_stack, value_type1.into())?; + fn validate_cvtop( + context: &mut FunctionValidationContext, + value_type1: ValueType, + value_type2: ValueType, + ) -> Result<(), Error> { + 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)?; - if StackValueType::from(local_type) != value_type { - return Err(Error(format!("Trying to update local {} of type {:?} with value of type {:?}", index, local_type, value_type))); + 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 {:?}", + index, local_type, value_type + ))); } 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() @@ -1216,37 +1260,75 @@ 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 {:?}", index, global_type, value_type))); + return Err(Error(format!( + "Trying to update global {} of type {:?} with value of type {:?}", + index, global_type, value_type + ))); } Ok(()) } - fn validate_load(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: ValueType) -> Result<(), Error> { + fn validate_load( + context: &mut FunctionValidationContext, + align: u32, + max_align: u32, + value_type: ValueType, + ) -> Result<(), Error> { if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align { - return Err(Error(format!("Too large memory alignment 2^{} (expected at most {})", align, max_align))); + return Err(Error(format!( + "Too large memory alignment 2^{} (expected at most {})", + align, max_align + ))); } - 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(()) } - fn validate_store(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: ValueType) -> Result<(), Error> { + fn validate_store( + context: &mut FunctionValidationContext, + align: u32, + max_align: u32, + value_type: ValueType, + ) -> Result<(), Error> { if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align { - return Err(Error(format!("Too large memory alignment 2^{} (expected at most {})", align, max_align))); + return Err(Error(format!( + "Too large memory alignment 2^{} (expected at most {})", + align, max_align + ))); } 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(()) } @@ -1257,14 +1339,22 @@ 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)?; @@ -1272,13 +1362,21 @@ 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() { @@ -1295,23 +1393,26 @@ impl Validator { BlockType::NoResult }; if required_block_type != label_block_type { - return Err( - Error( - format!( - "Labels in br_table points to block of different types: {:?} and {:?}", - required_block_type, - label_block.block_type - ) - ) - ); + return Err(Error(format!( + "Labels in br_table points to block of different types: {:?} and {:?}", + required_block_type, label_block.block_type + ))); } } 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(()) @@ -1320,7 +1421,11 @@ 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())?; @@ -1328,7 +1433,10 @@ 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 { @@ -1340,10 +1448,18 @@ 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())?; @@ -1359,7 +1475,11 @@ 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(()) } @@ -1416,7 +1536,9 @@ fn make_top_frame_polymorphic( value_stack: &mut StackWithLimit, frame_stack: &mut StackWithLimit, ) { - let frame = frame_stack.top_mut().expect("make_top_frame_polymorphic is called with empty frame stack"); + let frame = frame_stack + .top_mut() + .expect("make_top_frame_polymorphic is called with empty frame stack"); value_stack.resize(frame.value_stack_len, StackValueType::Any); frame.polymorphic_stack = true; } @@ -1501,7 +1623,11 @@ 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), + )?; } } @@ -1518,7 +1644,8 @@ fn pop_label( } fn top_label(frame_stack: &StackWithLimit) -> &BlockFrame { - frame_stack.top() + frame_stack + .top() .expect("this function can't be called with empty frame stack") } @@ -1534,8 +1661,7 @@ fn require_target( value_stack: &StackWithLimit, frame_stack: &StackWithLimit, ) -> Target { - let is_stack_polymorphic = top_label(frame_stack) - .polymorphic_stack; + 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"); @@ -1604,7 +1730,7 @@ fn require_local(locals: &Locals, idx: u32) -> Result { fn relative_local_depth( idx: u32, locals: &Locals, - value_stack: &StackWithLimit + value_stack: &StackWithLimit, ) -> Result { let value_stack_height = value_stack.len() as u32; let locals_and_params_count = locals.count(); @@ -1612,9 +1738,7 @@ fn relative_local_depth( let depth = value_stack_height .checked_add(locals_and_params_count) .and_then(|x| x.checked_sub(idx)) - .ok_or_else(|| - Error(String::from("Locals range not in 32-bit range")) - )?; + .ok_or_else(|| Error(String::from("Locals range not in 32-bit range")))?; Ok(depth) } @@ -1655,12 +1779,15 @@ impl Sink { self.ins.current_pc() } - fn pc_or_placeholder isa::Reloc>(&mut self, label: LabelId, reloc_creator: F) -> u32 { + fn pc_or_placeholder 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) => { - unresolved - .push(reloc_creator()); + unresolved.push(reloc_creator()); u32::max_value() } } @@ -1671,10 +1798,7 @@ impl Sink { } fn emit_br(&mut self, target: Target) { - let Target { - label, - drop_keep, - } = target; + let Target { label, drop_keep } = target; let pc = self.cur_pc(); let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::Br { pc }); self.ins.push(isa::Instruction::Br(isa::Target { @@ -1684,10 +1808,7 @@ impl Sink { } fn emit_br_eqz(&mut self, target: Target) { - let Target { - label, - drop_keep, - } = target; + let Target { label, drop_keep } = target; let pc = self.cur_pc(); let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::Br { pc }); self.ins.push(isa::Instruction::BrIfEqz(isa::Target { @@ -1697,10 +1818,7 @@ impl Sink { } fn emit_br_nez(&mut self, target: Target) { - let Target { - label, - drop_keep, - } = target; + let Target { label, drop_keep } = target; let pc = self.cur_pc(); let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::Br { pc }); self.ins.push(isa::Instruction::BrIfNez(isa::Target { @@ -1714,26 +1832,23 @@ 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(), - }, - ); + 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. fn new_label(&mut self) -> LabelId { let label_idx = self.labels.len(); - self.labels.push( - (Label::NotResolved, Vec::new()), - ); + self.labels.push((Label::NotResolved, Vec::new())); LabelId(label_idx) } @@ -1762,14 +1877,18 @@ impl Sink { /// Consume this Sink and returns isa::Instructions. fn into_inner(self) -> isa::Instructions { // 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, - } - ) - }, "there are unresolved labels left: {:?}", self.labels); + assert!( + { + 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 + ); self.ins } } diff --git a/src/validation/mod.rs b/src/validation/mod.rs index fdb2d11..26ed7a3 100644 --- a/src/validation/mod.rs +++ b/src/validation/mod.rs @@ -1,23 +1,23 @@ #[allow(unused_imports)] use alloc::prelude::*; +use core::fmt; #[cfg(feature = "std")] use std::error; -use core::fmt; -#[cfg(feature = "std")] -use std::collections::HashSet; #[cfg(not(feature = "std"))] use hashmap_core::HashSet; +#[cfg(feature = "std")] +use std::collections::HashSet; -use parity_wasm::elements::{ - BlockType, External, GlobalEntry, GlobalType, Internal, MemoryType, Module, Instruction, - ResizableLimits, TableType, ValueType, InitExpr, Type, -}; -use common::stack; use self::context::ModuleContextBuilder; use self::func::FunctionReader; -use memory_units::Pages; +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, +}; mod context; mod func; @@ -158,7 +158,8 @@ pub fn deny_floating_point(module: &Module) -> Result<(), Error> { if let Some(typ) = types.get(sig.type_ref() as usize) { match *typ { Type::Function(ref func) => { - if func.params() + if func + .params() .iter() .chain(func.return_type().as_ref()) .any(|&typ| typ == ValueType::F32 || typ == ValueType::F64) @@ -189,8 +190,7 @@ pub fn validate_module(module: Module) -> Result { .map(|&Type::Function(ref ty)| ty) .cloned() .collect() - }) - .unwrap_or_default(), + }).unwrap_or_default(), ); // Fill elements with imported values. @@ -245,32 +245,32 @@ pub fn validate_module(module: Module) -> Result { if function_section_len != code_section_len { return Err(Error(format!( "length of function section is {}, while len of code section is {}", - function_section_len, - code_section_len + function_section_len, code_section_len ))); } // 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 code_section = module.code_section().expect( - "function_section_len != 0; function_section_len == code_section_len; 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"); // check every function body for (index, function) in function_section.entries().iter().enumerate() { - let function_body = code_section.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 function_body = code_section + .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)) + Error(format!( + "Function #{} reading/validation error: {}", + index, msg + )) })?; code_map.push(code); } @@ -293,9 +293,7 @@ pub fn validate_module(module: Module) -> Result { // HashSet::insert returns false if item already in set. let duplicate = export_names.insert(export.field()) == false; if duplicate { - return Err(Error( - format!("duplicate export {}", export.field()), - )); + return Err(Error(format!("duplicate export {}", export.field()))); } match *export.internal() { Internal::Function(function_index) => { @@ -382,10 +380,7 @@ pub fn validate_module(module: Module) -> Result { } } - Ok(ValidatedModule { - module, - code_map, - }) + Ok(ValidatedModule { module, code_map }) } fn validate_limits(limits: &ResizableLimits) -> Result<(), Error> { @@ -413,15 +408,15 @@ fn validate_table_type(table_type: &TableType) -> Result<(), Error> { fn validate_global_entry(global_entry: &GlobalEntry, globals: &[GlobalType]) -> Result<(), Error> { let init = global_entry.init_expr(); - let init_expr_ty = expr_const_type(init, globals)?; - if init_expr_ty != global_entry.global_type().content_type() { - return Err(Error(format!( - "Trying to initialize variable of type {:?} with value of type {:?}", - global_entry.global_type().content_type(), - init_expr_ty - ))); - } - Ok(()) + let init_expr_ty = expr_const_type(init, globals)?; + if init_expr_ty != global_entry.global_type().content_type() { + return Err(Error(format!( + "Trying to initialize variable of type {:?} with value of type {:?}", + global_entry.global_type().content_type(), + init_expr_ty + ))); + } + Ok(()) } /// Returns type of this constant expression. @@ -437,21 +432,20 @@ fn expr_const_type(init_expr: &InitExpr, globals: &[GlobalType]) -> Result ValueType::I64, Instruction::F32Const(_) => ValueType::F32, Instruction::F64Const(_) => ValueType::F64, - Instruction::GetGlobal(idx) => { - match globals.get(idx as usize) { - Some(target_global) => { - if target_global.is_mutable() { - return Err(Error(format!("Global {} is mutable", idx))); - } - target_global.content_type() - } - None => { - return Err(Error( - format!("Global {} doesn't exists or not yet defined", idx), - )) + Instruction::GetGlobal(idx) => match globals.get(idx as usize) { + Some(target_global) => { + if target_global.is_mutable() { + return Err(Error(format!("Global {} is mutable", idx))); } + target_global.content_type() } - } + None => { + return Err(Error(format!( + "Global {} doesn't exists or not yet defined", + idx + ))) + } + }, _ => return Err(Error("Non constant opcode in init expr".into())), }; if code[1] != Instruction::End { diff --git a/src/validation/tests.rs b/src/validation/tests.rs index 9a8829e..08b270c 100644 --- a/src/validation/tests.rs +++ b/src/validation/tests.rs @@ -1,11 +1,10 @@ use super::{validate_module, ValidatedModule}; +use isa; use parity_wasm::builder::module; use parity_wasm::elements::{ - External, GlobalEntry, GlobalType, ImportEntry, InitExpr, MemoryType, - Instruction, Instructions, TableType, ValueType, BlockType, deserialize_buffer, - Module, + deserialize_buffer, BlockType, External, GlobalEntry, GlobalType, ImportEntry, InitExpr, + Instruction, Instructions, MemoryType, Module, TableType, ValueType, }; -use isa; use wabt; #[test] @@ -27,45 +26,34 @@ fn limits() { for (min, max, is_valid) in test_cases { // defined table - let m = module() - .table() - .with_min(min) - .with_max(max) - .build() - .build(); + let m = module().table().with_min(min).with_max(max).build().build(); assert_eq!(validate_module(m).is_ok(), is_valid); // imported table let m = module() - .with_import( - ImportEntry::new( - "core".into(), - "table".into(), - External::Table(TableType::new(min, max)) - ) - ) - .build(); + .with_import(ImportEntry::new( + "core".into(), + "table".into(), + External::Table(TableType::new(min, max)), + )).build(); assert_eq!(validate_module(m).is_ok(), is_valid); // defined memory let m = module() .memory() - .with_min(min) - .with_max(max) - .build() + .with_min(min) + .with_max(max) + .build() .build(); assert_eq!(validate_module(m).is_ok(), is_valid); // imported table let m = module() - .with_import( - ImportEntry::new( - "core".into(), - "memory".into(), - External::Memory(MemoryType::new(min, max)) - ) - ) - .build(); + .with_import(ImportEntry::new( + "core".into(), + "memory".into(), + External::Memory(MemoryType::new(min, max)), + )).build(); assert_eq!(validate_module(m).is_ok(), is_valid); } } @@ -73,92 +61,63 @@ fn limits() { #[test] fn global_init_const() { let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new( - vec![Instruction::I32Const(42), Instruction::End] - ) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::I32Const(42), Instruction::End]), + )).build(); assert!(validate_module(m).is_ok()); // init expr type differs from declared global type let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I64, true), - InitExpr::new(vec![Instruction::I32Const(42), Instruction::End]) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I64, true), + InitExpr::new(vec![Instruction::I32Const(42), Instruction::End]), + )).build(); assert!(validate_module(m).is_err()); } #[test] fn global_init_global() { let m = module() - .with_import( - ImportEntry::new( - "env".into(), - "ext_global".into(), - External::Global(GlobalType::new(ValueType::I32, false)) - ) - ) - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]) - ) - ) - .build(); + .with_import(ImportEntry::new( + "env".into(), + "ext_global".into(), + External::Global(GlobalType::new(ValueType::I32, false)), + )).with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]), + )).build(); assert!(validate_module(m).is_ok()); // get_global can reference only previously defined globals let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]), + )).build(); assert!(validate_module(m).is_err()); // get_global can reference only const globals let m = module() - .with_import( - ImportEntry::new( - "env".into(), - "ext_global".into(), - External::Global(GlobalType::new(ValueType::I32, true)) - ) - ) - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]) - ) - ) - .build(); + .with_import(ImportEntry::new( + "env".into(), + "ext_global".into(), + External::Global(GlobalType::new(ValueType::I32, true)), + )).with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]), + )).build(); assert!(validate_module(m).is_err()); // get_global in init_expr can only refer to imported globals. let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, false), - InitExpr::new(vec![Instruction::I32Const(0), Instruction::End]) - ) - ) - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, false), + InitExpr::new(vec![Instruction::I32Const(0), Instruction::End]), + )).with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]), + )).build(); assert!(validate_module(m).is_err()); } @@ -166,35 +125,26 @@ fn global_init_global() { fn global_init_misc() { // without delimiting End opcode let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::I32Const(42)]) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::I32Const(42)]), + )).build(); assert!(validate_module(m).is_err()); // empty init expr let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::End]) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::End]), + )).build(); assert!(validate_module(m).is_err()); // not an constant opcode used let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::Unreachable, Instruction::End]) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::Unreachable, Instruction::End]), + )).build(); assert!(validate_module(m).is_err()); } @@ -202,31 +152,25 @@ fn global_init_misc() { fn module_limits_validity() { // module cannot contain more than 1 memory atm. let m = module() - .with_import( - ImportEntry::new( - "core".into(), - "memory".into(), - External::Memory(MemoryType::new(10, None)) - ) - ) - .memory() - .with_min(10) - .build() + .with_import(ImportEntry::new( + "core".into(), + "memory".into(), + External::Memory(MemoryType::new(10, None)), + )).memory() + .with_min(10) + .build() .build(); assert!(validate_module(m).is_err()); // module cannot contain more than 1 table atm. let m = module() - .with_import( - ImportEntry::new( - "core".into(), - "table".into(), - External::Table(TableType::new(10, None)) - ) - ) - .table() - .with_min(10) - .build() + .with_import(ImportEntry::new( + "core".into(), + "table".into(), + External::Table(TableType::new(10, None)), + )).table() + .with_min(10) + .build() .build(); assert!(validate_module(m).is_err()); } @@ -236,19 +180,27 @@ fn funcs() { // recursive function calls is legal. let m = module() .function() - .signature().return_type().i32().build() - .body().with_instructions(Instructions::new(vec![ - Instruction::Call(1), - Instruction::End, - ])).build() - .build() + .signature() + .return_type() + .i32() + .build() + .body() + .with_instructions(Instructions::new(vec![ + Instruction::Call(1), + Instruction::End, + ])).build() + .build() .function() - .signature().return_type().i32().build() - .body().with_instructions(Instructions::new(vec![ - Instruction::Call(0), - Instruction::End, - ])).build() - .build() + .signature() + .return_type() + .i32() + .build() + .body() + .with_instructions(Instructions::new(vec![ + Instruction::Call(0), + Instruction::End, + ])).build() + .build() .build(); assert!(validate_module(m).is_ok()); } @@ -257,26 +209,20 @@ fn funcs() { fn globals() { // import immutable global is legal. let m = module() - .with_import( - ImportEntry::new( - "env".into(), - "ext_global".into(), - External::Global(GlobalType::new(ValueType::I32, false)) - ) - ) - .build(); + .with_import(ImportEntry::new( + "env".into(), + "ext_global".into(), + External::Global(GlobalType::new(ValueType::I32, false)), + )).build(); assert!(validate_module(m).is_ok()); // import mutable global is invalid. let m = module() - .with_import( - ImportEntry::new( - "env".into(), - "ext_global".into(), - External::Global(GlobalType::new(ValueType::I32, true)) - ) - ) - .build(); + .with_import(ImportEntry::new( + "env".into(), + "ext_global".into(), + External::Global(GlobalType::new(ValueType::I32, true)), + )).build(); assert!(validate_module(m).is_err()); } @@ -284,21 +230,23 @@ fn globals() { fn if_else_with_return_type_validation() { let m = module() .function() - .signature().build() - .body().with_instructions(Instructions::new(vec![ - Instruction::I32Const(1), - Instruction::If(BlockType::NoResult), - Instruction::I32Const(1), - Instruction::If(BlockType::Value(ValueType::I32)), - Instruction::I32Const(1), - Instruction::Else, - Instruction::I32Const(2), - Instruction::End, - Instruction::Drop, - Instruction::End, - Instruction::End, - ])).build() - .build() + .signature() + .build() + .body() + .with_instructions(Instructions::new(vec![ + Instruction::I32Const(1), + Instruction::If(BlockType::NoResult), + Instruction::I32Const(1), + Instruction::If(BlockType::Value(ValueType::I32)), + Instruction::I32Const(1), + Instruction::Else, + Instruction::I32Const(2), + Instruction::End, + Instruction::Drop, + Instruction::End, + Instruction::End, + ])).build() + .build() .build(); validate_module(m).unwrap(); } @@ -323,7 +271,7 @@ fn compile(wat: &str) -> (Vec, Vec) { instructions.push(instruction.clone()); pcs.push(pc); } else { - break + break; } } @@ -332,32 +280,34 @@ fn compile(wat: &str) -> (Vec, Vec) { #[test] fn implicit_return_no_value() { - let (code, _) = compile(r#" + let (code, _) = compile( + r#" (module (func (export "call") ) ) - "#); + "#, + ); assert_eq!( code, - vec![ - isa::Instruction::Return(isa::DropKeep { - drop: 0, - keep: isa::Keep::None, - }) - ] + vec![isa::Instruction::Return(isa::DropKeep { + drop: 0, + keep: isa::Keep::None, + })] ) } #[test] fn implicit_return_with_value() { - let (code, _) = compile(r#" + let (code, _) = compile( + r#" (module (func (export "call") (result i32) i32.const 0 ) ) - "#); + "#, + ); assert_eq!( code, vec![ @@ -372,32 +322,34 @@ fn implicit_return_with_value() { #[test] fn implicit_return_param() { - let (code, _) = compile(r#" + let (code, _) = compile( + r#" (module (func (export "call") (param i32) ) ) - "#); + "#, + ); assert_eq!( code, - vec![ - isa::Instruction::Return(isa::DropKeep { - drop: 1, - keep: isa::Keep::None, - }), - ] + vec![isa::Instruction::Return(isa::DropKeep { + drop: 1, + keep: isa::Keep::None, + }),] ) } #[test] fn get_local() { - let (code, _) = compile(r#" + let (code, _) = compile( + r#" (module (func (export "call") (param i32) (result i32) get_local 0 ) ) - "#); + "#, + ); assert_eq!( code, vec![ @@ -412,14 +364,16 @@ fn get_local() { #[test] fn explicit_return() { - let (code, _) = compile(r#" + let (code, _) = compile( + r#" (module (func (export "call") (param i32) (result i32) get_local 0 return ) ) - "#); + "#, + ); assert_eq!( code, vec![ @@ -438,7 +392,8 @@ fn explicit_return() { #[test] fn add_params() { - let (code, _) = compile(r#" + let (code, _) = compile( + r#" (module (func (export "call") (param i32) (param i32) (result i32) get_local 0 @@ -446,7 +401,8 @@ fn add_params() { i32.add ) ) - "#); + "#, + ); assert_eq!( code, vec![ @@ -468,7 +424,8 @@ fn add_params() { #[test] fn drop_locals() { - let (code, _) = compile(r#" + let (code, _) = compile( + r#" (module (func (export "call") (param i32) (local i32) @@ -476,7 +433,8 @@ fn drop_locals() { set_local 1 ) ) - "#); + "#, + ); assert_eq!( code, vec![ @@ -492,7 +450,8 @@ fn drop_locals() { #[test] fn if_without_else() { - let (code, pcs) = compile(r#" + let (code, pcs) = compile( + r#" (module (func (export "call") (param i32) (result i32) i32.const 1 @@ -503,7 +462,8 @@ fn if_without_else() { i32.const 3 ) ) - "#); + "#, + ); assert_eq!( code, vec![ @@ -517,7 +477,7 @@ fn if_without_else() { }), isa::Instruction::I32Const(2), isa::Instruction::Return(isa::DropKeep { - drop: 1, // 1 param + drop: 1, // 1 param keep: isa::Keep::Single, // 1 result }), isa::Instruction::I32Const(3), @@ -531,7 +491,8 @@ fn if_without_else() { #[test] fn if_else() { - let (code, pcs) = compile(r#" + let (code, pcs) = compile( + r#" (module (func (export "call") (local i32) @@ -545,7 +506,8 @@ fn if_else() { end ) ) - "#); + "#, + ); assert_eq!( code, vec![ @@ -578,7 +540,8 @@ fn if_else() { #[test] fn if_else_returns_result() { - let (code, pcs) = compile(r#" + let (code, pcs) = compile( + r#" (module (func (export "call") i32.const 1 @@ -590,7 +553,8 @@ fn if_else_returns_result() { drop ) ) - "#); + "#, + ); assert_eq!( code, vec![ @@ -622,7 +586,8 @@ fn if_else_returns_result() { #[test] fn if_else_branch_from_true_branch() { - let (code, pcs) = compile(r#" + let (code, pcs) = compile( + r#" (module (func (export "call") i32.const 1 @@ -638,7 +603,8 @@ fn if_else_branch_from_true_branch() { drop ) ) - "#); + "#, + ); assert_eq!( code, vec![ @@ -680,7 +646,8 @@ fn if_else_branch_from_true_branch() { #[test] fn if_else_branch_from_false_branch() { - let (code, pcs) = compile(r#" + let (code, pcs) = compile( + r#" (module (func (export "call") i32.const 1 @@ -696,7 +663,8 @@ fn if_else_branch_from_false_branch() { drop ) ) - "#); + "#, + ); assert_eq!( code, vec![ @@ -738,7 +706,8 @@ fn if_else_branch_from_false_branch() { #[test] fn loop_() { - let (code, _) = compile(r#" + let (code, _) = compile( + r#" (module (func (export "call") loop (result i32) @@ -749,7 +718,8 @@ fn loop_() { drop ) ) - "#); + "#, + ); assert_eq!( code, vec![ @@ -773,28 +743,29 @@ fn loop_() { #[test] fn loop_empty() { - let (code, _) = compile(r#" + let (code, _) = compile( + r#" (module (func (export "call") loop end ) ) - "#); + "#, + ); assert_eq!( code, - vec![ - isa::Instruction::Return(isa::DropKeep { - drop: 0, - keep: isa::Keep::None, - }), - ] + vec![isa::Instruction::Return(isa::DropKeep { + drop: 0, + keep: isa::Keep::None, + }),] ) } #[test] fn brtable() { - let (code, pcs) = compile(r#" + let (code, pcs) = compile( + r#" (module (func (export "call") block $1 @@ -805,7 +776,8 @@ fn brtable() { end ) ) - "#); + "#, + ); assert_eq!( code, vec![ @@ -838,7 +810,8 @@ fn brtable() { #[test] fn brtable_returns_result() { - let (code, pcs) = compile(r#" + let (code, pcs) = compile( + r#" (module (func (export "call") block $1 (result i32) @@ -852,7 +825,8 @@ fn brtable_returns_result() { drop ) ) - "#); + "#, + ); assert_eq!( code, vec![ @@ -888,7 +862,8 @@ fn brtable_returns_result() { #[test] fn wabt_example() { - let (code, pcs) = compile(r#" + let (code, pcs) = compile( + r#" (module (func (export "call") (param i32) (result i32) block $exit @@ -901,7 +876,8 @@ fn wabt_example() { return ) ) - "#); + "#, + ); assert_eq!( code, vec![ diff --git a/src/validation/util.rs b/src/validation/util.rs index 69d70ac..9067f4c 100644 --- a/src/validation/util.rs +++ b/src/validation/util.rs @@ -22,9 +22,7 @@ impl<'a> Locals<'a> { for locals_group in local_groups { acc = acc .checked_add(locals_group.count()) - .ok_or_else(|| - Error(String::from("Locals range not in 32-bit range")) - )?; + .ok_or_else(|| Error(String::from("Locals range not in 32-bit range")))?; } Ok(Locals { @@ -125,9 +123,6 @@ mod tests { Local::new(u32::max_value(), ValueType::I32), Local::new(1, ValueType::I64), ]; - assert_matches!( - Locals::new(&[], &local_groups), - Err(_) - ); + assert_matches!(Locals::new(&[], &local_groups), Err(_)); } } diff --git a/tests/spec/mod.rs b/tests/spec/mod.rs index 856b26b..ea2c9e4 100644 --- a/tests/spec/mod.rs +++ b/tests/spec/mod.rs @@ -1,12 +1,12 @@ mod run; macro_rules! run_test { - ($label: expr, $test_name: ident) => ( - #[test] - fn $test_name() { - self::run::spec($label) - } - ); + ($label: expr, $test_name: ident) => { + #[test] + fn $test_name() { + self::run::spec($label) + } + }; } run_test!("address", wasm_address); diff --git a/tests/spec/run.rs b/tests/spec/run.rs index 3f69cd8..f7baa76 100644 --- a/tests/spec/run.rs +++ b/tests/spec/run.rs @@ -1,14 +1,16 @@ #![cfg(test)] -use std::fs::File; use std::collections::HashMap; +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}; +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, +}; fn spec_to_runtime_value(val: Value) -> RuntimeValue { match val { @@ -21,30 +23,30 @@ fn spec_to_runtime_value(val: Value) -> RuntimeValue { #[derive(Debug)] enum Error { - Load(String), - Start(Trap), - Script(script::Error), - Interpreter(InterpreterError), + Load(String), + Start(Trap), + Script(script::Error), + Interpreter(InterpreterError), } impl From for Error { - fn from(e: InterpreterError) -> Error { - Error::Interpreter(e) - } + fn from(e: InterpreterError) -> Error { + Error::Interpreter(e) + } } impl From for Error { - fn from(e: script::Error) -> Error { - Error::Script(e) - } + fn from(e: script::Error) -> Error { + Error::Script(e) + } } struct SpecModule { - table: TableRef, - memory: MemoryRef, - global_i32: GlobalRef, - global_f32: GlobalRef, - global_f64: GlobalRef, + table: TableRef, + memory: MemoryRef, + global_i32: GlobalRef, + global_f32: GlobalRef, + global_f64: GlobalRef, } impl SpecModule { @@ -62,27 +64,27 @@ impl SpecModule { const PRINT_FUNC_INDEX: usize = 0; impl Externals for SpecModule { - fn invoke_index( - &mut self, - index: usize, - args: RuntimeArgs, - ) -> Result, Trap> { - match index { - PRINT_FUNC_INDEX => { - println!("print: {:?}", args); - Ok(None) - } - _ => panic!("SpecModule doesn't provide function at index {}", index), - } - } + fn invoke_index( + &mut self, + index: usize, + args: RuntimeArgs, + ) -> Result, Trap> { + match index { + PRINT_FUNC_INDEX => { + println!("print: {:?}", args); + Ok(None) + } + _ => panic!("SpecModule doesn't provide function at index {}", index), + } + } } impl ModuleImportResolver for SpecModule { - fn resolve_func( - &self, - field_name: &str, - func_type: &Signature, - ) -> Result { + fn resolve_func( + &self, + field_name: &str, + func_type: &Signature, + ) -> Result { let index = match field_name { "print" => PRINT_FUNC_INDEX, "print_i32" => PRINT_FUNC_INDEX, @@ -104,15 +106,15 @@ impl ModuleImportResolver for SpecModule { )); } - let func = FuncInstance::alloc_host(func_type.clone(), index); + let func = FuncInstance::alloc_host(func_type.clone(), index); return Ok(func); - } + } - fn resolve_global( - &self, - field_name: &str, - _global_type: &GlobalDescriptor, - ) -> Result { + fn resolve_global( + &self, + field_name: &str, + _global_type: &GlobalDescriptor, + ) -> Result { match field_name { "global_i32" => Ok(self.global_i32.clone()), "global_f32" => Ok(self.global_f32.clone()), @@ -190,7 +192,8 @@ impl SpecDriver { fn module_or_last(&self, name: Option<&str>) -> Result { match name { Some(name) => self.module(name), - None => self.last_module + None => self + .last_module .clone() .ok_or_else(|| InterpreterError::Instantiation("No modules registered".into())), } @@ -301,7 +304,8 @@ fn run_action( "Expected program to have loaded module {:?}", module )); - let vec_args = args.iter() + let vec_args = args + .iter() .cloned() .map(spec_to_runtime_value) .collect::>(); @@ -322,8 +326,7 @@ fn run_action( .export_by_name(&field) .ok_or_else(|| { InterpreterError::Global(format!("Expected to have export with name {}", field)) - })? - .as_global() + })?.as_global() .cloned() .ok_or_else(|| { InterpreterError::Global(format!("Expected export {} to be a global", field)) @@ -345,9 +348,12 @@ 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()? { @@ -435,7 +441,7 @@ fn try_spec(name: &str) -> Result<(), Error> { let result = run_action(&mut spec_driver, &action); match result { Ok(result) => panic!("Expected exhaustion, got result: {:?}", result), - Err(_e) => {}, + Err(_e) => {} } } CommandKind::AssertTrap { action, .. } => { @@ -456,13 +462,13 @@ fn try_spec(name: &str) -> Result<(), Error> { let module_load = try_load(&module.into_vec(), &mut spec_driver); match module_load { Ok(_) => panic!("Expected invalid module definition, got some module!"), - Err(_e) => {}, + 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) => {}, + Err(_e) => {} } } CommandKind::Register { name, as_name, .. } => { diff --git a/tests/spec_shim.rs b/tests/spec_shim.rs index 094d833..e254b66 100644 --- a/tests/spec_shim.rs +++ b/tests/spec_shim.rs @@ -1,6 +1,6 @@ //! Official spec testsuite. -extern crate wasmi; extern crate wabt; +extern crate wasmi; mod spec;