mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-16 08:10:49 +00:00
Add func method to Instance
This commit is contained in:
parent
ab65477d1f
commit
bc2e527bb2
@ -5,6 +5,7 @@ pub type CompileResult<T> = std::result::Result<T, Box<CompileError>>;
|
||||
pub type LinkResult<T> = std::result::Result<T, Vec<LinkError>>;
|
||||
pub type RuntimeResult<T> = std::result::Result<T, Box<RuntimeError>>;
|
||||
pub type CallResult<T> = std::result::Result<T, Box<CallError>>;
|
||||
pub type ResolveResult<T> = std::result::Result<T, Box<ResolveError>>;
|
||||
|
||||
/// This is returned when the chosen compiler is unable to
|
||||
/// successfully compile the provided webassembly module into
|
||||
@ -93,6 +94,23 @@ impl PartialEq for RuntimeError {
|
||||
}
|
||||
}
|
||||
|
||||
/// This error type is produced by resolving a wasm function
|
||||
/// given its name.
|
||||
///
|
||||
/// Comparing two `ResolveError`s always evaluates to false.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ResolveError {
|
||||
Signature { expected: FuncSig, found: Vec<Type> },
|
||||
NoSuchExport { name: String },
|
||||
ExportWrongType { name: String },
|
||||
}
|
||||
|
||||
impl PartialEq for ResolveError {
|
||||
fn eq(&self, _other: &ResolveError) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// This error type is produced by calling a wasm function
|
||||
/// exported from a module.
|
||||
///
|
||||
@ -102,9 +120,7 @@ impl PartialEq for RuntimeError {
|
||||
/// Comparing two `CallError`s always evaluates to false.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CallError {
|
||||
Signature { expected: FuncSig, found: Vec<Type> },
|
||||
NoSuchExport { name: String },
|
||||
ExportNotFunc { name: String },
|
||||
Resolve(ResolveError),
|
||||
Runtime(RuntimeError),
|
||||
}
|
||||
|
||||
@ -162,3 +178,33 @@ impl From<Box<RuntimeError>> for Box<CallError> {
|
||||
Box::new(CallError::Runtime(*runtime_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CompileError> for Box<Error> {
|
||||
fn from(compile_err: CompileError) -> Self {
|
||||
Box::new(Error::CompileError(compile_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RuntimeError> for Box<Error> {
|
||||
fn from(runtime_err: RuntimeError) -> Self {
|
||||
Box::new(Error::RuntimeError(runtime_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CallError> for Box<Error> {
|
||||
fn from(call_err: CallError) -> Self {
|
||||
Box::new(Error::CallError(call_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RuntimeError> for Box<CallError> {
|
||||
fn from(runtime_err: RuntimeError) -> Self {
|
||||
Box::new(CallError::Runtime(runtime_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ResolveError> for Box<CallError> {
|
||||
fn from(resolve_err: ResolveError) -> Self {
|
||||
Box::new(CallError::Resolve(resolve_err))
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
backend::Token,
|
||||
backing::{ImportBacking, LocalBacking},
|
||||
error::{CallError, CallResult, Result},
|
||||
error::{CallError, CallResult, ResolveError, ResolveResult, Result},
|
||||
export::{
|
||||
Context, Export, ExportIter, FuncPointer, GlobalPointer, MemoryPointer, TablePointer,
|
||||
},
|
||||
@ -13,8 +13,7 @@ use crate::{
|
||||
},
|
||||
vm,
|
||||
};
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use std::{mem, rc::Rc};
|
||||
|
||||
pub(crate) struct InstanceInner {
|
||||
#[allow(dead_code)]
|
||||
@ -72,6 +71,50 @@ impl Instance {
|
||||
Ok(instance)
|
||||
}
|
||||
|
||||
/// This returns the representation of a function that can be called
|
||||
/// safely.
|
||||
///
|
||||
/// # Usage:
|
||||
/// ```
|
||||
/// # use wasmer_runtime_core::Instance;
|
||||
/// # fn call_foo(instance: &mut Instance) -> Option<()> {
|
||||
/// instance
|
||||
/// .func("foo")?
|
||||
/// .call(&[])?;
|
||||
/// # Some(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn func(&mut self, name: &str) -> ResolveResult<Function> {
|
||||
let export_index =
|
||||
self.module
|
||||
.exports
|
||||
.get(name)
|
||||
.ok_or_else(|| ResolveError::NoSuchExport {
|
||||
name: name.to_string(),
|
||||
})?;
|
||||
|
||||
if let ExportIndex::Func(func_index) = export_index {
|
||||
let sig_index = *self
|
||||
.module
|
||||
.func_assoc
|
||||
.get(*func_index)
|
||||
.expect("broken invariant, incorrect func index");
|
||||
let signature = self.module.sig_registry.lookup_func_sig(sig_index);
|
||||
|
||||
Ok(Function {
|
||||
signature,
|
||||
module: &self.module,
|
||||
instance_inner: &mut self.inner,
|
||||
func_index: *func_index,
|
||||
})
|
||||
} else {
|
||||
Err(ResolveError::ExportWrongType {
|
||||
name: name.to_string(),
|
||||
}
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Call an exported webassembly function given the export name.
|
||||
/// Pass arguments by wrapping each one in the [`Value`] enum.
|
||||
/// The returned values are also each wrapped in a [`Value`].
|
||||
@ -99,16 +142,16 @@ impl Instance {
|
||||
self.module
|
||||
.exports
|
||||
.get(name)
|
||||
.ok_or_else(|| CallError::NoSuchExport {
|
||||
.ok_or_else(|| ResolveError::NoSuchExport {
|
||||
name: name.to_string(),
|
||||
})?;
|
||||
|
||||
let func_index = if let ExportIndex::Func(func_index) = export_index {
|
||||
*func_index
|
||||
} else {
|
||||
return Err(CallError::ExportNotFunc {
|
||||
return Err(CallError::Resolve(ResolveError::ExportWrongType {
|
||||
name: name.to_string(),
|
||||
}
|
||||
})
|
||||
.into());
|
||||
};
|
||||
|
||||
@ -134,7 +177,7 @@ impl Instance {
|
||||
let signature = self.module.sig_registry.lookup_func_sig(sig_index);
|
||||
|
||||
if !signature.check_sig(args) {
|
||||
Err(CallError::Signature {
|
||||
Err(ResolveError::Signature {
|
||||
expected: signature.clone(),
|
||||
found: args.iter().map(|val| val.ty()).collect(),
|
||||
})?
|
||||
@ -351,6 +394,84 @@ impl LikeNamespace for Instance {
|
||||
}
|
||||
}
|
||||
|
||||
/// A representation of an exported WebAssembly function.
|
||||
pub struct Function<'a> {
|
||||
signature: &'a FuncSig,
|
||||
module: &'a ModuleInner,
|
||||
instance_inner: &'a mut InstanceInner,
|
||||
func_index: FuncIndex,
|
||||
}
|
||||
|
||||
impl<'a> Function<'a> {
|
||||
/// Call an exported webassembly function safely.
|
||||
///
|
||||
/// Pass arguments by wrapping each one in the [`Value`] enum.
|
||||
/// The returned values are also each wrapped in a [`Value`].
|
||||
///
|
||||
/// [`Value`]: enum.Value.html
|
||||
///
|
||||
/// # Note:
|
||||
/// This returns `CallResult<Vec<Value>>` in order to support
|
||||
/// the future multi-value returns webassembly feature.
|
||||
///
|
||||
/// # Usage:
|
||||
/// ```
|
||||
/// # use wasmer_runtime_core::Instance;
|
||||
/// # fn call_foo(instance: &mut Instance) -> Option<()> {
|
||||
/// instance
|
||||
/// .func("foo")?
|
||||
/// .call(&[])?;
|
||||
/// # Some(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn call(&mut self, params: &[Value]) -> CallResult<Vec<Value>> {
|
||||
if !self.signature.check_sig(params) {
|
||||
Err(ResolveError::Signature {
|
||||
expected: self.signature.clone(),
|
||||
found: params.iter().map(|val| val.ty()).collect(),
|
||||
})?
|
||||
}
|
||||
|
||||
let vmctx = match self.func_index.local_or_import(self.module) {
|
||||
LocalOrImport::Local(_) => &mut *self.instance_inner.vmctx,
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
self.instance_inner.import_backing.functions[imported_func_index].vmctx
|
||||
}
|
||||
};
|
||||
|
||||
let token = Token::generate();
|
||||
|
||||
let returns = self.module.protected_caller.call(
|
||||
&self.module,
|
||||
self.func_index,
|
||||
params,
|
||||
&self.instance_inner.import_backing,
|
||||
vmctx,
|
||||
token,
|
||||
)?;
|
||||
|
||||
Ok(returns)
|
||||
}
|
||||
|
||||
pub fn signature(&self) -> &FuncSig {
|
||||
self.signature
|
||||
}
|
||||
|
||||
pub fn raw(&self) -> *const vm::Func {
|
||||
match self.func_index.local_or_import(self.module) {
|
||||
LocalOrImport::Local(local_func_index) => self
|
||||
.module
|
||||
.func_resolver
|
||||
.get(self.module, local_func_index)
|
||||
.unwrap()
|
||||
.as_ptr(),
|
||||
LocalOrImport::Import(import_func_index) => {
|
||||
self.instance_inner.import_backing.functions[import_func_index].func
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl Instance {
|
||||
pub fn memory_offset_addr(&self, _: u32, _: usize) -> *const u8 {
|
||||
|
@ -170,10 +170,11 @@ impl Ctx {
|
||||
}
|
||||
}
|
||||
|
||||
enum InnerFunc {}
|
||||
/// Used to provide type safety (ish) for passing around function pointers.
|
||||
/// The typesystem ensures this cannot be dereferenced since an
|
||||
/// empty enum cannot actually exist.
|
||||
pub enum Func {}
|
||||
pub struct Func(InnerFunc);
|
||||
|
||||
/// An imported function, which contains the vmctx that owns this function.
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -1,5 +1,5 @@
|
||||
pub use wasmer_runtime_core::import::ImportObject;
|
||||
pub use wasmer_runtime_core::instance::Instance;
|
||||
pub use wasmer_runtime_core::instance::{Function, Instance};
|
||||
pub use wasmer_runtime_core::module::Module;
|
||||
pub use wasmer_runtime_core::types::Value;
|
||||
pub use wasmer_runtime_core::vm::Ctx;
|
||||
@ -9,8 +9,9 @@ pub use wasmer_runtime_core::{compile_with, validate};
|
||||
pub use wasmer_runtime_core::error;
|
||||
pub use wasmer_runtime_core::imports;
|
||||
|
||||
pub mod value {
|
||||
pub use wasmer_runtime_core::types::{Type, Value};
|
||||
pub mod wasm {
|
||||
pub use wasmer_runtime_core::instance::Function;
|
||||
pub use wasmer_runtime_core::types::{FuncSig, Type, Value};
|
||||
}
|
||||
|
||||
/// Compile WebAssembly binary code into a [`Module`].
|
||||
|
Loading…
x
Reference in New Issue
Block a user