move invoke into Interpreter

This commit is contained in:
Andrew Dirksen 2018-11-21 16:58:33 -08:00
parent 0498125070
commit 07267813db
4 changed files with 55 additions and 68 deletions

View File

@ -1,7 +1,7 @@
use std::error; use std::error;
use std::fs::File; use std::fs::File;
use test::Bencher; use test::Bencher;
use wasmi::{FuncInstance, ImportsBuilder, Interpreter, Module, ModuleInstance, NopExternals, RuntimeValue}; use wasmi::{ImportsBuilder, Interpreter, Module, ModuleInstance, NopExternals, RuntimeValue};
// Load a module from a file. // Load a module from a file.
fn load_from_file(filename: &str) -> Result<Module, Box<error::Error>> { fn load_from_file(filename: &str) -> Result<Module, Box<error::Error>> {
@ -39,7 +39,7 @@ fn bench_tiny_keccak(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
interpreter.reset(); interpreter.reset();
FuncInstance::invoke_configurable(&func, &[test_data_ptr], &mut NopExternals, &mut interpreter).unwrap() interpreter.invoke(&func, &[test_data_ptr], &mut NopExternals).unwrap()
}); });
} }
@ -85,7 +85,7 @@ fn bench_rev_comp(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
interpreter.reset(); interpreter.reset();
FuncInstance::invoke_configurable(&func, &[test_data_ptr], &mut NopExternals, &mut interpreter).unwrap() interpreter.invoke(&func, &[test_data_ptr], &mut NopExternals).unwrap()
}); });
// Verify the result. // Verify the result.
@ -142,7 +142,7 @@ fn bench_regex_redux(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
interpreter.reset(); interpreter.reset();
FuncInstance::invoke_configurable(&func, &[test_data_ptr], &mut NopExternals, &mut interpreter).unwrap() interpreter.invoke(&func, &[test_data_ptr], &mut NopExternals).unwrap()
}); });
} }
@ -174,9 +174,9 @@ fn fac_recursive(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
interpreter.reset(); interpreter.reset();
let value = let value = interpreter
FuncInstance::invoke_configurable(&func, &[RuntimeValue::I64(25)], &mut NopExternals, &mut interpreter) .invoke(&func, &[RuntimeValue::I64(25)], &mut NopExternals)
.unwrap(); .unwrap();
assert_matches!(value, Some(RuntimeValue::I64(7034535277573963776))); assert_matches!(value, Some(RuntimeValue::I64(7034535277573963776)));
}); });
} }
@ -214,9 +214,9 @@ fn fac_opt(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
interpreter.reset(); interpreter.reset();
let value = let value = interpreter
FuncInstance::invoke_configurable(&func, &[RuntimeValue::I64(25)], &mut NopExternals, &mut interpreter) .invoke(&func, &[RuntimeValue::I64(25)], &mut NopExternals)
.unwrap(); .unwrap();
assert_matches!(value, Some(RuntimeValue::I64(7034535277573963776))); assert_matches!(value, Some(RuntimeValue::I64(7034535277573963776)));
}); });
} }
@ -255,9 +255,9 @@ fn recursive_ok(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
interpreter.reset(); interpreter.reset();
let value = let value = interpreter
FuncInstance::invoke_configurable(&func, &[RuntimeValue::I32(8000)], &mut NopExternals, &mut interpreter) .invoke(&func, &[RuntimeValue::I32(8000)], &mut NopExternals)
.unwrap(); .unwrap();
assert_matches!(value, Some(RuntimeValue::I32(0))); assert_matches!(value, Some(RuntimeValue::I32(0)));
}); });
} }
@ -295,7 +295,8 @@ fn recursive_trap(b: &mut Bencher) {
b.iter(|| { b.iter(|| {
interpreter.reset(); interpreter.reset();
FuncInstance::invoke_configurable(&func, &[RuntimeValue::I32(1000)], &mut NopExternals, &mut interpreter) interpreter
.invoke(&func, &[RuntimeValue::I32(1000)], &mut NopExternals)
.unwrap_err(); .unwrap_err();
}); });
} }

View File

