2018-10-29 10:16:55 +00:00
#[ allow(unused_imports) ]
use alloc ::prelude ::* ;
use alloc ::rc ::{ Rc , Weak } ;
use core ::fmt ;
2018-07-04 07:08:45 +00:00
use parity_wasm ::elements ::Local ;
2018-10-29 17:29:46 +00:00
use { Trap , Signature } ;
2018-01-17 15:32:33 +00:00
use host ::Externals ;
2018-07-09 16:06:44 +00:00
use runner ::{ check_function_args , Interpreter , InterpreterState } ;
2018-01-17 15:32:33 +00:00
use value ::RuntimeValue ;
2018-07-09 16:06:44 +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-10-29 10:16:55 +00:00
impl ::core ::ops ::Deref for FuncRef {
2018-01-22 17:07:30 +00:00
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.
///
2018-08-03 13:05:10 +00:00
/// Functions are the unit of organization of code in WebAssembly. Each function takes a sequence of values
2018-01-23 16:38:49 +00:00
/// 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-10-29 17:29:46 +00:00
check_function_args ( func . signature ( ) , & args ) ? ;
2018-02-01 11:59:21 +00:00
match * func . as_internal ( ) {
FuncInstanceInternal ::Internal { .. } = > {
2018-07-09 16:06:44 +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-09 16:06:44 +00:00
/// 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
/// continue the execution.
///
/// This is an experimental API, and this functionality may not be available in other WebAssembly engines.
///
/// # Errors
///
/// Returns `Err` if `args` types is not match function [`signature`].
///
/// [`signature`]: #method.signature
/// [`Trap`]: #enum.Trap.html
/// [`start_execution`]: struct.FuncInvocation.html#method.start_execution
/// [`resume_execution`]: struct.FuncInvocation.html#method.resume_execution
pub fn invoke_resumable < ' args > (
func : & FuncRef ,
args : & ' args [ RuntimeValue ] ,
) -> Result < FuncInvocation < ' args > , Trap > {
2018-10-29 17:29:46 +00:00
check_function_args ( func . signature ( ) , & args ) ? ;
2018-07-09 16:06:44 +00:00
match * func . as_internal ( ) {
FuncInstanceInternal ::Internal { .. } = > {
let interpreter = Interpreter ::new ( func , args ) ? ;
Ok ( FuncInvocation {
kind : FuncInvocationKind ::Internal ( interpreter ) ,
} )
}
FuncInstanceInternal ::Host {
ref host_func_index ,
..
} = > {
Ok ( FuncInvocation {
kind : FuncInvocationKind ::Host {
args ,
host_func_index : * host_func_index ,
finished : false ,
} ,
} )
} ,
}
}
}
/// A resumable invocation error.
#[ derive(Debug) ]
pub enum ResumableError {
/// Trap happened.
Trap ( Trap ) ,
/// The invocation is not resumable.
///
/// Invocations are only resumable if a host function is called, and the host function returns a trap of `Host` kind. For other cases, this error will be returned. This includes:
/// - The invocation is directly a host function.
/// - The invocation has not been started.
/// - The invocation returns normally or returns any trap other than `Host` kind.
///
/// This error is returned by [`resume_execution`].
///
/// [`resume_execution`]: struct.FuncInvocation.html#method.resume_execution
NotResumable ,
/// The invocation has already been started.
///
/// This error is returned by [`start_execution`].
///
/// [`start_execution`]: struct.FuncInvocation.html#method.start_execution
AlreadyStarted ,
}
impl From < Trap > for ResumableError {
fn from ( trap : Trap ) -> Self {
ResumableError ::Trap ( trap )
}
}
/// A resumable invocation handle. This struct is returned by `FuncInstance::invoke_resumable`.
pub struct FuncInvocation < ' args > {
kind : FuncInvocationKind < ' args > ,
}
enum FuncInvocationKind < ' args > {
Internal ( Interpreter ) ,
Host {
args : & ' args [ RuntimeValue ] ,
host_func_index : usize ,
finished : bool
} ,
}
impl < ' args > FuncInvocation < ' args > {
/// 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.
pub fn start_execution < ' externals , E : Externals + ' externals > ( & mut self , externals : & ' externals mut E ) -> Result < Option < RuntimeValue > , 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 } = > {
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.
///
/// `return_val` must be of the value type [`resumable_value_type`], defined by the host function import. Otherwise,
/// `UnexpectedSignature` trap will be returned. The current invocation must also be resumable
/// [`is_resumable`]. Otherwise, a `NotResumable` error will be returned.
///
/// [`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 < RuntimeValue > , externals : & ' externals mut E ) -> Result < Option < RuntimeValue > , 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 ) ;
} ,
}
}
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
}