diff --git a/lib/execute/src/action.rs b/lib/execute/src/action.rs new file mode 100644 index 0000000000..7ec3e27da7 --- /dev/null +++ b/lib/execute/src/action.rs @@ -0,0 +1,77 @@ +//! Support for performing actions with a wasm module from the outside. + +use cranelift_codegen::ir; +use std::string::String; +use std::vec::Vec; + +/// A runtime value. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Value { + /// A runtime value with type i32. + I32(i32), + /// A runtime value with type i64. + I64(i64), + /// A runtime value with type f32. + F32(u32), + /// A runtime value with type f64. + F64(u64), +} + +impl Value { + /// Return the type of this `Value`. + pub fn value_type(self) -> ir::Type { + match self { + Value::I32(_) => ir::types::I32, + Value::I64(_) => ir::types::I64, + Value::F32(_) => ir::types::F32, + Value::F64(_) => ir::types::F64, + } + } + + /// Assuming this `Value` holds an `i32`, return that value. + pub fn unwrap_i32(self) -> i32 { + match self { + Value::I32(x) => x, + _ => panic!("unwrapping value of type {} as i32", self.value_type()), + } + } + + /// Assuming this `Value` holds an `i64`, return that value. + pub fn unwrap_i64(self) -> i64 { + match self { + Value::I64(x) => x, + _ => panic!("unwrapping value of type {} as i64", self.value_type()), + } + } + + /// Assuming this `Value` holds an `f32`, return that value. + pub fn unwrap_f32(self) -> u32 { + match self { + Value::F32(x) => x, + _ => panic!("unwrapping value of type {} as f32", self.value_type()), + } + } + + /// Assuming this `Value` holds an `f64`, return that value. + pub fn unwrap_f64(self) -> u64 { + match self { + Value::F64(x) => x, + _ => panic!("unwrapping value of type {} as f64", self.value_type()), + } + } +} + +/// The result of invoking a wasm function or reading a wasm global. +#[derive(Debug)] +pub enum ActionOutcome { + /// The action returned normally. Its return values are provided. + Returned { + /// The return values. + values: Vec, + }, + /// A trap occurred while the action was executing. + Trapped { + /// The trap message. + message: String, + }, +} diff --git a/lib/execute/src/execute.rs b/lib/execute/src/execute.rs index 06d196a47b..13ebe191bd 100644 --- a/lib/execute/src/execute.rs +++ b/lib/execute/src/execute.rs @@ -1,6 +1,7 @@ //! TODO: Move the contents of this file to other files, as "execute.rs" is //! no longer a descriptive filename. +use action::ActionOutcome; use code::Code; use cranelift_codegen::binemit::Reloc; use cranelift_codegen::isa::TargetIsa; @@ -10,7 +11,7 @@ use cranelift_wasm::{ }; use export::{ExportValue, Resolver}; use instance::Instance; -use invoke::{invoke_by_index, InvokeOutcome}; +use invoke::invoke_by_index; use region::{protect, Protection}; use std::ptr::write_unaligned; use std::string::String; @@ -378,10 +379,10 @@ pub fn finish_instantiation( let vmctx = instance.vmctx(); let result = invoke_by_index(code, isa, module, compilation, vmctx, start_index, &[])?; match result { - InvokeOutcome::Returned { values } => { + ActionOutcome::Returned { values } => { assert!(values.is_empty()); } - InvokeOutcome::Trapped { message } => { + ActionOutcome::Trapped { message } => { return Err(format!("start function trapped: {}", message)); } } diff --git a/lib/execute/src/get.rs b/lib/execute/src/get.rs index 6d4014a06f..dab34a029c 100644 --- a/lib/execute/src/get.rs +++ b/lib/execute/src/get.rs @@ -1,8 +1,8 @@ //! Support for reading the value of a wasm global from outside the module. +use action::Value; use cranelift_codegen::ir; use cranelift_wasm::GlobalIndex; -use invoke::Value; use std::string::String; use vmcontext::VMContext; use wasmtime_environ::{Export, Module}; diff --git a/lib/execute/src/invoke.rs b/lib/execute/src/invoke.rs index 6f286f8aa6..0a3be0da14 100644 --- a/lib/execute/src/invoke.rs +++ b/lib/execute/src/invoke.rs @@ -1,5 +1,6 @@ //! Support for invoking wasm functions from outside a wasm module. +use action::{ActionOutcome, Value}; use code::Code; use cranelift_codegen::ir::InstBuilder; use cranelift_codegen::{binemit, ir, isa, Context}; @@ -14,78 +15,6 @@ use traphandlers::call_wasm; use vmcontext::VMContext; use wasmtime_environ::{Compilation, Export, Module, RelocSink}; -/// A runtime value. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum Value { - /// A runtime value with type i32. - I32(i32), - /// A runtime value with type i64. - I64(i64), - /// A runtime value with type f32. - F32(u32), - /// A runtime value with type f64. - F64(u64), -} - -impl Value { - /// Return the type of this `Value`. - pub fn value_type(self) -> ir::Type { - match self { - Value::I32(_) => ir::types::I32, - Value::I64(_) => ir::types::I64, - Value::F32(_) => ir::types::F32, - Value::F64(_) => ir::types::F64, - } - } - - /// Assuming this `Value` holds an `i32`, return that value. - pub fn unwrap_i32(self) -> i32 { - match self { - Value::I32(x) => x, - _ => panic!("unwrapping value of type {} as i32", self.value_type()), - } - } - - /// Assuming this `Value` holds an `i64`, return that value. - pub fn unwrap_i64(self) -> i64 { - match self { - Value::I64(x) => x, - _ => panic!("unwrapping value of type {} as i64", self.value_type()), - } - } - - /// Assuming this `Value` holds an `f32`, return that value. - pub fn unwrap_f32(self) -> u32 { - match self { - Value::F32(x) => x, - _ => panic!("unwrapping value of type {} as f32", self.value_type()), - } - } - - /// Assuming this `Value` holds an `f64`, return that value. - pub fn unwrap_f64(self) -> u64 { - match self { - Value::F64(x) => x, - _ => panic!("unwrapping value of type {} as f64", self.value_type()), - } - } -} - -/// The result of invoking a wasm function. -#[derive(Debug)] -pub enum InvokeOutcome { - /// The function returned normally. Its return values are provided. - Returned { - /// The return values. - values: Vec, - }, - /// A trap occurred while the function was executing. - Trapped { - /// The trap message. - message: String, - }, -} - /// Jumps to the code region of memory and invoke the exported function pub fn invoke( code: &mut Code, @@ -95,7 +24,7 @@ pub fn invoke( vmctx: *mut VMContext, function: &str, args: &[Value], -) -> Result { +) -> Result { let fn_index = match module.exports.get(function) { Some(Export::Function(index)) => *index, Some(_) => return Err(format!("exported item \"{}\" is not a function", function)), @@ -113,7 +42,7 @@ pub fn invoke_by_index( vmctx: *mut VMContext, fn_index: FuncIndex, args: &[Value], -) -> Result { +) -> Result { // TODO: Return Err if fn_index is out of bounds. let exec_code_buf = match module.defined_func_index(fn_index) { Some(def_fn_index) => { @@ -152,7 +81,7 @@ fn call_through_wrapper( vmctx: *mut VMContext, args: &[Value], sig: &ir::Signature, -) -> Result { +) -> Result { for (index, value) in args.iter().enumerate() { assert_eq!(value.value_type(), sig.params[index].value_type); } @@ -261,8 +190,8 @@ fn call_through_wrapper( values.push(v); } - InvokeOutcome::Returned { values } + ActionOutcome::Returned { values } } - Err(message) => InvokeOutcome::Trapped { message }, + Err(message) => ActionOutcome::Trapped { message }, }) } diff --git a/lib/execute/src/lib.rs b/lib/execute/src/lib.rs index 4b89f1f76f..3e6c62393b 100644 --- a/lib/execute/src/lib.rs +++ b/lib/execute/src/lib.rs @@ -41,6 +41,7 @@ extern crate libc; extern crate memoffset; extern crate cast; +mod action; mod code; mod execute; mod export; @@ -57,12 +58,13 @@ mod traphandlers; mod vmcontext; mod world; +pub use action::{ActionOutcome, Value}; pub use code::Code; pub use execute::{compile_and_link_module, finish_instantiation}; pub use export::{ExportValue, NullResolver, Resolver}; pub use get::get; pub use instance::Instance; -pub use invoke::{invoke, InvokeOutcome, Value}; +pub use invoke::invoke; pub use traphandlers::{call_wasm, LookupCodeSegment, RecordTrap, Unwind}; pub use vmcontext::{VMContext, VMGlobal, VMMemory, VMTable}; pub use world::InstanceWorld; diff --git a/lib/execute/src/world.rs b/lib/execute/src/world.rs index 47d9854a9f..e0eb300767 100644 --- a/lib/execute/src/world.rs +++ b/lib/execute/src/world.rs @@ -1,13 +1,15 @@ +use action::{ActionOutcome, Value}; +use code::Code; use cranelift_codegen::isa; use cranelift_wasm::{GlobalIndex, MemoryIndex}; +use execute::{compile_and_link_module, finish_instantiation}; use export::Resolver; +use get::get; +use instance::Instance; +use invoke::invoke; use std::str; use vmcontext::VMGlobal; use wasmtime_environ::{Compilation, Module, ModuleEnvironment, Tunables}; -use { - compile_and_link_module, finish_instantiation, get, invoke, Code, Instance, InvokeOutcome, - Value, -}; /// A module, an instance of that module, and accompanying compilation artifacts. /// @@ -62,7 +64,7 @@ impl InstanceWorld { isa: &isa::TargetIsa, function_name: &str, args: &[Value], - ) -> Result { + ) -> Result { invoke( code, isa, diff --git a/lib/wast/src/wast.rs b/lib/wast/src/wast.rs index 58e77b6962..067d0fc686 100644 --- a/lib/wast/src/wast.rs +++ b/lib/wast/src/wast.rs @@ -7,7 +7,7 @@ use std::io::Read; use std::path::Path; use std::str; use wabt::script::{self, Action, Command, CommandKind, ModuleBinary, ScriptParser}; -use wasmtime_execute::{Code, InstanceWorld, InvokeOutcome, Value}; +use wasmtime_execute::{ActionOutcome, Code, InstanceWorld, Value}; struct Instances { current: Option, @@ -44,8 +44,7 @@ impl Instances { self.namespace.insert(name, world); } - // fixme: Rename InvokeOutcome to ActionOutcome. - pub fn perform_action(&mut self, isa: &isa::TargetIsa, action: Action) -> InvokeOutcome { + pub fn perform_action(&mut self, isa: &isa::TargetIsa, action: Action) -> ActionOutcome { match action { Action::Invoke { module, @@ -91,7 +90,7 @@ impl Instances { .get(&field) .expect(&format!("error getting {} in module {}", field, name)), }; - InvokeOutcome::Returned { + ActionOutcome::Returned { values: vec![value], } } @@ -114,14 +113,14 @@ pub fn wast_buffer(name: &str, isa: &isa::TargetIsa, wast: &[u8]) { instances.define_unnamed_module(&*isa, module) } CommandKind::PerformAction(action) => match instances.perform_action(&*isa, action) { - InvokeOutcome::Returned { .. } => {} - InvokeOutcome::Trapped { message } => { + ActionOutcome::Returned { .. } => {} + ActionOutcome::Trapped { message } => { panic!("{}:{}: a trap occurred: {}", name, line, message); } }, CommandKind::AssertReturn { action, expected } => { match instances.perform_action(&*isa, action) { - InvokeOutcome::Returned { values } => { + ActionOutcome::Returned { values } => { for (v, e) in values.iter().zip(expected.iter()) { match *e { script::Value::I32(x) => { @@ -139,7 +138,7 @@ pub fn wast_buffer(name: &str, isa: &isa::TargetIsa, wast: &[u8]) { }; } } - InvokeOutcome::Trapped { message } => { + ActionOutcome::Trapped { message } => { panic!( "{}:{}: expected normal return, but a trap occurred: {}", name, line, message @@ -149,11 +148,11 @@ pub fn wast_buffer(name: &str, isa: &isa::TargetIsa, wast: &[u8]) { } CommandKind::AssertTrap { action, message } => { match instances.perform_action(&*isa, action) { - InvokeOutcome::Returned { values } => panic!( + ActionOutcome::Returned { values } => panic!( "{}:{}: expected trap, but invoke returned with {:?}", name, line, values ), - InvokeOutcome::Trapped { + ActionOutcome::Trapped { message: trap_message, } => { println!( @@ -165,11 +164,11 @@ pub fn wast_buffer(name: &str, isa: &isa::TargetIsa, wast: &[u8]) { } CommandKind::AssertExhaustion { action } => { match instances.perform_action(&*isa, action) { - InvokeOutcome::Returned { values } => panic!( + ActionOutcome::Returned { values } => panic!( "{}:{}: expected exhaustion, but invoke returned with {:?}", name, line, values ), - InvokeOutcome::Trapped { message } => { + ActionOutcome::Trapped { message } => { println!( "{}:{}: TODO: Check the exhaustion message: {}", name, line, message @@ -179,7 +178,7 @@ pub fn wast_buffer(name: &str, isa: &isa::TargetIsa, wast: &[u8]) { } CommandKind::AssertReturnCanonicalNan { action } => { match instances.perform_action(&*isa, action) { - InvokeOutcome::Returned { values } => { + ActionOutcome::Returned { values } => { for v in values.iter() { match v { Value::I32(_) | Value::I64(_) => { @@ -202,7 +201,7 @@ pub fn wast_buffer(name: &str, isa: &isa::TargetIsa, wast: &[u8]) { }; } } - InvokeOutcome::Trapped { message } => { + ActionOutcome::Trapped { message } => { panic!( "{}:{}: expected canonical NaN return, but a trap occurred: {}", name, line, message @@ -212,7 +211,7 @@ pub fn wast_buffer(name: &str, isa: &isa::TargetIsa, wast: &[u8]) { } CommandKind::AssertReturnArithmeticNan { action } => { match instances.perform_action(&*isa, action) { - InvokeOutcome::Returned { values } => { + ActionOutcome::Returned { values } => { for v in values.iter() { match v { Value::I32(_) | Value::I64(_) => { @@ -235,7 +234,7 @@ pub fn wast_buffer(name: &str, isa: &isa::TargetIsa, wast: &[u8]) { }; } } - InvokeOutcome::Trapped { message } => { + ActionOutcome::Trapped { message } => { panic!( "{}:{}: expected canonical NaN return, but a trap occurred: {}", name, line, message