mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-23 13:41:32 +00:00
Initial typed func rewrite
This commit is contained in:
@ -9,7 +9,7 @@ use crate::{
|
||||
module::{ExportIndex, Module, ModuleInner},
|
||||
sig_registry::SigRegistry,
|
||||
table::Table,
|
||||
typed_func::{Func, Safe, WasmTypeList},
|
||||
typed_func::{Func, Wasm, WasmTypeList},
|
||||
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Value},
|
||||
vm,
|
||||
};
|
||||
@ -107,7 +107,7 @@ impl Instance {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn func<Args, Rets>(&self, name: &str) -> ResolveResult<Func<Args, Rets, Safe>>
|
||||
pub fn func<Args, Rets>(&self, name: &str) -> ResolveResult<Func<Args, Rets, Wasm>>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
@ -157,8 +157,8 @@ impl Instance {
|
||||
}
|
||||
};
|
||||
|
||||
let typed_func: Func<Args, Rets, Safe> =
|
||||
unsafe { Func::new_from_ptr(func_ptr as _, ctx) };
|
||||
let typed_func: Func<Args, Rets, Wasm> =
|
||||
unsafe { Func::from_raw_parts(trampoline, invoke, f as _, ctx, invoke_env) };
|
||||
|
||||
Ok(typed_func)
|
||||
} else {
|
||||
|
@ -6,24 +6,79 @@ use crate::{
|
||||
types::{FuncSig, Type, WasmExternType},
|
||||
vm::Ctx,
|
||||
};
|
||||
use std::{any::Any, cell::UnsafeCell, marker::PhantomData, mem, panic, ptr, sync::Arc};
|
||||
use std::{
|
||||
any::Any, cell::UnsafeCell, ffi::c_void, fmt, marker::PhantomData, mem, panic, ptr, sync::Arc,
|
||||
};
|
||||
|
||||
thread_local! {
|
||||
pub static EARLY_TRAPPER: UnsafeCell<Option<Box<dyn UserTrapper>>> = UnsafeCell::new(None);
|
||||
}
|
||||
|
||||
pub trait Safeness {}
|
||||
pub struct Safe;
|
||||
pub struct Unsafe;
|
||||
impl Safeness for Safe {}
|
||||
impl Safeness for Unsafe {}
|
||||
#[repr(C)]
|
||||
pub enum WasmTrapInfo {
|
||||
Unreachable = 0,
|
||||
IncorrectCallIndirectSignature = 1,
|
||||
MemoryOutOfBounds = 2,
|
||||
CallIndirectOOB = 3,
|
||||
IllegalArithmetic = 4,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl fmt::Display for WasmTrapInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
WasmTrapInfo::Unreachable => "unreachable",
|
||||
WasmTrapInfo::IncorrectCallIndirectSignature => {
|
||||
"incorrect `call_indirect` signature"
|
||||
}
|
||||
WasmTrapInfo::MemoryOutOfBounds => "memory out-of-bounds access",
|
||||
WasmTrapInfo::CallIndirectOOB => "`call_indirect` out-of-bounds",
|
||||
WasmTrapInfo::IllegalArithmetic => "illegal arithmetic operation",
|
||||
WasmTrapInfo::Unknown => "unknown",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Kind {}
|
||||
|
||||
type Trampoline = extern "C" fn(*mut Ctx, *const c_void, *const u64, *mut u64);
|
||||
type Invoke = extern "C" fn(
|
||||
Trampoline,
|
||||
*mut Ctx,
|
||||
*const c_void,
|
||||
*const u64,
|
||||
*mut u64,
|
||||
&mut WasmTrapInfo,
|
||||
) -> bool;
|
||||
|
||||
pub struct Wasm {
|
||||
trampoline: Trampoline,
|
||||
invoke: Invoke,
|
||||
invoke_env: *mut c_void,
|
||||
}
|
||||
|
||||
pub struct Host(());
|
||||
impl Kind for Wasm {}
|
||||
impl Kind for Host {}
|
||||
|
||||
pub trait WasmTypeList {
|
||||
type CStruct;
|
||||
type RetArray: AsMut<[u64]>;
|
||||
fn from_ret_array(array: Self::RetArray) -> Self;
|
||||
fn empty_ret_array() -> Self::RetArray;
|
||||
fn from_c_struct(c_struct: Self::CStruct) -> Self;
|
||||
fn into_c_struct(self) -> Self::CStruct;
|
||||
fn types() -> &'static [Type];
|
||||
unsafe fn call<Rets>(self, f: *const (), ctx: *mut Ctx) -> Rets
|
||||
unsafe fn call<Rets>(
|
||||
self,
|
||||
f: *const c_void,
|
||||
wasm: Wasm,
|
||||
ctx: *mut Ctx,
|
||||
) -> Result<Rets, WasmTrapInfo>
|
||||
where
|
||||
Rets: WasmTypeList;
|
||||
}
|
||||
@ -33,7 +88,7 @@ where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
fn to_raw(&self) -> *const ();
|
||||
fn to_raw(&self) -> *const c_void;
|
||||
}
|
||||
|
||||
pub trait TrapEarly<Rets>
|
||||
@ -71,19 +126,31 @@ where
|
||||
// Func::new(f)
|
||||
// }
|
||||
|
||||
pub struct Func<'a, Args = (), Rets = (), Safety: Safeness = Safe> {
|
||||
f: *const (),
|
||||
pub struct Func<'a, Args = (), Rets = (), Inner: Kind = Wasm> {
|
||||
inner: Inner,
|
||||
f: *const c_void,
|
||||
ctx: *mut Ctx,
|
||||
_phantom: PhantomData<(&'a (), Safety, Args, Rets)>,
|
||||
_phantom: PhantomData<(&'a (), Args, Rets)>,
|
||||
}
|
||||
|
||||
impl<'a, Args, Rets> Func<'a, Args, Rets, Safe>
|
||||
impl<'a, Args, Rets> Func<'a, Args, Rets, Wasm>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
pub(crate) unsafe fn new_from_ptr(f: *const (), ctx: *mut Ctx) -> Func<'a, Args, Rets, Safe> {
|
||||
pub(crate) unsafe fn from_raw_parts(
|
||||
trampoline: Trampoline,
|
||||
invoke: Invoke,
|
||||
f: *const c_void,
|
||||
ctx: *mut Ctx,
|
||||
invoke_env: *mut c_void,
|
||||
) -> Func<'a, Args, Rets, Wasm> {
|
||||
Func {
|
||||
inner: Wasm {
|
||||
trampoline,
|
||||
invoke,
|
||||
invoke_env,
|
||||
},
|
||||
f,
|
||||
ctx,
|
||||
_phantom: PhantomData,
|
||||
@ -91,16 +158,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Args, Rets> Func<'a, Args, Rets, Unsafe>
|
||||
impl<'a, Args, Rets> Func<'a, Args, Rets, Host>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
pub fn new<F>(f: F) -> Func<'a, Args, Rets, Unsafe>
|
||||
pub fn new<F>(f: F) -> Func<'a, Args, Rets, Host>
|
||||
where
|
||||
F: ExternalFunction<Args, Rets>,
|
||||
{
|
||||
Func {
|
||||
inner: Host(()),
|
||||
f: f.to_raw(),
|
||||
ctx: ptr::null_mut(),
|
||||
_phantom: PhantomData,
|
||||
@ -108,11 +176,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Args, Rets, Safety> Func<'a, Args, Rets, Safety>
|
||||
impl<'a, Args, Rets, Inner> Func<'a, Args, Rets, Inner>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
Safety: Safeness,
|
||||
Inner: Kind,
|
||||
{
|
||||
pub fn params(&self) -> &'static [Type] {
|
||||
Args::types()
|
||||
@ -124,6 +192,13 @@ where
|
||||
|
||||
impl<A: WasmExternType> WasmTypeList for (A,) {
|
||||
type CStruct = S1<A>;
|
||||
type RetArray = [u64; 1];
|
||||
fn from_ret_array(array: Self::RetArray) -> Self {
|
||||
(WasmExternType::from_bits(array[0]),)
|
||||
}
|
||||
fn empty_ret_array() -> Self::RetArray {
|
||||
[0u64]
|
||||
}
|
||||
fn from_c_struct(c_struct: Self::CStruct) -> Self {
|
||||
let S1(a) = c_struct;
|
||||
(a,)
|
||||
@ -137,19 +212,45 @@ impl<A: WasmExternType> WasmTypeList for (A,) {
|
||||
&[A::TYPE]
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn call<Rets: WasmTypeList>(self, f: *const (), ctx: *mut Ctx) -> Rets {
|
||||
let f: extern "C" fn(*mut Ctx, A) -> Rets = mem::transmute(f);
|
||||
unsafe fn call<Rets: WasmTypeList>(
|
||||
self,
|
||||
f: *const c_void,
|
||||
wasm: Wasm,
|
||||
ctx: *mut Ctx,
|
||||
) -> Result<Rets, WasmTrapInfo> {
|
||||
// type Trampoline = extern "C" fn(*mut Ctx, *const c_void, *const u64, *mut u64);
|
||||
// type Invoke = extern "C" fn(Trampoline, *mut Ctx, *const c_void, *const u64, *mut u64, &mut WasmTrapInfo) -> bool;
|
||||
|
||||
let (a,) = self;
|
||||
f(ctx, a)
|
||||
let args = [a.to_bits()];
|
||||
let mut rets = Rets::empty_ret_array();
|
||||
let mut trap = WasmTrapInfo::Unknown;
|
||||
|
||||
if (wasm.invoke)(
|
||||
wasm.trampoline,
|
||||
ctx,
|
||||
f,
|
||||
args.as_ptr(),
|
||||
rets.as_mut().as_mut_ptr(),
|
||||
&mut trap,
|
||||
) {
|
||||
Ok(Rets::from_ret_array(rets))
|
||||
} else {
|
||||
Err(trap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: WasmExternType, Rets> Func<'a, (A,), Rets, Safe>
|
||||
impl<'a, A: WasmExternType, Rets> Func<'a, (A,), Rets, Wasm>
|
||||
where
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
pub fn call(&self, a: A) -> Result<Rets, RuntimeError> {
|
||||
Ok(unsafe { <A as WasmTypeList>::call(a, self.f, self.ctx) })
|
||||
unsafe { <A as WasmTypeList>::call(a, self.f, self.inner, self.ctx) }.map_err(|e| {
|
||||
RuntimeError::Trap {
|
||||
msg: e.to_string().into(),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,6 +261,14 @@ macro_rules! impl_traits {
|
||||
|
||||
impl< $( $x: WasmExternType, )* > WasmTypeList for ( $( $x ),* ) {
|
||||
type CStruct = $struct_name<$( $x ),*>;
|
||||
type RetArray = [u64; count_idents!( $( $x ),* )];
|
||||
fn from_ret_array(array: Self::RetArray) -> Self {
|
||||
let [ $( $x ),* ] = array;
|
||||
( $( WasmExternType::from_bits($x) ),* )
|
||||
}
|
||||
fn empty_ret_array() -> Self::RetArray {
|
||||
[0; count_idents!( $( $x ),* )]
|
||||
}
|
||||
fn from_c_struct(c_struct: Self::CStruct) -> Self {
|
||||
#[allow(non_snake_case)]
|
||||
let $struct_name ( $( $x ),* ) = c_struct;
|
||||
@ -174,18 +283,33 @@ macro_rules! impl_traits {
|
||||
&[$( $x::TYPE, )*]
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn call<Rets: WasmTypeList>(self, f: *const (), ctx: *mut Ctx) -> Rets {
|
||||
let f: extern fn(*mut Ctx $( ,$x )*) -> Rets::CStruct = mem::transmute(f);
|
||||
unsafe fn call<Rets: WasmTypeList>(self, f: *const c_void, wasm: Wasm, ctx: *mut Ctx) -> Result<Rets, WasmTrapInfo> {
|
||||
// type Trampoline = extern "C" fn(*mut Ctx, *const c_void, *const u64, *mut u64);
|
||||
// type Invoke = extern "C" fn(Trampoline, *mut Ctx, *const c_void, *const u64, *mut u64, &mut WasmTrapInfo) -> bool;
|
||||
|
||||
#[allow(unused_parens)]
|
||||
let ( $( $x ),* ) = self;
|
||||
let c_struct = f(ctx $( ,$x )*);
|
||||
Rets::from_c_struct(c_struct)
|
||||
let args = [ $( $x.to_bits() ),* ];
|
||||
let mut rets = Rets::empty_ret_array();
|
||||
let mut trap = WasmTrapInfo::Unknown;
|
||||
|
||||
if (wasm.invoke)(wasm.trampoline, ctx, f, args.as_ptr(), rets.as_mut().as_mut_ptr(), &mut trap) {
|
||||
Ok(Rets::from_ret_array(rets))
|
||||
} else {
|
||||
Err(trap)
|
||||
}
|
||||
|
||||
// let f: extern fn(*mut Ctx $( ,$x )*) -> Rets::CStruct = mem::transmute(f);
|
||||
// #[allow(unused_parens)]
|
||||
// let ( $( $x ),* ) = self;
|
||||
// let c_struct = f(ctx $( ,$x )*);
|
||||
// Rets::from_c_struct(c_struct)
|
||||
}
|
||||
}
|
||||
|
||||
impl< $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap> ExternalFunction<($( $x ),*), Rets> for FN {
|
||||
#[allow(non_snake_case)]
|
||||
fn to_raw(&self) -> *const () {
|
||||
fn to_raw(&self) -> *const c_void {
|
||||
assert_eq!(mem::size_of::<Self>(), 0, "you cannot use a closure that captures state for `Func`.");
|
||||
|
||||
extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap>( ctx: &mut Ctx $( ,$x: $x )* ) -> Rets::CStruct {
|
||||
@ -209,23 +333,36 @@ macro_rules! impl_traits {
|
||||
}
|
||||
}
|
||||
|
||||
wrap::<$( $x, )* Rets, Trap, Self> as *const ()
|
||||
wrap::<$( $x, )* Rets, Trap, Self> as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, $( $x: WasmExternType, )* Rets> Func<'a, ( $( $x ),* ), Rets, Safe>
|
||||
impl<'a, $( $x: WasmExternType, )* Rets> Func<'a, ( $( $x ),* ), Rets, Wasm>
|
||||
where
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
#[allow(non_snake_case)]
|
||||
pub fn call(&self, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
|
||||
#[allow(unused_parens)]
|
||||
Ok(unsafe { <( $( $x ),* ) as WasmTypeList>::call(( $($x),* ), self.f, self.ctx) })
|
||||
unsafe { <( $( $x ),* ) as WasmTypeList>::call(( $($x),* ), self.f, self.inner, self.ctx) }.map_err(|e| {
|
||||
RuntimeError::Trap {
|
||||
msg: e.to_string().into(),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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, A);
|
||||
impl_traits!([C] S2, A, B);
|
||||
@ -240,11 +377,11 @@ impl_traits!([C] S10, A, B, C, D, E, F, G, H, I, J);
|
||||
impl_traits!([C] S11, A, B, C, D, E, F, G, H, I, J, K);
|
||||
impl_traits!([C] S12, A, B, C, D, E, F, G, H, I, J, K, L);
|
||||
|
||||
impl<'a, Args, Rets, Safety> IsExport for Func<'a, Args, Rets, Safety>
|
||||
impl<'a, Args, Rets, Inner> IsExport for Func<'a, Args, Rets, Inner>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
Safety: Safeness,
|
||||
Inner: Kind,
|
||||
{
|
||||
fn to_export(&self) -> Export {
|
||||
let func = unsafe { FuncPointer::new(self.f as _) };
|
||||
|
@ -76,37 +76,99 @@ where
|
||||
Self: Sized,
|
||||
{
|
||||
const TYPE: Type;
|
||||
fn to_bits(self) -> u64;
|
||||
fn from_bits(n: u64) -> Self;
|
||||
}
|
||||
|
||||
unsafe impl WasmExternType for i8 {
|
||||
const TYPE: Type = Type::I32;
|
||||
fn to_bits(self) -> u64 {
|
||||
self as u64
|
||||
}
|
||||
fn from_bits(n: u64) -> Self {
|
||||
n as _
|
||||
}
|
||||
}
|
||||
unsafe impl WasmExternType for u8 {
|
||||
const TYPE: Type = Type::I32;
|
||||
fn to_bits(self) -> u64 {
|
||||
self as u64
|
||||
}
|
||||
fn from_bits(n: u64) -> Self {
|
||||
n as _
|
||||
}
|
||||
}
|
||||
unsafe impl WasmExternType for i16 {
|
||||
const TYPE: Type = Type::I32;
|
||||
fn to_bits(self) -> u64 {
|
||||
self as u64
|
||||
}
|
||||
fn from_bits(n: u64) -> Self {
|
||||
n as _
|
||||
}
|
||||
}
|
||||
unsafe impl WasmExternType for u16 {
|
||||
const TYPE: Type = Type::I32;
|
||||
fn to_bits(self) -> u64 {
|
||||
self as u64
|
||||
}
|
||||
fn from_bits(n: u64) -> Self {
|
||||
n as _
|
||||
}
|
||||
}
|
||||
unsafe impl WasmExternType for i32 {
|
||||
const TYPE: Type = Type::I32;
|
||||
fn to_bits(self) -> u64 {
|
||||
self as u64
|
||||
}
|
||||
fn from_bits(n: u64) -> Self {
|
||||
n as _
|
||||
}
|
||||
}
|
||||
unsafe impl WasmExternType for u32 {
|
||||
const TYPE: Type = Type::I32;
|
||||
fn to_bits(self) -> u64 {
|
||||
self as u64
|
||||
}
|
||||
fn from_bits(n: u64) -> Self {
|
||||
n as _
|
||||
}
|
||||
}
|
||||
unsafe impl WasmExternType for i64 {
|
||||
const TYPE: Type = Type::I64;
|
||||
fn to_bits(self) -> u64 {
|
||||
self as u64
|
||||
}
|
||||
fn from_bits(n: u64) -> Self {
|
||||
n as _
|
||||
}
|
||||
}
|
||||
unsafe impl WasmExternType for u64 {
|
||||
const TYPE: Type = Type::I64;
|
||||
fn to_bits(self) -> u64 {
|
||||
self
|
||||
}
|
||||
fn from_bits(n: u64) -> Self {
|
||||
n
|
||||
}
|
||||
}
|
||||
unsafe impl WasmExternType for f32 {
|
||||
const TYPE: Type = Type::F32;
|
||||
fn to_bits(self) -> u64 {
|
||||
self.to_bits() as u64
|
||||
}
|
||||
fn from_bits(n: u64) -> Self {
|
||||
f32::from_bits(n as u32)
|
||||
}
|
||||
}
|
||||
unsafe impl WasmExternType for f64 {
|
||||
const TYPE: Type = Type::F64;
|
||||
fn to_bits(self) -> u64 {
|
||||
self.to_bits()
|
||||
}
|
||||
fn from_bits(n: u64) -> Self {
|
||||
f64::from_bits(n)
|
||||
}
|
||||
}
|
||||
|
||||
// pub trait IntegerAtomic
|
||||
|
Reference in New Issue
Block a user