mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-23 05:31:32 +00:00
feat(runtime-core) Allow host functions without an explicit vm::Ctx
argument.
This patch allows host functions to get a signature without an explicit `vm::Ctx` argument. It is for Rust only. The C API receives a function pointer and has no clue whether a `vm::Ctx` argument is present or not, so it assumes it is always declared. From the backend point of view, the pointer to `vm::Ctx` is always inserted in the stack, but it is not used by the function when the argument is absent.
This commit is contained in:
@ -124,16 +124,27 @@ pub trait WasmTypeList {
|
|||||||
self,
|
self,
|
||||||
f: NonNull<vm::Func>,
|
f: NonNull<vm::Func>,
|
||||||
wasm: Wasm,
|
wasm: Wasm,
|
||||||
ctx: *mut Ctx,
|
ctx: *mut vm::Ctx,
|
||||||
) -> Result<Rets, RuntimeError>
|
) -> Result<Rets, RuntimeError>
|
||||||
where
|
where
|
||||||
Rets: WasmTypeList;
|
Rets: WasmTypeList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Empty trait to specify the kind of `ExternalFunction`: With or
|
||||||
|
/// without a `vm::Ctx` argument.
|
||||||
|
pub trait ExternalFunctionKind {}
|
||||||
|
|
||||||
|
pub struct ExplicitVmCtx {}
|
||||||
|
pub struct ImplicitVmCtx {}
|
||||||
|
|
||||||
|
impl ExternalFunctionKind for ExplicitVmCtx {}
|
||||||
|
impl ExternalFunctionKind for ImplicitVmCtx {}
|
||||||
|
|
||||||
/// Represents a function that can be converted to a `vm::Func`
|
/// Represents a function that can be converted to a `vm::Func`
|
||||||
/// (function pointer) that can be called within WebAssembly.
|
/// (function pointer) that can be called within WebAssembly.
|
||||||
pub trait ExternalFunction<Args, Rets>
|
pub trait ExternalFunction<Kind, Args, Rets>
|
||||||
where
|
where
|
||||||
|
Kind: ExternalFunctionKind,
|
||||||
Args: WasmTypeList,
|
Args: WasmTypeList,
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
@ -208,9 +219,10 @@ where
|
|||||||
Args: WasmTypeList,
|
Args: WasmTypeList,
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
pub fn new<F>(f: F) -> Func<'a, Args, Rets, Host>
|
pub fn new<F, Kind>(f: F) -> Func<'a, Args, Rets, Host>
|
||||||
where
|
where
|
||||||
F: ExternalFunction<Args, Rets>,
|
Kind: ExternalFunctionKind,
|
||||||
|
F: ExternalFunction<Kind, Args, Rets>,
|
||||||
{
|
{
|
||||||
Func {
|
Func {
|
||||||
inner: Host(()),
|
inner: Host(()),
|
||||||
@ -438,7 +450,7 @@ macro_rules! impl_traits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl< $( $x, )* Rets, Trap, FN > ExternalFunction<( $( $x ),* ), Rets> for FN
|
impl< $( $x, )* Rets, Trap, FN > ExternalFunction<ExplicitVmCtx, ( $( $x ),* ), Rets> for FN
|
||||||
where
|
where
|
||||||
$( $x: WasmExternType, )*
|
$( $x: WasmExternType, )*
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
@ -451,20 +463,20 @@ macro_rules! impl_traits {
|
|||||||
/// This is required for the llvm backend to be able to unwind through this function.
|
/// This is required for the llvm backend to be able to unwind through this function.
|
||||||
#[cfg_attr(nightly, unwind(allowed))]
|
#[cfg_attr(nightly, unwind(allowed))]
|
||||||
extern fn wrap<$( $x, )* Rets, Trap, FN>(
|
extern fn wrap<$( $x, )* Rets, Trap, FN>(
|
||||||
ctx: &mut vm::Ctx $( , $x: <$x as WasmExternType>::Native )*
|
vmctx: &mut vm::Ctx $( , $x: <$x as WasmExternType>::Native )*
|
||||||
) -> Rets::CStruct
|
) -> Rets::CStruct
|
||||||
where
|
where
|
||||||
$( $x: WasmExternType, )*
|
$( $x: WasmExternType, )*
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
Trap: TrapEarly<Rets>,
|
Trap: TrapEarly<Rets>,
|
||||||
FN: Fn(&mut vm::Ctx $( , $x )*) -> Trap,
|
FN: Fn(&mut vm::Ctx, $( $x, )*) -> Trap,
|
||||||
{
|
{
|
||||||
let f: FN = unsafe { mem::transmute_copy(&()) };
|
let f: FN = unsafe { mem::transmute_copy(&()) };
|
||||||
|
|
||||||
let err = match panic::catch_unwind(
|
let err = match panic::catch_unwind(
|
||||||
panic::AssertUnwindSafe(
|
panic::AssertUnwindSafe(
|
||||||
|| {
|
|| {
|
||||||
f(ctx $( , WasmExternType::from_native($x) )* ).report()
|
f(vmctx $( , WasmExternType::from_native($x) )* ).report()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@ -477,7 +489,7 @@ macro_rules! impl_traits {
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
(&*ctx.module).runnable_module.do_early_trap(err)
|
(&*vmctx.module).runnable_module.do_early_trap(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,7 +502,65 @@ macro_rules! impl_traits {
|
|||||||
);
|
);
|
||||||
|
|
||||||
NonNull::new(unsafe {
|
NonNull::new(unsafe {
|
||||||
::std::mem::transmute_copy::<_, *mut vm::Func>(self)
|
mem::transmute_copy::<_, *mut vm::Func>(self)
|
||||||
|
}).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl< $( $x, )* Rets, Trap, FN > ExternalFunction<ImplicitVmCtx, ( $( $x ),* ), Rets> for FN
|
||||||
|
where
|
||||||
|
$( $x: WasmExternType, )*
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
Trap: TrapEarly<Rets>,
|
||||||
|
FN: Fn($( $x, )*) -> Trap,
|
||||||
|
{
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn to_raw(&self) -> NonNull<vm::Func> {
|
||||||
|
if mem::size_of::<Self>() == 0 {
|
||||||
|
/// This is required for the llvm backend to be able to unwind through this function.
|
||||||
|
#[cfg_attr(nightly, unwind(allowed))]
|
||||||
|
extern fn wrap<$( $x, )* Rets, Trap, FN>(
|
||||||
|
vmctx: &mut vm::Ctx $( , $x: <$x as WasmExternType>::Native )*
|
||||||
|
) -> Rets::CStruct
|
||||||
|
where
|
||||||
|
$( $x: WasmExternType, )*
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
Trap: TrapEarly<Rets>,
|
||||||
|
FN: Fn($( $x, )*) -> Trap,
|
||||||
|
{
|
||||||
|
let f: FN = unsafe { mem::transmute_copy(&()) };
|
||||||
|
|
||||||
|
let err = match panic::catch_unwind(
|
||||||
|
panic::AssertUnwindSafe(
|
||||||
|
|| {
|
||||||
|
f($( WasmExternType::from_native($x), )* ).report()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Ok(Ok(returns)) => return returns.into_c_struct(),
|
||||||
|
Ok(Err(err)) => {
|
||||||
|
let b: Box<_> = err.into();
|
||||||
|
b as Box<dyn Any>
|
||||||
|
},
|
||||||
|
Err(err) => err,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
(&*vmctx.module).runnable_module.do_early_trap(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap()
|
||||||
|
} else {
|
||||||
|
assert_eq!(
|
||||||
|
mem::size_of::<Self>(),
|
||||||
|
mem::size_of::<usize>(),
|
||||||
|
"you cannot use a closure that captures state for `Func`."
|
||||||
|
);
|
||||||
|
|
||||||
|
NonNull::new(unsafe {
|
||||||
|
mem::transmute_copy::<_, *mut vm::Func>(self)
|
||||||
}).unwrap()
|
}).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user