Support Func imports with zero shims (#839)
* Move `Func` to its own file * Support `Func` imports with zero shims This commit extends the `Func` type in the `wasmtime` crate with static `wrap*` constructors. The goal of these constructors is to create a `Func` type which has zero shims associated with it, creating as small of a layer as possible between wasm code and calling imported Rust code. This is achieved by creating an `extern "C"` shim function which matches the ABI of what Cranelift will generate, and then the host function is passed directly into an `InstanceHandle` to get called later. This also enables enough inlining opportunities that LLVM will be able to see all functions and inline everything to the point where your function is called immediately from wasm, no questions asked.
This commit is contained in:
@@ -1,12 +1,9 @@
|
||||
use crate::callable::{Callable, NativeCallable, WasmtimeFn, WrappedCallable};
|
||||
use crate::runtime::Store;
|
||||
use crate::trampoline::{generate_global_export, generate_memory_export, generate_table_export};
|
||||
use crate::trap::Trap;
|
||||
use crate::types::{ExternType, FuncType, GlobalType, MemoryType, TableType, ValType};
|
||||
use crate::values::{from_checked_anyfunc, into_checked_anyfunc, Val};
|
||||
use crate::Mutability;
|
||||
use crate::{ExternType, GlobalType, MemoryType, TableType, ValType};
|
||||
use crate::{Func, Store};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use std::slice;
|
||||
use wasmtime_environ::wasm;
|
||||
@@ -140,121 +137,6 @@ impl From<Table> for Extern {
|
||||
}
|
||||
}
|
||||
|
||||
/// A WebAssembly function which can be called.
|
||||
///
|
||||
/// This type can represent a number of callable items, such as:
|
||||
///
|
||||
/// * An exported function from a WebAssembly module.
|
||||
/// * A user-defined function used to satisfy an import.
|
||||
///
|
||||
/// These types of callable items are all wrapped up in this `Func` and can be
|
||||
/// used to both instantiate an [`Instance`](crate::Instance) as well as be
|
||||
/// extracted from an [`Instance`](crate::Instance).
|
||||
///
|
||||
/// # `Func` and `Clone`
|
||||
///
|
||||
/// Functions are internally reference counted so you can `clone` a `Func`. The
|
||||
/// cloning process only performs a shallow clone, so two cloned `Func`
|
||||
/// instances are equivalent in their functionality.
|
||||
#[derive(Clone)]
|
||||
pub struct Func {
|
||||
_store: Store,
|
||||
callable: Rc<dyn WrappedCallable + 'static>,
|
||||
ty: FuncType,
|
||||
}
|
||||
|
||||
impl Func {
|
||||
/// Creates a new `Func` with the given arguments, typically to create a
|
||||
/// user-defined function to pass as an import to a module.
|
||||
///
|
||||
/// * `store` - a cache of data where information is stored, typically
|
||||
/// shared with a [`Module`](crate::Module).
|
||||
///
|
||||
/// * `ty` - the signature of this function, used to indicate what the
|
||||
/// inputs and outputs are, which must be WebAssembly types.
|
||||
///
|
||||
/// * `callable` - a type implementing the [`Callable`] trait which
|
||||
/// is the implementation of this `Func` value.
|
||||
///
|
||||
/// Note that the implementation of `callable` must adhere to the `ty`
|
||||
/// signature given, error or traps may occur if it does not respect the
|
||||
/// `ty` signature.
|
||||
pub fn new(store: &Store, ty: FuncType, callable: Rc<dyn Callable + 'static>) -> Self {
|
||||
let callable = Rc::new(NativeCallable::new(callable, &ty, &store));
|
||||
Func::from_wrapped(store, ty, callable)
|
||||
}
|
||||
|
||||
fn from_wrapped(
|
||||
store: &Store,
|
||||
ty: FuncType,
|
||||
callable: Rc<dyn WrappedCallable + 'static>,
|
||||
) -> Func {
|
||||
Func {
|
||||
_store: store.clone(),
|
||||
callable,
|
||||
ty,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the underlying wasm type that this `Func` has.
|
||||
pub fn ty(&self) -> &FuncType {
|
||||
&self.ty
|
||||
}
|
||||
|
||||
/// Returns the number of parameters that this function takes.
|
||||
pub fn param_arity(&self) -> usize {
|
||||
self.ty.params().len()
|
||||
}
|
||||
|
||||
/// Returns the number of results this function produces.
|
||||
pub fn result_arity(&self) -> usize {
|
||||
self.ty.results().len()
|
||||
}
|
||||
|
||||
/// Invokes this function with the `params` given, returning the results and
|
||||
/// any trap, if one occurs.
|
||||
///
|
||||
/// The `params` here must match the type signature of this `Func`, or a
|
||||
/// trap will occur. If a trap occurs while executing this function, then a
|
||||
/// trap will also be returned.
|
||||
///
|
||||
/// This function should not panic unless the underlying function itself
|
||||
/// initiates a panic.
|
||||
pub fn call(&self, params: &[Val]) -> Result<Box<[Val]>, Trap> {
|
||||
let mut results = vec![Val::null(); self.result_arity()];
|
||||
self.callable.call(params, &mut results)?;
|
||||
Ok(results.into_boxed_slice())
|
||||
}
|
||||
|
||||
pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::Export {
|
||||
self.callable.wasmtime_export()
|
||||
}
|
||||
|
||||
pub(crate) fn from_wasmtime_function(
|
||||
export: wasmtime_runtime::Export,
|
||||
store: &Store,
|
||||
instance_handle: InstanceHandle,
|
||||
) -> Self {
|
||||
// This is only called with `Export::Function`, and since it's coming
|
||||
// from wasmtime_runtime itself we should support all the types coming
|
||||
// out of it, so assert such here.
|
||||
let ty = if let wasmtime_runtime::Export::Function { signature, .. } = &export {
|
||||
FuncType::from_wasmtime_signature(signature.clone())
|
||||
.expect("core wasm signature should be supported")
|
||||
} else {
|
||||
panic!("expected function export")
|
||||
};
|
||||
let callable = WasmtimeFn::new(store, instance_handle, export);
|
||||
Func::from_wrapped(store, ty, Rc::new(callable))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Func {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Func")
|
||||
}
|
||||
}
|
||||
|
||||
/// A WebAssembly `global` value which can be read and written to.
|
||||
///
|
||||
/// A `global` in WebAssembly is sort of like a global variable within an
|
||||
|
||||
Reference in New Issue
Block a user