Initial typed func rewrite

This commit is contained in:
Lachlan Sneff
2019-04-09 12:48:41 -07:00
parent 80b809383e
commit 5e1a67d835
3 changed files with 235 additions and 36 deletions

View File

@ -9,7 +9,7 @@ use crate::{
module::{ExportIndex, Module, ModuleInner}, module::{ExportIndex, Module, ModuleInner},
sig_registry::SigRegistry, sig_registry::SigRegistry,
table::Table, table::Table,
typed_func::{Func, Safe, WasmTypeList}, typed_func::{Func, Wasm, WasmTypeList},
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Value}, types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Value},
vm, vm,
}; };
@ -107,7 +107,7 @@ impl Instance {
/// # Ok(()) /// # 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 where
Args: WasmTypeList, Args: WasmTypeList,
Rets: WasmTypeList, Rets: WasmTypeList,
@ -157,8 +157,8 @@ impl Instance {
} }
}; };
let typed_func: Func<Args, Rets, Safe> = let typed_func: Func<Args, Rets, Wasm> =
unsafe { Func::new_from_ptr(func_ptr as _, ctx) }; unsafe { Func::from_raw_parts(trampoline, invoke, f as _, ctx, invoke_env) };
Ok(typed_func) Ok(typed_func)
} else { } else {

View File

@ -6,24 +6,79 @@ use crate::{
types::{FuncSig, Type, WasmExternType}, types::{FuncSig, Type, WasmExternType},
vm::Ctx, 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! { thread_local! {
pub static EARLY_TRAPPER: UnsafeCell<Option<Box<dyn UserTrapper>>> = UnsafeCell::new(None); pub static EARLY_TRAPPER: UnsafeCell<Option<Box<dyn UserTrapper>>> = UnsafeCell::new(None);
} }
pub trait Safeness {} #[repr(C)]
pub struct Safe; pub enum WasmTrapInfo {
pub struct Unsafe; Unreachable = 0,
impl Safeness for Safe {} IncorrectCallIndirectSignature = 1,
impl Safeness for Unsafe {} 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 { pub trait WasmTypeList {
type CStruct; 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 from_c_struct(c_struct: Self::CStruct) -> Self;
fn into_c_struct(self) -> Self::CStruct; fn into_c_struct(self) -> Self::CStruct;
fn types() -> &'static [Type]; 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 where
Rets: WasmTypeList; Rets: WasmTypeList;
} }
@ -33,7 +88,7 @@ where
Args: WasmTypeList, Args: WasmTypeList,
Rets: WasmTypeList, Rets: WasmTypeList,
{ {
fn to_raw(&self) -> *const (); fn to_raw(&self) -> *const c_void;
} }
pub trait TrapEarly<Rets> pub trait TrapEarly<Rets>
@ -71,19 +126,31 @@ where
// Func::new(f) // Func::new(f)
// } // }
pub struct Func<'a, Args = (), Rets = (), Safety: Safeness = Safe> { pub struct Func<'a, Args = (), Rets = (), Inner: Kind = Wasm> {
f: *const (), inner: Inner,
f: *const c_void,
ctx: *mut Ctx, 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 where
Args: WasmTypeList, Args: WasmTypeList,
Rets: 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 { Func {
inner: Wasm {
trampoline,
invoke,
invoke_env,
},
f, f,
ctx, ctx,
_phantom: PhantomData, _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 where
Args: WasmTypeList, Args: WasmTypeList,
Rets: 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 where
F: ExternalFunction<Args, Rets>, F: ExternalFunction<Args, Rets>,
{ {
Func { Func {
inner: Host(()),
f: f.to_raw(), f: f.to_raw(),
ctx: ptr::null_mut(), ctx: ptr::null_mut(),
_phantom: PhantomData, _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 where
Args: WasmTypeList, Args: WasmTypeList,
Rets: WasmTypeList, Rets: WasmTypeList,
Safety: Safeness, Inner: Kind,
{ {
pub fn params(&self) -> &'static [Type] { pub fn params(&self) -> &'static [Type] {
Args::types() Args::types()
@ -124,6 +192,13 @@ where
impl<A: WasmExternType> WasmTypeList for (A,) { impl<A: WasmExternType> WasmTypeList for (A,) {
type CStruct = S1<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 { fn from_c_struct(c_struct: Self::CStruct) -> Self {
let S1(a) = c_struct; let S1(a) = c_struct;
(a,) (a,)
@ -137,19 +212,45 @@ impl<A: WasmExternType> WasmTypeList for (A,) {
&[A::TYPE] &[A::TYPE]
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe fn call<Rets: WasmTypeList>(self, f: *const (), ctx: *mut Ctx) -> Rets { unsafe fn call<Rets: WasmTypeList>(
let f: extern "C" fn(*mut Ctx, A) -> Rets = mem::transmute(f); 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; 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 where
Rets: WasmTypeList, Rets: WasmTypeList,
{ {
pub fn call(&self, a: A) -> Result<Rets, RuntimeError> { 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 ),* ) { impl< $( $x: WasmExternType, )* > WasmTypeList for ( $( $x ),* ) {
type CStruct = $struct_name<$( $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 { fn from_c_struct(c_struct: Self::CStruct) -> Self {
#[allow(non_snake_case)] #[allow(non_snake_case)]
let $struct_name ( $( $x ),* ) = c_struct; let $struct_name ( $( $x ),* ) = c_struct;
@ -174,18 +283,33 @@ macro_rules! impl_traits {
&[$( $x::TYPE, )*] &[$( $x::TYPE, )*]
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe fn call<Rets: WasmTypeList>(self, f: *const (), ctx: *mut Ctx) -> Rets { unsafe fn call<Rets: WasmTypeList>(self, f: *const c_void, wasm: Wasm, ctx: *mut Ctx) -> Result<Rets, WasmTrapInfo> {
let f: extern fn(*mut Ctx $( ,$x )*) -> Rets::CStruct = mem::transmute(f); // 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)] #[allow(unused_parens)]
let ( $( $x ),* ) = self; let ( $( $x ),* ) = self;
let c_struct = f(ctx $( ,$x )*); let args = [ $( $x.to_bits() ),* ];
Rets::from_c_struct(c_struct) 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 { impl< $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap> ExternalFunction<($( $x ),*), Rets> for FN {
#[allow(non_snake_case)] #[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`."); 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 { 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 where
Rets: WasmTypeList, Rets: WasmTypeList,
{ {
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn call(&self, $( $x: $x, )* ) -> Result<Rets, RuntimeError> { pub fn call(&self, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
#[allow(unused_parens)] #[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!([C] S0,);
impl_traits!([transparent] S1, A); impl_traits!([transparent] S1, A);
impl_traits!([C] S2, A, B); 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] 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_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 where
Args: WasmTypeList, Args: WasmTypeList,
Rets: WasmTypeList, Rets: WasmTypeList,
Safety: Safeness, Inner: Kind,
{ {
fn to_export(&self) -> Export { fn to_export(&self) -> Export {
let func = unsafe { FuncPointer::new(self.f as _) }; let func = unsafe { FuncPointer::new(self.f as _) };

View File

@ -76,37 +76,99 @@ where
Self: Sized, Self: Sized,
{ {
const TYPE: Type; const TYPE: Type;
fn to_bits(self) -> u64;
fn from_bits(n: u64) -> Self;
} }
unsafe impl WasmExternType for i8 { unsafe impl WasmExternType for i8 {
const TYPE: Type = Type::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 u8 { unsafe impl WasmExternType for u8 {
const TYPE: Type = Type::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 i16 { unsafe impl WasmExternType for i16 {
const TYPE: Type = Type::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 u16 { unsafe impl WasmExternType for u16 {
const TYPE: Type = Type::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 i32 { unsafe impl WasmExternType for i32 {
const TYPE: Type = Type::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 { unsafe impl WasmExternType for u32 {
const TYPE: Type = Type::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 i64 { unsafe impl WasmExternType for i64 {
const TYPE: Type = Type::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 { unsafe impl WasmExternType for u64 {
const TYPE: Type = Type::I64; const TYPE: Type = Type::I64;
fn to_bits(self) -> u64 {
self
}
fn from_bits(n: u64) -> Self {
n
}
} }
unsafe impl WasmExternType for f32 { unsafe impl WasmExternType for f32 {
const TYPE: Type = Type::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 { unsafe impl WasmExternType for f64 {
const TYPE: Type = Type::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 // pub trait IntegerAtomic