@ -6,7 +6,7 @@ use host::Externals;
use isa; use isa;
use module::ModuleInstance; use module::ModuleInstance;
use parity_wasm::elements::Local; use parity_wasm::elements::Local;
use runner::{check_function_args, Interpreter, InterpreterState}; use runner::{Interpreter, InterpreterState};
use types::ValueType; use types::ValueType;
use value::RuntimeValue; use value::RuntimeValue;
use {Signature, Trap}; use {Signature, Trap};
@ -117,50 +117,6 @@ impl FuncInstance {
} }
} }
/// Invoke this function with extra configuration parameters.
///
/// This is an experimental API
///
/// # Errors
///
/// Returns `Err` if `args` types is not match function [`signature`] or
/// if [`Trap`] at execution time occured.
///
/// [`signature`]: #method.signature
/// [`Trap`]: #enum.Trap.html
pub fn invoke_configurable<E: Externals>(
func: &FuncRef,
args: &[RuntimeValue],
externals: &mut E,
interpreter: &mut Interpreter,
) -> Result<Option<RuntimeValue>, Trap> {
check_function_args(func.signature(), &args)?;
match *func.as_internal() {
FuncInstanceInternal::Internal { .. } => interpreter.start_execution(externals, func, args),
FuncInstanceInternal::Host {
ref host_func_index, ..
} => externals.invoke_index(*host_func_index, args.into()),
}
}
/// Invoke this function.
///
/// # Errors
///
/// Returns `Err` if `args` types is not match function [`signature`] or
/// if [`Trap`] at execution time occured.
///
/// [`signature`]: #method.signature
/// [`Trap`]: #enum.Trap.html
pub fn invoke<E: Externals>(
func: &FuncRef,
args: &[RuntimeValue],
externals: &mut E,
) -> Result<Option<RuntimeValue>, Trap> {
let mut interpreter = Interpreter::new();
Self::invoke_configurable(func, args, externals, &mut interpreter)
}
/// Invoke the function, get a resumable handle. This handle can then be used to [`start_execution`]. If a /// Invoke the function, get a resumable handle. This handle can then be used to [`start_execution`]. If a
/// Host trap happens, caller can use [`resume_execution`] to feed the expected return value back in, and then /// Host trap happens, caller can use [`resume_execution`] to feed the expected return value back in, and then
/// continue the execution. /// continue the execution.
@ -267,7 +223,7 @@ impl FuncInvocation {
if interpreter.state() != &InterpreterState::Initialized { if interpreter.state() != &InterpreterState::Initialized {
return Err(ResumableError::AlreadyStarted); return Err(ResumableError::AlreadyStarted);
} }
Ok(interpreter.start_execution(externals, func, args)?) Ok(interpreter.start_execution(func, args, externals)?)
} }
FuncInvocationKind::Host { FuncInvocationKind::Host {
ref mut finished, ref mut finished,

View File

@ -21,6 +21,7 @@ use host::Externals;
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
use types::{GlobalDescriptor, TableDescriptor, MemoryDescriptor}; use types::{GlobalDescriptor, TableDescriptor, MemoryDescriptor};
use memory_units::Pages; use memory_units::Pages;
use runner::Interpreter;
/// Reference to a [`ModuleInstance`]. /// Reference to a [`ModuleInstance`].
/// ///
@ -629,7 +630,7 @@ impl ModuleInstance {
} }
}; };
FuncInstance::invoke(&func_instance, args, externals) Interpreter::new().invoke(&func_instance, args, externals)
.map_err(|t| Error::Trap(t)) .map_err(|t| Error::Trap(t))
} }
@ -688,7 +689,7 @@ impl<'a> NotStartedModuleRef<'a> {
let start_func = self.instance.func_by_index(start_fn_idx).expect( let start_func = self.instance.func_by_index(start_fn_idx).expect(
"Due to validation start function should exists", "Due to validation start function should exists",
); );
FuncInstance::invoke(&start_func, &[], state)?; Interpreter::new().invoke(&start_func, &[], state)?;
} }
Ok(self.instance) Ok(self.instance)
} }

View File

@ -5,8 +5,8 @@ use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
use core::fmt; use core::fmt;
use core::ops; use core::ops;
use core::{u32, usize}; use core::{u32, usize};
use func::{FuncInstance, FuncInstanceInternal, FuncRef}; use func::{FuncInstanceInternal, FuncRef};
use host::Externals; use host::{Externals, RuntimeArgs};
use isa; use isa;
use memory::MemoryRef; use memory::MemoryRef;
use memory_units::Pages; use memory_units::Pages;
@ -222,11 +222,35 @@ impl Interpreter {
&self.state &self.state
} }
pub(crate) fn start_execution<E: Externals>( /// Run func using this interpreter.
///
/// # Errors
///
/// Returns `Err` if `args` types is not match function [`signature`] or
/// if [`Trap`] at execution time occured.
///
/// [`signature`]: #method.signature
/// [`Trap`]: #enum.Trap.html
pub fn invoke<E: Externals>(
&mut self, &mut self,
externals: &mut E,
func: &FuncRef, func: &FuncRef,
args: &[RuntimeValue], args: &[RuntimeValue],
externals: &mut E,
) -> Result<Option<RuntimeValue>, Trap> {
check_function_args(func.signature(), &args)?;
match *func.as_internal() {
FuncInstanceInternal::Internal { .. } => self.start_execution(func, args, externals),
FuncInstanceInternal::Host {
ref host_func_index, ..
} => externals.invoke_index(*host_func_index, args.into()),
}
}
pub(crate) fn start_execution<E: Externals>(
&mut self,
func: &FuncRef,
args: &[RuntimeValue],
externals: &mut E,
) -> Result<Option<RuntimeValue>, Trap> { ) -> Result<Option<RuntimeValue>, Trap> {
// Ensure that the VM has not been executed. This is checked in `FuncInvocation::start_execution`. // Ensure that the VM has not been executed. This is checked in `FuncInvocation::start_execution`.
assert!(self.state == InterpreterState::Initialized); assert!(self.state == InterpreterState::Initialized);
@ -318,12 +342,17 @@ impl Interpreter {
self.call_stack.push(function_context)?; self.call_stack.push(function_context)?;
self.call_stack.push(nested_context)?; self.call_stack.push(nested_context)?;
} }
FuncInstanceInternal::Host { ref signature, .. } => { FuncInstanceInternal::Host {
ref signature,
host_func_index,
} => {
let args = prepare_function_args(signature, &mut self.value_stack); let args = prepare_function_args(signature, &mut self.value_stack);
// We push the function context first. If the VM is not resumable, it does no harm. If it is, we then save the context here. // We push the function context first. If the VM is not resumable, it does no harm. If it is, we then save the context here.
self.call_stack.push(function_context)?; self.call_stack.push(function_context)?;
let return_val = match FuncInstance::invoke(&nested_func, &args, externals) { let return_val = match externals
.invoke_index(host_func_index, RuntimeArgs::from(args.as_ref()))
{
Ok(val) => val, Ok(val) => val,
Err(trap) => { Err(trap) => {
if trap.kind().is_host() { if trap.kind().is_host() {