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},
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 {

View File

@ -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 _) };

View File

@ -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