2018-01-22 16:57:00 +00:00
|
|
|
use std::rc::{Rc, Weak};
|
2018-01-17 15:32:33 +00:00
|
|
|
use std::fmt;
|
2018-07-04 07:08:45 +00:00
|
|
|
use parity_wasm::elements::Local;
|
2018-02-06 11:14:57 +00:00
|
|
|
use {Trap, TrapKind, Signature};
|
2018-01-17 15:32:33 +00:00
|
|
|
use host::Externals;
|
2018-07-06 00:10:35 +00:00
|
|
|
use runner::{check_function_args, Interpreter, InterpreterState};
|
2018-01-17 15:32:33 +00:00
|
|
|
use value::RuntimeValue;
|
2018-07-06 00:10:35 +00:00
|
|
|
use types::ValueType;
|
2018-01-22 16:57:00 +00:00
|
|
|
use module::ModuleInstance;
|
2018-07-04 07:08:45 +00:00
|
|
|
use isa;
|
2018-01-17 15:32:33 +00:00
|
|
|
|
2018-01-26 16:24:40 +00:00
|
|
|
/// Reference to a function (See [`FuncInstance`] for details).
|
2018-01-23 16:38:49 +00:00
|
|
|
///
|
|
|
|
/// This reference has a reference-counting semantics.
|
|
|
|
///
|
|
|
|
/// [`FuncInstance`]: struct.FuncInstance.html
|
2018-01-17 15:32:33 +00:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct FuncRef(Rc<FuncInstance>);
|
|
|
|
|
2018-01-22 17:07:30 +00:00
|
|
|
impl ::std::ops::Deref for FuncRef {
|
|
|
|
type Target = FuncInstance;
|
|
|
|
fn deref(&self) -> &FuncInstance {
|
2018-01-17 15:32:33 +00:00
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-23 16:38:49 +00:00
|
|
|
/// Runtime representation of a function.
|
|
|
|
///
|
|
|
|
/// Functions are the unit of orgianization of code in WebAssembly. Each function takes a sequence of values
|
|
|
|
/// as parameters and either optionally return a value or trap.
|
2018-01-25 15:10:39 +00:00
|
|
|
/// Functions can call other function including itself (i.e recursive calls are allowed) and imported functions
|
|
|
|
/// (i.e functions defined in another module or by the host environment).
|
2018-01-23 16:38:49 +00:00
|
|
|
///
|
|
|
|
/// Functions can be defined either:
|
|
|
|
///
|
|
|
|
/// - by a wasm module,
|
|
|
|
/// - by the host environment and passed to a wasm module as an import.
|
|
|
|
/// See more in [`Externals`].
|
|
|
|
///
|
|
|
|
/// [`Externals`]: trait.Externals.html
|
2018-01-22 17:07:30 +00:00
|
|
|
pub struct FuncInstance(FuncInstanceInternal);
|
|
|
|
|
2018-01-17 15:32:33 +00:00
|
|
|
#[derive(Clone)]
|
2018-01-22 17:07:30 +00:00
|
|
|
pub(crate) enum FuncInstanceInternal {
|
2018-01-17 15:32:33 +00:00
|
|
|
Internal {
|
2018-01-18 12:48:43 +00:00
|
|
|
signature: Rc<Signature>,
|
2018-01-22 16:57:00 +00:00
|
|
|
module: Weak<ModuleInstance>,
|
2018-01-17 15:32:33 +00:00
|
|
|
body: Rc<FuncBody>,
|
|
|
|
},
|
|
|
|
Host {
|
2018-01-18 12:48:43 +00:00
|
|
|
signature: Signature,
|
2018-01-17 15:32:33 +00:00
|
|
|
host_func_index: usize,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for FuncInstance {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2018-01-22 17:07:30 +00:00
|
|
|
match self.as_internal() {
|
|
|
|
&FuncInstanceInternal::Internal {
|
2018-01-18 12:48:43 +00:00
|
|
|
ref signature,
|
2018-01-17 15:32:33 +00:00
|
|
|
..
|
|
|
|
} => {
|
2018-01-23 11:26:45 +00:00
|
|
|
// We can't write description of self.module here, because it generate
|
2018-01-18 12:48:43 +00:00
|
|
|
// debug string for function instances and this will lead to infinite loop.
|
2018-01-17 15:32:33 +00:00
|
|
|
write!(
|
|
|
|
f,
|
2018-01-18 12:48:43 +00:00
|
|
|
"Internal {{ signature={:?} }}",
|
|
|
|
signature,
|
2018-01-17 15:32:33 +00:00
|
|
|
)
|
|
|
|
}
|
2018-01-22 17:07:30 +00:00
|
|
|
&FuncInstanceInternal::Host { ref signature, .. } => {
|
2018-01-18 12:48:43 +00:00
|
|
|
write!(f, "Host {{ signature={:?} }}", signature)
|
2018-01-17 15:32:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FuncInstance {
|
2018-01-26 16:24:40 +00:00
|
|
|
/// Allocate a function instance for a host function.
|
|
|
|
///
|
|
|
|
/// When this function instance will be called by the wasm code,
|
|
|
|
/// the instance of [`Externals`] will be invoked by calling `invoke_index`
|
|
|
|
/// with specified `host_func_index` here.
|
|
|
|
/// This call will be made with the `signature` provided here.
|
|
|
|
///
|
|
|
|
/// [`Externals`]: trait.Externals.html
|
2018-01-22 17:07:30 +00:00
|
|
|
pub fn alloc_host(signature: Signature, host_func_index: usize) -> FuncRef {
|
|
|
|
let func = FuncInstanceInternal::Host {
|
|
|
|
signature,
|
|
|
|
host_func_index,
|
|
|
|
};
|
|
|
|
FuncRef(Rc::new(FuncInstance(func)))
|
|
|
|
}
|
|
|
|
|
2018-01-26 16:24:40 +00:00
|
|
|
/// Returns [signature] of this function instance.
|
|
|
|
///
|
|
|
|
/// This function instance can only be called with matching signatures.
|
|
|
|
///
|
|
|
|
/// [signature]: struct.Signature.html
|
|
|
|
pub fn signature(&self) -> &Signature {
|
|
|
|
match *self.as_internal() {
|
|
|
|
FuncInstanceInternal::Internal { ref signature, .. } => signature,
|
|
|
|
FuncInstanceInternal::Host { ref signature, .. } => signature,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-22 17:07:30 +00:00
|
|
|
pub(crate) fn as_internal(&self) -> &FuncInstanceInternal {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
|
2018-01-17 15:32:33 +00:00
|
|
|
pub(crate) fn alloc_internal(
|
2018-01-22 16:57:00 +00:00
|
|
|
module: Weak<ModuleInstance>,
|
2018-01-18 12:48:43 +00:00
|
|
|
signature: Rc<Signature>,
|
2018-01-17 15:32:33 +00:00
|
|
|
body: FuncBody,
|
|
|
|
) -> FuncRef {
|
2018-01-22 17:07:30 +00:00
|
|
|
let func = FuncInstanceInternal::Internal {
|
2018-01-18 12:48:43 +00:00
|
|
|
signature,
|
2018-01-17 15:32:33 +00:00
|
|
|
module: module,
|
|
|
|
body: Rc::new(body),
|
|
|
|
};
|
2018-01-22 17:07:30 +00:00
|
|
|
FuncRef(Rc::new(FuncInstance(func)))
|
2018-01-17 15:32:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn body(&self) -> Option<Rc<FuncBody>> {
|
2018-01-22 17:07:30 +00:00
|
|
|
match *self.as_internal() {
|
|
|
|
FuncInstanceInternal::Internal { ref body, .. } => Some(Rc::clone(body)),
|
|
|
|
FuncInstanceInternal::Host { .. } => None,
|
2018-01-17 15:32:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-06 11:14:57 +00:00
|
|
|
/// 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>(
|
2018-01-23 15:12:41 +00:00
|
|
|
func: &FuncRef,
|
|
|
|
args: &[RuntimeValue],
|
2018-01-17 15:32:33 +00:00
|
|
|
externals: &mut E,
|
2018-02-01 11:59:21 +00:00
|
|
|
) -> Result<Option<RuntimeValue>, Trap> {
|
2018-02-06 11:14:57 +00:00
|
|
|
check_function_args(func.signature(), &args).map_err(|_| TrapKind::UnexpectedSignature)?;
|
2018-02-01 11:59:21 +00:00
|
|
|
match *func.as_internal() {
|
|
|
|
FuncInstanceInternal::Internal { .. } => {
|
2018-07-09 10:27:34 +00:00
|
|
|
let mut interpreter = Interpreter::new(func, args)?;
|
|
|
|
interpreter.start_execution(externals)
|
2018-01-17 15:32:33 +00:00
|
|
|
}
|
2018-02-06 11:14:57 +00:00
|
|
|
FuncInstanceInternal::Host {
|
|
|
|
ref host_func_index,
|
|
|
|
..
|
|
|
|
} => externals.invoke_index(*host_func_index, args.into()),
|
2018-01-17 15:32:33 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-06 00:10:35 +00:00
|
|
|
|
|
|
|
/// Invoke the function, get a resumable handle. This handle can then be used to actually start the execution. If a
|
|
|
|
/// Host trap happens, caller can use `resume_execution` to feed the expected return value back in, and then
|
|
|
|
/// continue the execution.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// Returns `Err` if `args` types is not match function [`signature`].
|
|
|
|
///
|
|
|
|
/// [`signature`]: #method.signature
|
|
|
|
/// [`Trap`]: #enum.Trap.html
|
2018-07-09 10:27:34 +00:00
|
|
|
pub fn invoke_resumable<'args>(
|
2018-07-06 00:10:35 +00:00
|
|
|
func: &FuncRef,
|
|
|
|
args: &'args [RuntimeValue],
|
2018-07-09 10:27:34 +00:00
|
|
|
) -> Result<FuncInvocation<'args>, Trap> {
|
2018-07-06 00:10:35 +00:00
|
|
|
check_function_args(func.signature(), &args).map_err(|_| TrapKind::UnexpectedSignature)?;
|
|
|
|
match *func.as_internal() {
|
|
|
|
FuncInstanceInternal::Internal { .. } => {
|
2018-07-09 10:27:34 +00:00
|
|
|
let interpreter = Interpreter::new(func, args)?;
|
2018-07-06 00:10:35 +00:00
|
|
|
Ok(FuncInvocation {
|
|
|
|
kind: FuncInvocationKind::Internal(interpreter),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
FuncInstanceInternal::Host {
|
|
|
|
ref host_func_index,
|
|
|
|
..
|
|
|
|
} => {
|
|
|
|
Ok(FuncInvocation {
|
|
|
|
kind: FuncInvocationKind::Host {
|
2018-07-09 10:27:34 +00:00
|
|
|
args,
|
2018-07-06 00:10:35 +00:00
|
|
|
host_func_index: *host_func_index,
|
|
|
|
finished: false,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A resumable invocation error.
|
2018-07-09 10:27:34 +00:00
|
|
|
#[derive(Debug)]
|
2018-07-06 00:10:35 +00:00
|
|
|
pub enum ResumableError {
|
|
|
|
/// Trap happened.
|
|
|
|
Trap(Trap),
|
|
|
|
/// The invocation is not resumable.
|
|
|
|
NotResumable,
|
|
|
|
/// The invocation has already been started.
|
|
|
|
AlreadyStarted,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Trap> for ResumableError {
|
|
|
|
fn from(trap: Trap) -> Self {
|
|
|
|
ResumableError::Trap(trap)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-06 00:22:23 +00:00
|
|
|
/// A resumable invocation handle. This struct is returned by `FuncInstance::invoke_resumable`.
|
2018-07-09 10:27:34 +00:00
|
|
|
pub struct FuncInvocation<'args> {
|
|
|
|
kind: FuncInvocationKind<'args>,
|
2018-07-06 00:10:35 +00:00
|
|
|
}
|
|
|
|
|
2018-07-09 10:27:34 +00:00
|
|
|
enum FuncInvocationKind<'args> {
|
|
|
|
Internal(Interpreter),
|
2018-07-06 00:10:35 +00:00
|
|
|
Host {
|
|
|
|
args: &'args [RuntimeValue],
|
|
|
|
host_func_index: usize,
|
|
|
|
finished: bool
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2018-07-09 10:27:34 +00:00
|
|
|
impl<'args> FuncInvocation<'args> {
|
2018-07-06 00:10:35 +00:00
|
|
|
/// Whether this invocation is currently resumable.
|
|
|
|
pub fn is_resumable(&self) -> bool {
|
|
|
|
match &self.kind {
|
|
|
|
&FuncInvocationKind::Internal(ref interpreter) => interpreter.state().is_resumable(),
|
|
|
|
&FuncInvocationKind::Host { .. } => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If the invocation is resumable, the expected return value type to be feed back in.
|
|
|
|
pub fn resumable_value_type(&self) -> Option<ValueType> {
|
|
|
|
match &self.kind {
|
|
|
|
&FuncInvocationKind::Internal(ref interpreter) => {
|
|
|
|
match interpreter.state() {
|
|
|
|
&InterpreterState::Resumable(ref value_type) => value_type.clone(),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
&FuncInvocationKind::Host { .. } => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Start the invocation execution.
|
2018-07-09 10:27:34 +00:00
|
|
|
pub fn start_execution<'externals, E: Externals + 'externals>(&mut self, externals: &'externals mut E) -> Result<Option<RuntimeValue>, ResumableError> {
|
2018-07-06 00:10:35 +00:00
|
|
|
match self.kind {
|
|
|
|
FuncInvocationKind::Internal(ref mut interpreter) => {
|
|
|
|
if interpreter.state() != &InterpreterState::Initialized {
|
|
|
|
return Err(ResumableError::AlreadyStarted);
|
|
|
|
}
|
2018-07-09 10:27:34 +00:00
|
|
|
Ok(interpreter.start_execution(externals)?)
|
2018-07-06 00:10:35 +00:00
|
|
|
},
|
2018-07-09 10:27:34 +00:00
|
|
|
FuncInvocationKind::Host { ref args, ref mut finished, ref host_func_index } => {
|
2018-07-06 00:10:35 +00:00
|
|
|
if *finished {
|
|
|
|
return Err(ResumableError::AlreadyStarted);
|
|
|
|
}
|
|
|
|
*finished = true;
|
|
|
|
Ok(externals.invoke_index(*host_func_index, args.clone().into())?)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Resume an execution if a previous trap of Host kind happened.
|
2018-07-09 10:27:34 +00:00
|
|
|
pub fn resume_execution<'externals, E: Externals + 'externals>(&mut self, return_val: Option<RuntimeValue>, externals: &'externals mut E) -> Result<Option<RuntimeValue>, ResumableError> {
|
2018-07-06 00:10:35 +00:00
|
|
|
match self.kind {
|
|
|
|
FuncInvocationKind::Internal(ref mut interpreter) => {
|
|
|
|
if !interpreter.state().is_resumable() {
|
|
|
|
return Err(ResumableError::AlreadyStarted);
|
|
|
|
}
|
2018-07-09 10:27:34 +00:00
|
|
|
Ok(interpreter.resume_execution(return_val, externals)?)
|
2018-07-06 00:10:35 +00:00
|
|
|
},
|
|
|
|
FuncInvocationKind::Host { .. } => {
|
|
|
|
return Err(ResumableError::NotResumable);
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct FuncBody {
|
|
|
|
pub locals: Vec<Local>,
|
2018-07-04 07:08:45 +00:00
|
|
|
pub code: isa::Instructions,
|
2018-01-17 15:32:33 +00:00
|
|
|
}
|