mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-07 05:08:19 +00:00
!temp Move HostFunction, Func & co. into wasmer.
Because `Func` needs an access to the runtime API (`wasmer-runtime`) to trap properly, either we move parts of `wasmer-runtime` to `wasm-common`, or we move parts of `wasm-common` into `wasmer`. I decided to go with the second approach since `wasmer` is the only crate to use `HostFunction` & co. It's not “common” by definition, and it's way easier (for the moment).
This commit is contained in:
@@ -1,13 +1,13 @@
|
|||||||
use crate::externals::{Extern, Function, Global, Memory, Table};
|
use crate::externals::{Extern, Function, Global, Memory, Table};
|
||||||
use crate::import_object::LikeNamespace;
|
use crate::import_object::LikeNamespace;
|
||||||
use crate::native::NativeFunc;
|
use crate::native::NativeFunc;
|
||||||
|
use crate::WasmTypeList;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use std::{
|
use std::{
|
||||||
iter::{ExactSizeIterator, FromIterator},
|
iter::{ExactSizeIterator, FromIterator},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasm_common::WasmTypeList;
|
|
||||||
use wasmer_runtime::Export;
|
use wasmer_runtime::Export;
|
||||||
|
|
||||||
/// The `ExportError` can happen when trying to get a specific
|
/// The `ExportError` can happen when trying to get a specific
|
||||||
|
|||||||
493
lib/api/src/externals/function.rs
vendored
493
lib/api/src/externals/function.rs
vendored
@@ -5,12 +5,14 @@ use crate::types::Val;
|
|||||||
use crate::FunctionType;
|
use crate::FunctionType;
|
||||||
use crate::NativeFunc;
|
use crate::NativeFunc;
|
||||||
use crate::RuntimeError;
|
use crate::RuntimeError;
|
||||||
|
pub use inner::{HostFunction, WasmTypeList};
|
||||||
|
use inner::{WithEnv, WithoutEnv};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use wasm_common::{HostFunction, WasmTypeList, WithEnv, WithoutEnv};
|
|
||||||
use wasmer_runtime::{
|
use wasmer_runtime::{
|
||||||
wasmer_call_trampoline, Export, ExportFunction, VMCallerCheckedAnyfunc, VMContext,
|
raise_user_trap, resume_panic, wasmer_call_trampoline, Export, ExportFunction,
|
||||||
VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind, VMTrampoline,
|
VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind,
|
||||||
|
VMTrampoline,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A function defined in the Wasm module
|
/// A function defined in the Wasm module
|
||||||
@@ -58,7 +60,7 @@ impl Function {
|
|||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
Env: Sized + 'static,
|
Env: Sized + 'static,
|
||||||
{
|
{
|
||||||
let func: wasm_common::Func<Args, Rets> = wasm_common::Func::new(func);
|
let func: inner::Func<Args, Rets> = inner::Func::new(func);
|
||||||
let address = func.address() as *const VMFunctionBody;
|
let address = func.address() as *const VMFunctionBody;
|
||||||
let vmctx = std::ptr::null_mut() as *mut _ as *mut VMContext;
|
let vmctx = std::ptr::null_mut() as *mut _ as *mut VMContext;
|
||||||
let signature = func.ty();
|
let signature = func.ty();
|
||||||
@@ -143,7 +145,7 @@ impl Function {
|
|||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
Env: Sized + 'static,
|
Env: Sized + 'static,
|
||||||
{
|
{
|
||||||
let func: wasm_common::Func<Args, Rets> = wasm_common::Func::new(func);
|
let func: inner::Func<Args, Rets> = inner::Func::new(func);
|
||||||
let address = func.address() as *const VMFunctionBody;
|
let address = func.address() as *const VMFunctionBody;
|
||||||
// TODO: We need to refactor the Function context.
|
// TODO: We need to refactor the Function context.
|
||||||
// Right now is structured as it's always a `VMContext`. However, only
|
// Right now is structured as it's always a `VMContext`. However, only
|
||||||
@@ -441,8 +443,485 @@ impl<T: VMDynamicFunction> VMDynamicFunctionCall<T> for VMDynamicFunctionContext
|
|||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(Ok(())) => {}
|
Ok(Ok(())) => {}
|
||||||
Ok(Err(trap)) => wasmer_runtime::raise_user_trap(Box::new(trap)),
|
Ok(Err(trap)) => raise_user_trap(Box::new(trap)),
|
||||||
Err(panic) => wasmer_runtime::resume_panic(panic),
|
Err(panic) => resume_panic(panic),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod inner {
|
||||||
|
use std::convert::Infallible;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::panic::{self, AssertUnwindSafe};
|
||||||
|
use wasm_common::{FunctionType, NativeWasmType, Type, WasmExternType};
|
||||||
|
use wasmer_runtime::{raise_user_trap, resume_panic};
|
||||||
|
|
||||||
|
/// Represents a list of WebAssembly values.
|
||||||
|
pub trait WasmTypeList {
|
||||||
|
/// CStruct type.
|
||||||
|
type CStruct;
|
||||||
|
|
||||||
|
/// Array of return values.
|
||||||
|
type Array: AsMut<[i128]>;
|
||||||
|
|
||||||
|
/// Construct `Self` based on an array of returned values.
|
||||||
|
fn from_array(array: Self::Array) -> Self;
|
||||||
|
|
||||||
|
/// Transforms Rust values into an Array
|
||||||
|
fn into_array(self) -> Self::Array;
|
||||||
|
|
||||||
|
/// Generates an empty array that will hold the returned values of
|
||||||
|
/// the WebAssembly function.
|
||||||
|
fn empty_array() -> Self::Array;
|
||||||
|
|
||||||
|
/// Transforms C values into Rust values.
|
||||||
|
fn from_c_struct(c_struct: Self::CStruct) -> Self;
|
||||||
|
|
||||||
|
/// Transforms Rust values into C values.
|
||||||
|
fn into_c_struct(self) -> Self::CStruct;
|
||||||
|
|
||||||
|
/// Get types of the current values.
|
||||||
|
fn wasm_types() -> &'static [Type];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a TrapEarly type.
|
||||||
|
pub trait TrapEarly<Rets>
|
||||||
|
where
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
{
|
||||||
|
/// The error type for this trait.
|
||||||
|
type Error: Error + Sync + Send + 'static;
|
||||||
|
|
||||||
|
/// Get returns or error result.
|
||||||
|
fn report(self) -> Result<Rets, Self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Rets> TrapEarly<Rets> for Rets
|
||||||
|
where
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
{
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn report(self) -> Result<Self, Infallible> {
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Rets, E> TrapEarly<Rets> for Result<Rets, E>
|
||||||
|
where
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
E: Error + Sync + Send + 'static,
|
||||||
|
{
|
||||||
|
type Error = E;
|
||||||
|
|
||||||
|
fn report(self) -> Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Empty trait to specify the kind of `HostFunction`: With or
|
||||||
|
/// without a `vm::Ctx` argument. See the `ExplicitVmCtx` and the
|
||||||
|
/// `ImplicitVmCtx` structures.
|
||||||
|
///
|
||||||
|
/// This trait is never aimed to be used by a user. It is used by the
|
||||||
|
/// trait system to automatically generate an appropriate `wrap`
|
||||||
|
/// function.
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub trait HostFunctionKind {}
|
||||||
|
|
||||||
|
/// An empty struct to help Rust typing to determine
|
||||||
|
/// when a `HostFunction` doesn't take an Environment
|
||||||
|
pub struct WithEnv {}
|
||||||
|
|
||||||
|
impl HostFunctionKind for WithEnv {}
|
||||||
|
|
||||||
|
/// An empty struct to help Rust typing to determine
|
||||||
|
/// when a `HostFunction` takes an Environment
|
||||||
|
pub struct WithoutEnv {}
|
||||||
|
|
||||||
|
impl HostFunctionKind for WithoutEnv {}
|
||||||
|
|
||||||
|
/// Represents a function that can be converted to a `vm::Func`
|
||||||
|
/// (function pointer) that can be called within WebAssembly.
|
||||||
|
pub trait HostFunction<Args, Rets, Kind, T>
|
||||||
|
where
|
||||||
|
Args: WasmTypeList,
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
Kind: HostFunctionKind,
|
||||||
|
T: Sized,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
/// Convert to function pointer.
|
||||||
|
fn to_raw(self) -> *const FunctionBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct FunctionBody(*mut u8);
|
||||||
|
|
||||||
|
/// Represents a function that can be used by WebAssembly.
|
||||||
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
|
pub struct Func<Args = (), Rets = ()> {
|
||||||
|
address: *const FunctionBody,
|
||||||
|
_phantom: PhantomData<(Args, Rets)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<Args, Rets> Send for Func<Args, Rets> {}
|
||||||
|
|
||||||
|
impl<Args, Rets> Func<Args, Rets>
|
||||||
|
where
|
||||||
|
Args: WasmTypeList,
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
{
|
||||||
|
/// Creates a new `Func`.
|
||||||
|
pub fn new<F, T, E>(func: F) -> Self
|
||||||
|
where
|
||||||
|
F: HostFunction<Args, Rets, T, E>,
|
||||||
|
T: HostFunctionKind,
|
||||||
|
E: Sized,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
address: func.to_raw(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the type of the Func
|
||||||
|
pub fn ty(&self) -> FunctionType {
|
||||||
|
FunctionType::new(Args::wasm_types(), Rets::wasm_types())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the address of the Func
|
||||||
|
pub fn address(&self) -> *const FunctionBody {
|
||||||
|
self.address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WasmTypeList for Infallible {
|
||||||
|
type CStruct = Self;
|
||||||
|
type Array = [i128; 0];
|
||||||
|
|
||||||
|
fn from_array(_: Self::Array) -> Self {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_array(self) -> Self::Array {
|
||||||
|
[]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn empty_array() -> Self::Array {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_c_struct(_: Self::CStruct) -> Self {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_c_struct(self) -> Self::CStruct {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wasm_types() -> &'static [Type] {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_traits {
|
||||||
|
( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => {
|
||||||
|
/// Struct for typed funcs.
|
||||||
|
#[repr($repr)]
|
||||||
|
pub struct $struct_name< $( $x ),* > ( $( <$x as WasmExternType>::Native ),* )
|
||||||
|
where
|
||||||
|
$( $x: WasmExternType ),*;
|
||||||
|
|
||||||
|
#[allow(unused_parens, dead_code)]
|
||||||
|
impl< $( $x ),* > WasmTypeList for ( $( $x ),* )
|
||||||
|
where
|
||||||
|
$( $x: WasmExternType ),*
|
||||||
|
{
|
||||||
|
type CStruct = $struct_name<$( $x ),*>;
|
||||||
|
|
||||||
|
type Array = [i128; count_idents!( $( $x ),* )];
|
||||||
|
|
||||||
|
fn from_array(array: Self::Array) -> Self {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
let [ $( $x ),* ] = array;
|
||||||
|
|
||||||
|
( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* )
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_array(self) -> Self::Array {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
let ( $( $x ),* ) = self;
|
||||||
|
[ $( WasmExternType::to_native($x).to_binary() ),* ]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn empty_array() -> Self::Array {
|
||||||
|
[0; count_idents!( $( $x ),* )]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_c_struct(c_struct: Self::CStruct) -> Self {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
let $struct_name ( $( $x ),* ) = c_struct;
|
||||||
|
|
||||||
|
( $( WasmExternType::from_native($x) ),* )
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_parens, non_snake_case)]
|
||||||
|
fn into_c_struct(self) -> Self::CStruct {
|
||||||
|
let ( $( $x ),* ) = self;
|
||||||
|
|
||||||
|
$struct_name ( $( WasmExternType::to_native($x) ),* )
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wasm_types() -> &'static [Type] {
|
||||||
|
&[$( $x::Native::WASM_TYPE ),*]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_parens)]
|
||||||
|
impl< $( $x, )* Rets, Trap, FN > HostFunction<( $( $x ),* ), Rets, WithoutEnv, ()> for FN
|
||||||
|
where
|
||||||
|
$( $x: WasmExternType, )*
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
Trap: TrapEarly<Rets>,
|
||||||
|
FN: Fn($( $x , )*) -> Trap + 'static + Send,
|
||||||
|
{
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn to_raw(self) -> *const FunctionBody {
|
||||||
|
extern fn wrap<$( $x, )* Rets, Trap, FN>( _: usize, $($x: $x::Native, )* ) -> Rets::CStruct
|
||||||
|
where
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
Trap: TrapEarly<Rets>,
|
||||||
|
$( $x: WasmExternType, )*
|
||||||
|
FN: Fn( $( $x ),* ) -> Trap + 'static
|
||||||
|
{
|
||||||
|
let f: &FN = unsafe { &*(&() as *const () as *const FN) };
|
||||||
|
let result = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||||
|
f( $( WasmExternType::from_native($x) ),* ).report()
|
||||||
|
}));
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(Ok(result)) => return result.into_c_struct(),
|
||||||
|
Ok(Err(trap)) => unsafe { raise_user_trap(Box::new(trap)) },
|
||||||
|
Err(panic) => unsafe { resume_panic(panic) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wrap::<$( $x, )* Rets, Trap, Self> as *const FunctionBody
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_parens)]
|
||||||
|
impl< $( $x, )* Rets, Trap, T, FN > HostFunction<( $( $x ),* ), Rets, WithEnv, T> for FN
|
||||||
|
where
|
||||||
|
$( $x: WasmExternType, )*
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
Trap: TrapEarly<Rets>,
|
||||||
|
T: Sized,
|
||||||
|
FN: Fn(&mut T, $( $x , )*) -> Trap + 'static + Send
|
||||||
|
{
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn to_raw(self) -> *const FunctionBody {
|
||||||
|
extern fn wrap<$( $x, )* Rets, Trap, T, FN>( ctx: &mut T, $($x: $x::Native, )* ) -> Rets::CStruct
|
||||||
|
where
|
||||||
|
Rets: WasmTypeList,
|
||||||
|
Trap: TrapEarly<Rets>,
|
||||||
|
$( $x: WasmExternType, )*
|
||||||
|
T: Sized,
|
||||||
|
FN: Fn(&mut T, $( $x ),* ) -> Trap + 'static
|
||||||
|
{
|
||||||
|
let f: &FN = unsafe { &*(&() as *const () as *const FN) };
|
||||||
|
|
||||||
|
let result = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||||
|
f(ctx, $( WasmExternType::from_native($x) ),* ).report()
|
||||||
|
}));
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(Ok(result)) => return result.into_c_struct(),
|
||||||
|
Ok(Err(trap)) => unsafe { raise_user_trap(Box::new(trap)) },
|
||||||
|
Err(panic) => unsafe { resume_panic(panic) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wrap::<$( $x, )* Rets, Trap, T, Self> as *const FunctionBody
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! count_idents {
|
||||||
|
( $($idents:ident),* ) => {{
|
||||||
|
#[allow(dead_code, non_camel_case_types)]
|
||||||
|
enum Idents { $($idents,)* __CountIdentsLast }
|
||||||
|
const COUNT: usize = Idents::__CountIdentsLast as usize;
|
||||||
|
COUNT
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
//impl_traits!([C] S0,);
|
||||||
|
//impl_traits!([transparent] S1, A1);
|
||||||
|
impl_traits!([C] S2, A1, A2);
|
||||||
|
impl_traits!([C] S3, A1, A2, A3);
|
||||||
|
impl_traits!([C] S4, A1, A2, A3, A4);
|
||||||
|
impl_traits!([C] S5, A1, A2, A3, A4, A5);
|
||||||
|
impl_traits!([C] S6, A1, A2, A3, A4, A5, A6);
|
||||||
|
impl_traits!([C] S7, A1, A2, A3, A4, A5, A6, A7);
|
||||||
|
impl_traits!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8);
|
||||||
|
impl_traits!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9);
|
||||||
|
impl_traits!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
|
||||||
|
impl_traits!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
|
||||||
|
impl_traits!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
|
||||||
|
impl_traits!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
|
||||||
|
impl_traits!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
|
||||||
|
impl_traits!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15);
|
||||||
|
impl_traits!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);
|
||||||
|
impl_traits!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);
|
||||||
|
impl_traits!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18);
|
||||||
|
impl_traits!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19);
|
||||||
|
impl_traits!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20);
|
||||||
|
impl_traits!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21);
|
||||||
|
impl_traits!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22);
|
||||||
|
impl_traits!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23);
|
||||||
|
impl_traits!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24);
|
||||||
|
impl_traits!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25);
|
||||||
|
impl_traits!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_wasm_type_list {
|
||||||
|
use super::*;
|
||||||
|
use crate::types::Type;
|
||||||
|
// WasmTypeList
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_simple_values() {
|
||||||
|
// Simple values
|
||||||
|
assert_eq!(<i32>::wasm_types(), [Type::I32]);
|
||||||
|
assert_eq!(<i64>::wasm_types(), [Type::I64]);
|
||||||
|
assert_eq!(<f32>::wasm_types(), [Type::F32]);
|
||||||
|
assert_eq!(<f64>::wasm_types(), [Type::F64]);
|
||||||
|
|
||||||
|
// Multi values
|
||||||
|
assert_eq!(<(i32, i32)>::wasm_types(), [Type::I32, Type::I32]);
|
||||||
|
assert_eq!(<(i64, i64)>::wasm_types(), [Type::I64, Type::I64]);
|
||||||
|
assert_eq!(<(f32, f32)>::wasm_types(), [Type::F32, Type::F32]);
|
||||||
|
assert_eq!(<(f64, f64)>::wasm_types(), [Type::F64, Type::F64]);
|
||||||
|
|
||||||
|
// Mixed values
|
||||||
|
// assert_eq!(<(i32, i64, f32, f64)>::wasm_types(), [Type::I32, Type::I64, Type::F32, Type::F64]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_array() {
|
||||||
|
assert_eq!(<()>::empty_array().len(), 0);
|
||||||
|
assert_eq!(<i32>::empty_array().len(), 1);
|
||||||
|
assert_eq!(<(i32, i64)>::empty_array().len(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_from_array() {
|
||||||
|
// assert_eq!(<()>::from_array([]), ());
|
||||||
|
// assert_eq!(<(i32)>::from_array([1]), (1));
|
||||||
|
// assert_eq!(<(i32, i32)>::from_array([1, 1]), (1, 1));
|
||||||
|
// // This doesn't work
|
||||||
|
// // assert_eq!(<(i32, i64, f32, f64)>::from_array([1, 2, (3.1f32).to_bits().into(), (4.2f64).to_bits().into()]), (1, 2, 3.1f32, 4.2f64));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_into_array() {
|
||||||
|
// assert_eq!(().into_array(), []);
|
||||||
|
// assert_eq!((1).into_array(), [1]);
|
||||||
|
// assert_eq!((1, 2).into_array(), [1, 2]);
|
||||||
|
// assert_eq!((1, 2, 3).into_array(), [1, 2, 3]);
|
||||||
|
// // This doesn't work
|
||||||
|
// // assert_eq!(<(i32, i64, f32, f64)>::from_array([1, 2, (3.1f32).to_bits().into(), (4.2f64).to_bits().into()]), (1, 2, 3.1f32, 4.2f64));
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_into_c_struct() {
|
||||||
|
// assert_eq!(<()>::into_c_struct(), &[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_func {
|
||||||
|
use super::*;
|
||||||
|
use crate::types::Type;
|
||||||
|
use std::ptr;
|
||||||
|
// WasmTypeList
|
||||||
|
|
||||||
|
fn func() {}
|
||||||
|
fn func__i32() -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
fn func_i32(_a: i32) {}
|
||||||
|
fn func_i32__i32(a: i32) -> i32 {
|
||||||
|
a * 2
|
||||||
|
}
|
||||||
|
fn func_i32_i32__i32(a: i32, b: i32) -> i32 {
|
||||||
|
a + b
|
||||||
|
}
|
||||||
|
fn func_i32_i32__i32_i32(a: i32, b: i32) -> (i32, i32) {
|
||||||
|
(a, b)
|
||||||
|
}
|
||||||
|
fn func_f32_i32__i32_f32(a: f32, b: i32) -> (i32, f32) {
|
||||||
|
(b, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_function_types() {
|
||||||
|
assert_eq!(Func::new(func).ty(), FunctionType::new(vec![], vec![]));
|
||||||
|
assert_eq!(
|
||||||
|
Func::new(func__i32).ty(),
|
||||||
|
FunctionType::new(vec![], vec![Type::I32])
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Func::new(func_i32).ty(),
|
||||||
|
FunctionType::new(vec![Type::I32], vec![])
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Func::new(func_i32__i32).ty(),
|
||||||
|
FunctionType::new(vec![Type::I32], vec![Type::I32])
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Func::new(func_i32_i32__i32).ty(),
|
||||||
|
FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32])
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Func::new(func_i32_i32__i32_i32).ty(),
|
||||||
|
FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32, Type::I32])
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Func::new(func_f32_i32__i32_f32).ty(),
|
||||||
|
FunctionType::new(vec![Type::F32, Type::I32], vec![Type::I32, Type::F32])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_function_pointer() {
|
||||||
|
let f = Func::new(func_i32__i32);
|
||||||
|
let function = unsafe {
|
||||||
|
std::mem::transmute::<*const FunctionBody, fn(usize, i32) -> i32>(f.address)
|
||||||
|
};
|
||||||
|
assert_eq!(function(0, 3), 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_function_call() {
|
||||||
|
let f = Func::new(func_i32__i32);
|
||||||
|
let x = |args: <(i32, i32) as WasmTypeList>::Array,
|
||||||
|
rets: &mut <(i32, i32) as WasmTypeList>::Array| {
|
||||||
|
let result = func_i32_i32__i32_i32(args[0] as _, args[1] as _);
|
||||||
|
rets[0] = result.0 as _;
|
||||||
|
rets[1] = result.1 as _;
|
||||||
|
};
|
||||||
|
let mut rets = <(i64, i64)>::empty_array();
|
||||||
|
x([20, 10], &mut rets);
|
||||||
|
// panic!("Rets: {:?}",rets);
|
||||||
|
let mut rets = <(i64)>::empty_array();
|
||||||
|
// let result = f.call([1], &mut rets);
|
||||||
|
// assert_eq!(result.is_err(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
lib/api/src/externals/mod.rs
vendored
2
lib/api/src/externals/mod.rs
vendored
@@ -3,7 +3,7 @@ mod global;
|
|||||||
mod memory;
|
mod memory;
|
||||||
mod table;
|
mod table;
|
||||||
|
|
||||||
pub use self::function::Function;
|
pub use self::function::{Function, HostFunction, WasmTypeList};
|
||||||
pub use self::global::Global;
|
pub use self::global::Global;
|
||||||
pub use self::memory::Memory;
|
pub use self::memory::Memory;
|
||||||
pub use self::table::Table;
|
pub use self::table::Table;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ mod types;
|
|||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub use crate::exports::{ExportError, Exportable, Exports};
|
pub use crate::exports::{ExportError, Exportable, Exports};
|
||||||
pub use crate::externals::{Extern, Function, Global, Memory, Table};
|
pub use crate::externals::{Extern, Function, Global, HostFunction, Memory, Table, WasmTypeList};
|
||||||
pub use crate::import_object::{ImportObject, ImportObjectIterator, LikeNamespace};
|
pub use crate::import_object::{ImportObject, ImportObjectIterator, LikeNamespace};
|
||||||
pub use crate::instance::Instance;
|
pub use crate::instance::Instance;
|
||||||
pub use crate::memory_view::{Atomically, MemoryView};
|
pub use crate::memory_view::{Atomically, MemoryView};
|
||||||
@@ -37,8 +37,8 @@ pub use crate::utils::is_wasm;
|
|||||||
|
|
||||||
pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST};
|
pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST};
|
||||||
pub use wasm_common::{
|
pub use wasm_common::{
|
||||||
Bytes, GlobalInit, LocalFunctionIndex, Pages, ValueType, WasmExternType, WasmTypeList,
|
Bytes, GlobalInit, LocalFunctionIndex, Pages, ValueType, WasmExternType, WASM_MAX_PAGES,
|
||||||
WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE,
|
WASM_MIN_PAGES, WASM_PAGE_SIZE,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "compiler")]
|
#[cfg(feature = "compiler")]
|
||||||
pub use wasmer_compiler::CompilerConfig;
|
pub use wasmer_compiler::CompilerConfig;
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ use crate::externals::function::{
|
|||||||
FunctionDefinition, HostFunctionDefinition, VMDynamicFunction, VMDynamicFunctionWithEnv,
|
FunctionDefinition, HostFunctionDefinition, VMDynamicFunction, VMDynamicFunctionWithEnv,
|
||||||
VMDynamicFunctionWithoutEnv, WasmFunctionDefinition,
|
VMDynamicFunctionWithoutEnv, WasmFunctionDefinition,
|
||||||
};
|
};
|
||||||
use crate::{Function, FunctionType, RuntimeError, Store};
|
use crate::{Function, FunctionType, RuntimeError, Store, WasmTypeList};
|
||||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||||
use wasm_common::{NativeWasmType, WasmExternType, WasmTypeList};
|
use wasm_common::{NativeWasmType, WasmExternType};
|
||||||
use wasmer_runtime::{
|
use wasmer_runtime::{
|
||||||
ExportFunction, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind,
|
ExportFunction, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,10 +43,7 @@ pub use crate::indexes::{
|
|||||||
LocalFunctionIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex,
|
LocalFunctionIndex, LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex,
|
||||||
SignatureIndex, TableIndex,
|
SignatureIndex, TableIndex,
|
||||||
};
|
};
|
||||||
pub use crate::native::{
|
pub use crate::native::{NativeWasmType, ValueType, WasmExternType};
|
||||||
Func, HostFunction, NativeWasmType, ValueType, WasmExternType, WasmTypeList, WithEnv,
|
|
||||||
WithoutEnv,
|
|
||||||
};
|
|
||||||
pub use crate::r#ref::{ExternRef, HostInfo, HostRef};
|
pub use crate::r#ref::{ExternRef, HostInfo, HostRef};
|
||||||
pub use crate::units::{Bytes, Pages, WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE};
|
pub use crate::units::{Bytes, Pages, WASM_MAX_PAGES, WASM_MIN_PAGES, WASM_PAGE_SIZE};
|
||||||
pub use crate::values::Value;
|
pub use crate::values::Value;
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
//! This module permits to create native functions
|
//! This module permits to create native functions
|
||||||
//! easily in Rust, thanks to its advanced typing system.
|
//! easily in Rust, thanks to its advanced typing system.
|
||||||
|
|
||||||
use crate::types::{FunctionType, Type};
|
use crate::types::Type;
|
||||||
use crate::values::Value;
|
use crate::values::Value;
|
||||||
use std::convert::Infallible;
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::panic::{self, AssertUnwindSafe};
|
|
||||||
|
|
||||||
/// `NativeWasmType` represents a native Wasm type.
|
/// `NativeWasmType` represents a native Wasm type.
|
||||||
/// It uses the Rust Type system to automatically detect the
|
/// It uses the Rust Type system to automatically detect the
|
||||||
@@ -244,470 +241,3 @@ macro_rules! impl_value_type_for {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl_value_type_for!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
|
impl_value_type_for!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
|
||||||
|
|
||||||
/// Represents a list of WebAssembly values.
|
|
||||||
pub trait WasmTypeList {
|
|
||||||
/// CStruct type.
|
|
||||||
type CStruct;
|
|
||||||
|
|
||||||
/// Array of return values.
|
|
||||||
type Array: AsMut<[i128]>;
|
|
||||||
|
|
||||||
/// Construct `Self` based on an array of returned values.
|
|
||||||
fn from_array(array: Self::Array) -> Self;
|
|
||||||
|
|
||||||
/// Transforms Rust values into an Array
|
|
||||||
fn into_array(self) -> Self::Array;
|
|
||||||
|
|
||||||
/// Generates an empty array that will hold the returned values of
|
|
||||||
/// the WebAssembly function.
|
|
||||||
fn empty_array() -> Self::Array;
|
|
||||||
|
|
||||||
/// Transforms C values into Rust values.
|
|
||||||
fn from_c_struct(c_struct: Self::CStruct) -> Self;
|
|
||||||
|
|
||||||
/// Transforms Rust values into C values.
|
|
||||||
fn into_c_struct(self) -> Self::CStruct;
|
|
||||||
|
|
||||||
/// Get types of the current values.
|
|
||||||
fn wasm_types() -> &'static [Type];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents a TrapEarly type.
|
|
||||||
pub trait TrapEarly<Rets>
|
|
||||||
where
|
|
||||||
Rets: WasmTypeList,
|
|
||||||
{
|
|
||||||
/// The error type for this trait.
|
|
||||||
type Error: Send + 'static;
|
|
||||||
|
|
||||||
/// Get returns or error result.
|
|
||||||
fn report(self) -> Result<Rets, Self::Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Rets> TrapEarly<Rets> for Rets
|
|
||||||
where
|
|
||||||
Rets: WasmTypeList,
|
|
||||||
{
|
|
||||||
type Error = Infallible;
|
|
||||||
|
|
||||||
fn report(self) -> Result<Self, Infallible> {
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Rets, E> TrapEarly<Rets> for Result<Rets, E>
|
|
||||||
where
|
|
||||||
Rets: WasmTypeList,
|
|
||||||
E: Send + 'static,
|
|
||||||
{
|
|
||||||
type Error = E;
|
|
||||||
|
|
||||||
fn report(self) -> Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Empty trait to specify the kind of `HostFunction`: With or
|
|
||||||
/// without a `vm::Ctx` argument. See the `ExplicitVmCtx` and the
|
|
||||||
/// `ImplicitVmCtx` structures.
|
|
||||||
///
|
|
||||||
/// This trait is never aimed to be used by a user. It is used by the
|
|
||||||
/// trait system to automatically generate an appropriate `wrap`
|
|
||||||
/// function.
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub trait HostFunctionKind {}
|
|
||||||
|
|
||||||
/// An empty struct to help Rust typing to determine
|
|
||||||
/// when a `HostFunction` doesn't take an Environment
|
|
||||||
pub struct WithEnv {}
|
|
||||||
|
|
||||||
impl HostFunctionKind for WithEnv {}
|
|
||||||
|
|
||||||
/// An empty struct to help Rust typing to determine
|
|
||||||
/// when a `HostFunction` takes an Environment
|
|
||||||
pub struct WithoutEnv {}
|
|
||||||
|
|
||||||
impl HostFunctionKind for WithoutEnv {}
|
|
||||||
|
|
||||||
/// Represents a function that can be converted to a `vm::Func`
|
|
||||||
/// (function pointer) that can be called within WebAssembly.
|
|
||||||
pub trait HostFunction<Args, Rets, Kind, T>
|
|
||||||
where
|
|
||||||
Args: WasmTypeList,
|
|
||||||
Rets: WasmTypeList,
|
|
||||||
Kind: HostFunctionKind,
|
|
||||||
T: Sized,
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
/// Convert to function pointer.
|
|
||||||
fn to_raw(self) -> *const FunctionBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct FunctionBody(*mut u8);
|
|
||||||
|
|
||||||
/// Represents a function that can be used by WebAssembly.
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
|
||||||
pub struct Func<Args = (), Rets = ()> {
|
|
||||||
address: *const FunctionBody,
|
|
||||||
_phantom: PhantomData<(Args, Rets)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<Args, Rets> Send for Func<Args, Rets> {}
|
|
||||||
|
|
||||||
impl<Args, Rets> Func<Args, Rets>
|
|
||||||
where
|
|
||||||
Args: WasmTypeList,
|
|
||||||
Rets: WasmTypeList,
|
|
||||||
{
|
|
||||||
/// Creates a new `Func`.
|
|
||||||
pub fn new<F, T, E>(func: F) -> Self
|
|
||||||
where
|
|
||||||
F: HostFunction<Args, Rets, T, E>,
|
|
||||||
T: HostFunctionKind,
|
|
||||||
E: Sized,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
address: func.to_raw(),
|
|
||||||
_phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the type of the Func
|
|
||||||
pub fn ty(&self) -> FunctionType {
|
|
||||||
FunctionType::new(Args::wasm_types(), Rets::wasm_types())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the address of the Func
|
|
||||||
pub fn address(&self) -> *const FunctionBody {
|
|
||||||
self.address
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WasmTypeList for Infallible {
|
|
||||||
type CStruct = Self;
|
|
||||||
type Array = [i128; 0];
|
|
||||||
|
|
||||||
fn from_array(_: Self::Array) -> Self {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_array(self) -> Self::Array {
|
|
||||||
[]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn empty_array() -> Self::Array {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_c_struct(_: Self::CStruct) -> Self {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_c_struct(self) -> Self::CStruct {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wasm_types() -> &'static [Type] {
|
|
||||||
&[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_traits {
|
|
||||||
( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => {
|
|
||||||
/// Struct for typed funcs.
|
|
||||||
#[repr($repr)]
|
|
||||||
pub struct $struct_name< $( $x ),* > ( $( <$x as WasmExternType>::Native ),* )
|
|
||||||
where
|
|
||||||
$( $x: WasmExternType ),*;
|
|
||||||
|
|
||||||
#[allow(unused_parens, dead_code)]
|
|
||||||
impl< $( $x ),* > WasmTypeList for ( $( $x ),* )
|
|
||||||
where
|
|
||||||
$( $x: WasmExternType ),*
|
|
||||||
{
|
|
||||||
type CStruct = $struct_name<$( $x ),*>;
|
|
||||||
|
|
||||||
type Array = [i128; count_idents!( $( $x ),* )];
|
|
||||||
|
|
||||||
fn from_array(array: Self::Array) -> Self {
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
let [ $( $x ),* ] = array;
|
|
||||||
|
|
||||||
( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* )
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_array(self) -> Self::Array {
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
let ( $( $x ),* ) = self;
|
|
||||||
[ $( WasmExternType::to_native($x).to_binary() ),* ]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn empty_array() -> Self::Array {
|
|
||||||
[0; count_idents!( $( $x ),* )]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_c_struct(c_struct: Self::CStruct) -> Self {
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
let $struct_name ( $( $x ),* ) = c_struct;
|
|
||||||
|
|
||||||
( $( WasmExternType::from_native($x) ),* )
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_parens, non_snake_case)]
|
|
||||||
fn into_c_struct(self) -> Self::CStruct {
|
|
||||||
let ( $( $x ),* ) = self;
|
|
||||||
|
|
||||||
$struct_name ( $( WasmExternType::to_native($x) ),* )
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wasm_types() -> &'static [Type] {
|
|
||||||
&[$( $x::Native::WASM_TYPE ),*]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_parens)]
|
|
||||||
impl< $( $x, )* Rets, Trap, FN > HostFunction<( $( $x ),* ), Rets, WithoutEnv, ()> for FN
|
|
||||||
where
|
|
||||||
$( $x: WasmExternType, )*
|
|
||||||
Rets: WasmTypeList,
|
|
||||||
Trap: TrapEarly<Rets>,
|
|
||||||
FN: Fn($( $x , )*) -> Trap + 'static + Send,
|
|
||||||
{
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
fn to_raw(self) -> *const FunctionBody {
|
|
||||||
extern fn wrap<$( $x, )* Rets, Trap, FN>( _: usize, $($x: $x::Native, )* ) -> Rets::CStruct
|
|
||||||
where
|
|
||||||
Rets: WasmTypeList,
|
|
||||||
Trap: TrapEarly<Rets>,
|
|
||||||
$( $x: WasmExternType, )*
|
|
||||||
FN: Fn( $( $x ),* ) -> Trap + 'static
|
|
||||||
{
|
|
||||||
let f: &FN = unsafe { &*(&() as *const () as *const FN) };
|
|
||||||
let result = panic::catch_unwind(AssertUnwindSafe(|| {
|
|
||||||
f( $( WasmExternType::from_native($x) ),* ).report()
|
|
||||||
}));
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(Ok(result)) => return result.into_c_struct(),
|
|
||||||
Ok(Err(trap)) => wasmer_runtime::raise_user_trap(Box::new(trap)),
|
|
||||||
Err(panic) => wasmer_runtime::resume_panic(panic),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wrap::<$( $x, )* Rets, Trap, Self> as *const FunctionBody
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_parens)]
|
|
||||||
impl< $( $x, )* Rets, Trap, T, FN > HostFunction<( $( $x ),* ), Rets, WithEnv, T> for FN
|
|
||||||
where
|
|
||||||
$( $x: WasmExternType, )*
|
|
||||||
Rets: WasmTypeList,
|
|
||||||
Trap: TrapEarly<Rets>,
|
|
||||||
T: Sized,
|
|
||||||
FN: Fn(&mut T, $( $x , )*) -> Trap + 'static + Send
|
|
||||||
{
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
fn to_raw(self) -> *const FunctionBody {
|
|
||||||
extern fn wrap<$( $x, )* Rets, Trap, T, FN>( ctx: &mut T, $($x: $x::Native, )* ) -> Rets::CStruct
|
|
||||||
where
|
|
||||||
Rets: WasmTypeList,
|
|
||||||
Trap: TrapEarly<Rets>,
|
|
||||||
$( $x: WasmExternType, )*
|
|
||||||
T: Sized,
|
|
||||||
FN: Fn(&mut T, $( $x ),* ) -> Trap + 'static
|
|
||||||
{
|
|
||||||
let f: &FN = unsafe { &*(&() as *const () as *const FN) };
|
|
||||||
|
|
||||||
let result = panic::catch_unwind(AssertUnwindSafe(|| {
|
|
||||||
f(ctx, $( WasmExternType::from_native($x) ),* ).report()
|
|
||||||
}));
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(Ok(result)) => return result.into_c_struct(),
|
|
||||||
Ok(Err(trap)) => wasmer_runtime::raise_user_trap(Box::new(trap)),
|
|
||||||
Err(panic) => wasmer_runtime::resume_panic(panic),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wrap::<$( $x, )* Rets, Trap, T, Self> as *const FunctionBody
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! count_idents {
|
|
||||||
( $($idents:ident),* ) => {{
|
|
||||||
#[allow(dead_code, non_camel_case_types)]
|
|
||||||
enum Idents { $($idents,)* __CountIdentsLast }
|
|
||||||
const COUNT: usize = Idents::__CountIdentsLast as usize;
|
|
||||||
COUNT
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_traits!([C] S0,);
|
|
||||||
impl_traits!([transparent] S1, A1);
|
|
||||||
impl_traits!([C] S2, A1, A2);
|
|
||||||
impl_traits!([C] S3, A1, A2, A3);
|
|
||||||
impl_traits!([C] S4, A1, A2, A3, A4);
|
|
||||||
impl_traits!([C] S5, A1, A2, A3, A4, A5);
|
|
||||||
impl_traits!([C] S6, A1, A2, A3, A4, A5, A6);
|
|
||||||
impl_traits!([C] S7, A1, A2, A3, A4, A5, A6, A7);
|
|
||||||
impl_traits!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8);
|
|
||||||
impl_traits!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9);
|
|
||||||
impl_traits!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
|
|
||||||
impl_traits!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
|
|
||||||
impl_traits!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
|
|
||||||
impl_traits!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
|
|
||||||
impl_traits!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
|
|
||||||
impl_traits!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15);
|
|
||||||
impl_traits!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);
|
|
||||||
impl_traits!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);
|
|
||||||
impl_traits!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18);
|
|
||||||
impl_traits!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19);
|
|
||||||
impl_traits!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20);
|
|
||||||
// impl_traits!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21);
|
|
||||||
// impl_traits!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22);
|
|
||||||
// impl_traits!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23);
|
|
||||||
// impl_traits!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24);
|
|
||||||
// impl_traits!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25);
|
|
||||||
// impl_traits!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test_wasm_type_list {
|
|
||||||
use super::*;
|
|
||||||
use crate::types::Type;
|
|
||||||
// WasmTypeList
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_simple_values() {
|
|
||||||
// Simple values
|
|
||||||
assert_eq!(<i32>::wasm_types(), [Type::I32]);
|
|
||||||
assert_eq!(<i64>::wasm_types(), [Type::I64]);
|
|
||||||
assert_eq!(<f32>::wasm_types(), [Type::F32]);
|
|
||||||
assert_eq!(<f64>::wasm_types(), [Type::F64]);
|
|
||||||
|
|
||||||
// Multi values
|
|
||||||
assert_eq!(<(i32, i32)>::wasm_types(), [Type::I32, Type::I32]);
|
|
||||||
assert_eq!(<(i64, i64)>::wasm_types(), [Type::I64, Type::I64]);
|
|
||||||
assert_eq!(<(f32, f32)>::wasm_types(), [Type::F32, Type::F32]);
|
|
||||||
assert_eq!(<(f64, f64)>::wasm_types(), [Type::F64, Type::F64]);
|
|
||||||
|
|
||||||
// Mixed values
|
|
||||||
// assert_eq!(<(i32, i64, f32, f64)>::wasm_types(), [Type::I32, Type::I64, Type::F32, Type::F64]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_empty_array() {
|
|
||||||
assert_eq!(<()>::empty_array().len(), 0);
|
|
||||||
assert_eq!(<i32>::empty_array().len(), 1);
|
|
||||||
assert_eq!(<(i32, i64)>::empty_array().len(), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn test_from_array() {
|
|
||||||
// assert_eq!(<()>::from_array([]), ());
|
|
||||||
// assert_eq!(<(i32)>::from_array([1]), (1));
|
|
||||||
// assert_eq!(<(i32, i32)>::from_array([1, 1]), (1, 1));
|
|
||||||
// // This doesn't work
|
|
||||||
// // assert_eq!(<(i32, i64, f32, f64)>::from_array([1, 2, (3.1f32).to_bits().into(), (4.2f64).to_bits().into()]), (1, 2, 3.1f32, 4.2f64));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn test_into_array() {
|
|
||||||
// assert_eq!(().into_array(), []);
|
|
||||||
// assert_eq!((1).into_array(), [1]);
|
|
||||||
// assert_eq!((1, 2).into_array(), [1, 2]);
|
|
||||||
// assert_eq!((1, 2, 3).into_array(), [1, 2, 3]);
|
|
||||||
// // This doesn't work
|
|
||||||
// // assert_eq!(<(i32, i64, f32, f64)>::from_array([1, 2, (3.1f32).to_bits().into(), (4.2f64).to_bits().into()]), (1, 2, 3.1f32, 4.2f64));
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_into_c_struct() {
|
|
||||||
// assert_eq!(<()>::into_c_struct(), &[]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test_func {
|
|
||||||
use super::*;
|
|
||||||
use crate::types::Type;
|
|
||||||
use std::ptr;
|
|
||||||
// WasmTypeList
|
|
||||||
|
|
||||||
fn func() {}
|
|
||||||
fn func__i32() -> i32 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
fn func_i32(_a: i32) {}
|
|
||||||
fn func_i32__i32(a: i32) -> i32 {
|
|
||||||
a * 2
|
|
||||||
}
|
|
||||||
fn func_i32_i32__i32(a: i32, b: i32) -> i32 {
|
|
||||||
a + b
|
|
||||||
}
|
|
||||||
fn func_i32_i32__i32_i32(a: i32, b: i32) -> (i32, i32) {
|
|
||||||
(a, b)
|
|
||||||
}
|
|
||||||
fn func_f32_i32__i32_f32(a: f32, b: i32) -> (i32, f32) {
|
|
||||||
(b, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_function_types() {
|
|
||||||
assert_eq!(Func::new(func).ty(), FunctionType::new(vec![], vec![]));
|
|
||||||
assert_eq!(
|
|
||||||
Func::new(func__i32).ty(),
|
|
||||||
FunctionType::new(vec![], vec![Type::I32])
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Func::new(func_i32).ty(),
|
|
||||||
FunctionType::new(vec![Type::I32], vec![])
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Func::new(func_i32__i32).ty(),
|
|
||||||
FunctionType::new(vec![Type::I32], vec![Type::I32])
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Func::new(func_i32_i32__i32).ty(),
|
|
||||||
FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32])
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Func::new(func_i32_i32__i32_i32).ty(),
|
|
||||||
FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32, Type::I32])
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Func::new(func_f32_i32__i32_f32).ty(),
|
|
||||||
FunctionType::new(vec![Type::F32, Type::I32], vec![Type::I32, Type::F32])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_function_pointer() {
|
|
||||||
let f = Func::new(func_i32__i32);
|
|
||||||
let function =
|
|
||||||
unsafe { std::mem::transmute::<*const FunctionBody, fn(usize, i32) -> i32>(f.address) };
|
|
||||||
assert_eq!(function(0, 3), 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_function_call() {
|
|
||||||
let f = Func::new(func_i32__i32);
|
|
||||||
let x = |args: <(i32, i32) as WasmTypeList>::Array,
|
|
||||||
rets: &mut <(i32, i32) as WasmTypeList>::Array| {
|
|
||||||
let result = func_i32_i32__i32_i32(args[0] as _, args[1] as _);
|
|
||||||
rets[0] = result.0 as _;
|
|
||||||
rets[1] = result.1 as _;
|
|
||||||
};
|
|
||||||
let mut rets = <(i64, i64)>::empty_array();
|
|
||||||
x([20, 10], &mut rets);
|
|
||||||
// panic!("Rets: {:?}",rets);
|
|
||||||
let mut rets = <(i64)>::empty_array();
|
|
||||||
// let result = f.call([1], &mut rets);
|
|
||||||
// assert_eq!(result.is_err(), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user