wasmtime: Modify WasmTy and WasmRet for future {extern,func}ref support
This commit is contained in:
@@ -193,17 +193,26 @@ macro_rules! getters {
|
|||||||
unsafe extern "C" fn(
|
unsafe extern "C" fn(
|
||||||
*mut VMContext,
|
*mut VMContext,
|
||||||
*mut VMContext,
|
*mut VMContext,
|
||||||
$($args,)*
|
$( $args::Abi, )*
|
||||||
) -> R,
|
) -> R::Abi,
|
||||||
>(anyfunc.as_ref().func_ptr.as_ptr());
|
>(anyfunc.as_ref().func_ptr.as_ptr());
|
||||||
|
|
||||||
let mut ret = None;
|
let mut ret = None;
|
||||||
$(let $args = $args.into_abi();)*
|
|
||||||
|
let weak_store = instance.store.weak();
|
||||||
|
let weak_store = WeakStore(&weak_store);
|
||||||
|
|
||||||
|
$( let $args = $args.into_abi_for_arg(weak_store); )*
|
||||||
|
|
||||||
invoke_wasm_and_catch_traps(anyfunc.as_ref().vmctx, &instance.store, || {
|
invoke_wasm_and_catch_traps(anyfunc.as_ref().vmctx, &instance.store, || {
|
||||||
ret = Some(fnptr(anyfunc.as_ref().vmctx, ptr::null_mut(), $($args,)*));
|
ret = Some(fnptr(
|
||||||
|
anyfunc.as_ref().vmctx,
|
||||||
|
ptr::null_mut(),
|
||||||
|
$( $args, )*
|
||||||
|
));
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(ret.unwrap())
|
Ok(R::from_abi(ret.unwrap(), weak_store))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -783,6 +792,12 @@ pub(crate) fn invoke_wasm_and_catch_traps(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Public (but hidden) wrapper around a `Weak<StoreInner>` so that we can use it
|
||||||
|
// in public (but hidden) trait methods.
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct WeakStore<'a>(&'a Weak<StoreInner>);
|
||||||
|
|
||||||
/// A trait implemented for types which can be arguments to closures passed to
|
/// A trait implemented for types which can be arguments to closures passed to
|
||||||
/// [`Func::wrap`] and friends.
|
/// [`Func::wrap`] and friends.
|
||||||
///
|
///
|
||||||
@@ -791,160 +806,40 @@ pub(crate) fn invoke_wasm_and_catch_traps(
|
|||||||
/// stable over time.
|
/// stable over time.
|
||||||
///
|
///
|
||||||
/// For more information see [`Func::wrap`]
|
/// For more information see [`Func::wrap`]
|
||||||
pub unsafe trait WasmTy: Copy {
|
pub unsafe trait WasmTy {
|
||||||
|
// The raw ABI representation of this type inside Wasm.
|
||||||
|
#[doc(hidden)]
|
||||||
|
type Abi: Copy;
|
||||||
|
|
||||||
|
// Convert this value into its ABI representation, when passing a value into
|
||||||
|
// Wasm as an argument.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn into_abi_for_arg<'a>(self, store: WeakStore<'a>) -> Self::Abi;
|
||||||
|
|
||||||
|
// Convert from the raw ABI representation back into `Self`, when receiving
|
||||||
|
// a value from Wasm.
|
||||||
|
//
|
||||||
|
// Safety: The abi value *must* have be valid for this type (e.g. for
|
||||||
|
// `externref`, it must be a valid raw `VMExternRef` pointer, not some
|
||||||
|
// random, dangling pointer).
|
||||||
|
#[doc(hidden)]
|
||||||
|
unsafe fn from_abi<'a>(abi: Self::Abi, store: WeakStore<'a>) -> Self;
|
||||||
|
|
||||||
|
// Add this type to the given vec of expected valtypes.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn push(dst: &mut Vec<ValType>);
|
fn push(dst: &mut Vec<ValType>);
|
||||||
|
|
||||||
|
// Does the next valtype(s) match this type?
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()>;
|
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()>;
|
||||||
|
|
||||||
|
// Load this type's raw ABI representation from an args array.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
unsafe fn load(ptr: &mut *const u128) -> Self;
|
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi;
|
||||||
|
|
||||||
|
// Store this type's raw ABI representation into an args array.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
unsafe fn store(abi: Self, ptr: *mut u128);
|
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128);
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl WasmTy for () {
|
|
||||||
fn push(_dst: &mut Vec<ValType>) {}
|
|
||||||
fn matches(_tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn load(_ptr: &mut *const u128) -> Self {}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn store(_abi: Self, _ptr: *mut u128) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl WasmTy for i32 {
|
|
||||||
fn push(dst: &mut Vec<ValType>) {
|
|
||||||
dst.push(ValType::I32);
|
|
||||||
}
|
|
||||||
fn matches(mut tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
|
||||||
let next = tys.next();
|
|
||||||
ensure!(
|
|
||||||
next == Some(ValType::I32),
|
|
||||||
"Type mismatch, expected i32, got {:?}",
|
|
||||||
next
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn load(ptr: &mut *const u128) -> Self {
|
|
||||||
let ret = **ptr as Self;
|
|
||||||
*ptr = (*ptr).add(1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn store(abi: Self, ptr: *mut u128) {
|
|
||||||
*ptr = abi as u128;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl WasmTy for u32 {
|
|
||||||
fn push(dst: &mut Vec<ValType>) {
|
|
||||||
<i32 as WasmTy>::push(dst)
|
|
||||||
}
|
|
||||||
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
|
||||||
<i32 as WasmTy>::matches(tys)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn load(ptr: &mut *const u128) -> Self {
|
|
||||||
<i32 as WasmTy>::load(ptr) as Self
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn store(abi: Self, ptr: *mut u128) {
|
|
||||||
<i32 as WasmTy>::store(abi as i32, ptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl WasmTy for i64 {
|
|
||||||
fn push(dst: &mut Vec<ValType>) {
|
|
||||||
dst.push(ValType::I64);
|
|
||||||
}
|
|
||||||
fn matches(mut tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
|
||||||
let next = tys.next();
|
|
||||||
ensure!(
|
|
||||||
next == Some(ValType::I64),
|
|
||||||
"Type mismatch, expected i64, got {:?}",
|
|
||||||
next
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn load(ptr: &mut *const u128) -> Self {
|
|
||||||
let ret = **ptr as Self;
|
|
||||||
*ptr = (*ptr).add(1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn store(abi: Self, ptr: *mut u128) {
|
|
||||||
*ptr = abi as u128;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl WasmTy for u64 {
|
|
||||||
fn push(dst: &mut Vec<ValType>) {
|
|
||||||
<i64 as WasmTy>::push(dst)
|
|
||||||
}
|
|
||||||
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
|
||||||
<i64 as WasmTy>::matches(tys)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn load(ptr: &mut *const u128) -> Self {
|
|
||||||
<i64 as WasmTy>::load(ptr) as Self
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn store(abi: Self, ptr: *mut u128) {
|
|
||||||
<i64 as WasmTy>::store(abi as i64, ptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl WasmTy for f32 {
|
|
||||||
fn push(dst: &mut Vec<ValType>) {
|
|
||||||
dst.push(ValType::F32);
|
|
||||||
}
|
|
||||||
fn matches(mut tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
|
||||||
let next = tys.next();
|
|
||||||
ensure!(
|
|
||||||
next == Some(ValType::F32),
|
|
||||||
"Type mismatch, expected f32, got {:?}",
|
|
||||||
next
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn load(ptr: &mut *const u128) -> Self {
|
|
||||||
let ret = f32::from_bits(**ptr as u32);
|
|
||||||
*ptr = (*ptr).add(1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn store(abi: Self, ptr: *mut u128) {
|
|
||||||
*ptr = abi.to_bits() as u128;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl WasmTy for f64 {
|
|
||||||
fn push(dst: &mut Vec<ValType>) {
|
|
||||||
dst.push(ValType::F64);
|
|
||||||
}
|
|
||||||
fn matches(mut tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
|
||||||
let next = tys.next();
|
|
||||||
ensure!(
|
|
||||||
next == Some(ValType::F64),
|
|
||||||
"Type mismatch, expected f64, got {:?}",
|
|
||||||
next
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn load(ptr: &mut *const u128) -> Self {
|
|
||||||
let ret = f64::from_bits(**ptr as u64);
|
|
||||||
*ptr = (*ptr).add(1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
unsafe fn store(abi: Self, ptr: *mut u128) {
|
|
||||||
*ptr = abi.to_bits() as u128;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait implemented for types which can be returned from closures passed to
|
/// A trait implemented for types which can be returned from closures passed to
|
||||||
@@ -956,64 +851,362 @@ unsafe impl WasmTy for f64 {
|
|||||||
///
|
///
|
||||||
/// For more information see [`Func::wrap`]
|
/// For more information see [`Func::wrap`]
|
||||||
pub unsafe trait WasmRet {
|
pub unsafe trait WasmRet {
|
||||||
|
// Same as `WasmTy::Abi`.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
type Abi;
|
type Abi: Copy;
|
||||||
|
|
||||||
|
// Similar to `WasmTy::into_abi_for_arg` but used when host code is
|
||||||
|
// returning a value into Wasm, rather than host code passing an argument to
|
||||||
|
// a Wasm call. Unlike `into_abi_for_arg`, implementors of this method can
|
||||||
|
// raise traps, which means that callers must ensure that
|
||||||
|
// `invoke_wasm_and_catch_traps` is on the stack, and therefore this method
|
||||||
|
// is unsafe.
|
||||||
|
#[doc(hidden)]
|
||||||
|
unsafe fn into_abi_for_ret<'a>(self, store: WeakStore<'a>) -> Self::Abi;
|
||||||
|
|
||||||
|
// Same as `WasmTy::from_abi`.
|
||||||
|
#[doc(hidden)]
|
||||||
|
unsafe fn from_abi<'a>(abi: Self::Abi, store: WeakStore<'a>) -> Self;
|
||||||
|
|
||||||
|
// Same as `WasmTy::push`.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn push(dst: &mut Vec<ValType>);
|
fn push(dst: &mut Vec<ValType>);
|
||||||
|
|
||||||
|
// Same as `WasmTy::matches`.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()>;
|
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()>;
|
||||||
|
|
||||||
|
// Same as `WasmTy::load_from_args`.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn into_abi(self) -> Self::Abi;
|
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi;
|
||||||
|
|
||||||
|
// Same as `WasmTy::store_to_args`.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
unsafe fn store(abi: Self::Abi, ptr: *mut u128);
|
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: WasmTy> WasmRet for T {
|
unsafe impl WasmTy for () {
|
||||||
type Abi = T;
|
type Abi = Self;
|
||||||
fn push(dst: &mut Vec<ValType>) {
|
|
||||||
T::push(dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
#[inline]
|
||||||
T::matches(tys)
|
fn into_abi_for_arg<'a>(self, _store: WeakStore<'a>) -> Self::Abi {}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn from_abi<'a>(_abi: Self::Abi, _store: WeakStore<'a>) -> Self {}
|
||||||
|
|
||||||
|
fn push(_dst: &mut Vec<ValType>) {}
|
||||||
|
|
||||||
|
fn matches(_tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_abi(self) -> Self::Abi {
|
unsafe fn load_from_args(_ptr: &mut *const u128) -> Self::Abi {}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn store_to_args(_abi: Self::Abi, _ptr: *mut u128) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl WasmTy for i32 {
|
||||||
|
type Abi = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_abi_for_arg<'a>(self, _store: WeakStore<'a>) -> Self::Abi {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn store(abi: Self::Abi, ptr: *mut u128) {
|
unsafe fn from_abi<'a>(abi: Self::Abi, _store: WeakStore<'a>) -> Self {
|
||||||
T::store(abi, ptr);
|
abi
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(dst: &mut Vec<ValType>) {
|
||||||
|
dst.push(ValType::I32);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches(mut tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
||||||
|
let next = tys.next();
|
||||||
|
ensure!(
|
||||||
|
next == Some(ValType::I32),
|
||||||
|
"Type mismatch, expected i32, got {:?}",
|
||||||
|
next
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
|
||||||
|
let ret = **ptr as Self;
|
||||||
|
*ptr = (*ptr).add(1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
|
||||||
|
*ptr = abi as u128;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: WasmTy> WasmRet for Result<T, Trap> {
|
unsafe impl WasmTy for u32 {
|
||||||
type Abi = T;
|
type Abi = <i32 as WasmTy>::Abi;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_abi_for_arg<'a>(self, _store: WeakStore<'a>) -> Self::Abi {
|
||||||
|
self as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn from_abi<'a>(abi: Self::Abi, _store: WeakStore<'a>) -> Self {
|
||||||
|
abi as Self
|
||||||
|
}
|
||||||
|
|
||||||
fn push(dst: &mut Vec<ValType>) {
|
fn push(dst: &mut Vec<ValType>) {
|
||||||
T::push(dst)
|
<i32 as WasmTy>::push(dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
||||||
T::matches(tys)
|
<i32 as WasmTy>::matches(tys)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_abi(self) -> Self::Abi {
|
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
|
||||||
|
<i32 as WasmTy>::load_from_args(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
|
||||||
|
<i32 as WasmTy>::store_to_args(abi, ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl WasmTy for i64 {
|
||||||
|
type Abi = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_abi_for_arg<'a>(self, _store: WeakStore<'a>) -> Self::Abi {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn from_abi<'a>(abi: Self::Abi, _store: WeakStore<'a>) -> Self {
|
||||||
|
abi
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(dst: &mut Vec<ValType>) {
|
||||||
|
dst.push(ValType::I64);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches(mut tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
||||||
|
let next = tys.next();
|
||||||
|
ensure!(
|
||||||
|
next == Some(ValType::I64),
|
||||||
|
"Type mismatch, expected i64, got {:?}",
|
||||||
|
next
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
|
||||||
|
let ret = **ptr as Self;
|
||||||
|
*ptr = (*ptr).add(1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
|
||||||
|
*ptr = abi as u128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl WasmTy for u64 {
|
||||||
|
type Abi = <i64 as WasmTy>::Abi;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_abi_for_arg<'a>(self, _store: WeakStore<'a>) -> Self::Abi {
|
||||||
|
self as i64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn from_abi<'a>(abi: Self::Abi, _store: WeakStore<'a>) -> Self {
|
||||||
|
abi as Self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(dst: &mut Vec<ValType>) {
|
||||||
|
<i64 as WasmTy>::push(dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
||||||
|
<i64 as WasmTy>::matches(tys)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
|
||||||
|
<i64 as WasmTy>::load_from_args(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
|
||||||
|
<i64 as WasmTy>::store_to_args(abi, ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl WasmTy for f32 {
|
||||||
|
type Abi = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_abi_for_arg<'a>(self, _store: WeakStore<'a>) -> Self::Abi {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn from_abi<'a>(abi: Self::Abi, _store: WeakStore<'a>) -> Self {
|
||||||
|
abi
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(dst: &mut Vec<ValType>) {
|
||||||
|
dst.push(ValType::F32);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches(mut tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
||||||
|
let next = tys.next();
|
||||||
|
ensure!(
|
||||||
|
next == Some(ValType::F32),
|
||||||
|
"Type mismatch, expected f32, got {:?}",
|
||||||
|
next
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
|
||||||
|
let ret = f32::from_bits(**ptr as u32);
|
||||||
|
*ptr = (*ptr).add(1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
|
||||||
|
*ptr = abi.to_bits() as u128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl WasmTy for f64 {
|
||||||
|
type Abi = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_abi_for_arg<'a>(self, _store: WeakStore<'a>) -> Self::Abi {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn from_abi<'a>(abi: Self::Abi, _store: WeakStore<'a>) -> Self {
|
||||||
|
abi
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(dst: &mut Vec<ValType>) {
|
||||||
|
dst.push(ValType::F64);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches(mut tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
||||||
|
let next = tys.next();
|
||||||
|
ensure!(
|
||||||
|
next == Some(ValType::F64),
|
||||||
|
"Type mismatch, expected f64, got {:?}",
|
||||||
|
next
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
|
||||||
|
let ret = f64::from_bits(**ptr as u64);
|
||||||
|
*ptr = (*ptr).add(1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
|
||||||
|
*ptr = abi.to_bits() as u128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T> WasmRet for T
|
||||||
|
where
|
||||||
|
T: WasmTy,
|
||||||
|
{
|
||||||
|
type Abi = <T as WasmTy>::Abi;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn into_abi_for_ret<'a>(self, store: WeakStore<'a>) -> Self::Abi {
|
||||||
|
<Self as WasmTy>::into_abi_for_arg(self, store)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn from_abi<'a>(abi: Self::Abi, store: WeakStore<'a>) -> Self {
|
||||||
|
<Self as WasmTy>::from_abi(abi, store)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn push(dst: &mut Vec<ValType>) {
|
||||||
|
<Self as WasmTy>::push(dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
||||||
|
<Self as WasmTy>::matches(tys)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
|
||||||
|
<Self as WasmTy>::load_from_args(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
|
||||||
|
<Self as WasmTy>::store_to_args(abi, ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T> WasmRet for Result<T, Trap>
|
||||||
|
where
|
||||||
|
T: WasmTy,
|
||||||
|
{
|
||||||
|
type Abi = <T as WasmTy>::Abi;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn into_abi_for_ret<'a>(self, store: WeakStore<'a>) -> Self::Abi {
|
||||||
match self {
|
match self {
|
||||||
Ok(val) => return T::into_abi(val),
|
Ok(val) => return <T as WasmTy>::into_abi_for_arg(val, store),
|
||||||
Err(trap) => handle_trap(trap),
|
Err(trap) => handle_trap(trap),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_trap(trap: Trap) -> ! {
|
unsafe fn handle_trap(trap: Trap) -> ! {
|
||||||
unsafe { raise_user_trap(trap.into()) }
|
raise_user_trap(trap.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn store(abi: Self::Abi, ptr: *mut u128) {
|
unsafe fn from_abi<'a>(abi: Self::Abi, store: WeakStore<'a>) -> Self {
|
||||||
T::store(abi, ptr);
|
Ok(<T as WasmTy>::from_abi(abi, store))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(dst: &mut Vec<ValType>) {
|
||||||
|
<T as WasmTy>::push(dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
||||||
|
<T as WasmTy>::matches(tys)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn load_from_args(ptr: &mut *const u128) -> Self::Abi {
|
||||||
|
<T as WasmTy>::load_from_args(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128) {
|
||||||
|
<T as WasmTy>::store_to_args(abi, ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1141,40 +1334,53 @@ macro_rules! impl_into_func {
|
|||||||
R: WasmRet,
|
R: WasmRet,
|
||||||
{
|
{
|
||||||
fn into_func(self, store: &Store) -> Func {
|
fn into_func(self, store: &Store) -> Func {
|
||||||
// Note that this shim's ABI must match that expected by
|
/// This shim is called by Wasm code, constructs a `Caller`,
|
||||||
// cranelift, since cranelift is generating raw function calls
|
/// calls the wrapped host function, and returns the translated
|
||||||
// directly to this function.
|
/// result back to Wasm.
|
||||||
unsafe extern "C" fn shim<F, $($args,)* R>(
|
///
|
||||||
|
/// Note that this shim's ABI must *exactly* match that expected
|
||||||
|
/// by Cranelift, since Cranelift is generating raw function
|
||||||
|
/// calls directly to this function.
|
||||||
|
unsafe extern "C" fn wasm_to_host_shim<F, $($args,)* R>(
|
||||||
vmctx: *mut VMContext,
|
vmctx: *mut VMContext,
|
||||||
caller_vmctx: *mut VMContext,
|
caller_vmctx: *mut VMContext,
|
||||||
$($args: $args,)*
|
$( $args: $args::Abi, )*
|
||||||
) -> R::Abi
|
) -> R::Abi
|
||||||
where
|
where
|
||||||
F: Fn(Caller<'_>, $($args),*) -> R + 'static,
|
F: Fn(Caller<'_>, $( $args ),*) -> R + 'static,
|
||||||
$($args: WasmTy,)*
|
$( $args: WasmTy, )*
|
||||||
R: WasmRet,
|
R: WasmRet,
|
||||||
{
|
{
|
||||||
let ret = {
|
|
||||||
let state = (*vmctx).host_state();
|
let state = (*vmctx).host_state();
|
||||||
// Double-check ourselves in debug mode, but we control
|
// Double-check ourselves in debug mode, but we control
|
||||||
// the `Any` here so an unsafe downcast should also
|
// the `Any` here so an unsafe downcast should also
|
||||||
// work.
|
// work.
|
||||||
debug_assert!(state.is::<(F, Weak<StoreInner>)>());
|
debug_assert!(state.is::<(F, Weak<StoreInner>)>());
|
||||||
let (func, store) = &*(state as *const _ as *const (F, Weak<StoreInner>));
|
let (func, store) = &*(state as *const _ as *const (F, Weak<StoreInner>));
|
||||||
|
let weak_store = WeakStore(store);
|
||||||
|
|
||||||
|
let ret = {
|
||||||
panic::catch_unwind(AssertUnwindSafe(|| {
|
panic::catch_unwind(AssertUnwindSafe(|| {
|
||||||
func(
|
func(
|
||||||
Caller { store, caller_vmctx },
|
Caller { store, caller_vmctx },
|
||||||
$($args,)*
|
$( $args::from_abi($args, weak_store), )*
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
match ret {
|
match ret {
|
||||||
Ok(ret) => ret.into_abi(),
|
Ok(ret) => ret.into_abi_for_ret(weak_store),
|
||||||
Err(panic) => wasmtime_runtime::resume_panic(panic),
|
Err(panic) => wasmtime_runtime::resume_panic(panic),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn trampoline<$($args,)* R>(
|
/// This trampoline allows host code to indirectly call the
|
||||||
|
/// wrapped function (e.g. via `Func::call` on a `funcref` that
|
||||||
|
/// happens to reference our wrapped function).
|
||||||
|
///
|
||||||
|
/// It reads the arguments out of the incoming `args` array,
|
||||||
|
/// calls the given function pointer, and then stores the result
|
||||||
|
/// back into the `args` array.
|
||||||
|
unsafe extern "C" fn host_trampoline<$($args,)* R>(
|
||||||
callee_vmctx: *mut VMContext,
|
callee_vmctx: *mut VMContext,
|
||||||
caller_vmctx: *mut VMContext,
|
caller_vmctx: *mut VMContext,
|
||||||
ptr: *const VMFunctionBody,
|
ptr: *const VMFunctionBody,
|
||||||
@@ -1189,14 +1395,14 @@ macro_rules! impl_into_func {
|
|||||||
unsafe extern "C" fn(
|
unsafe extern "C" fn(
|
||||||
*mut VMContext,
|
*mut VMContext,
|
||||||
*mut VMContext,
|
*mut VMContext,
|
||||||
$($args,)*
|
$( $args::Abi, )*
|
||||||
) -> R::Abi,
|
) -> R::Abi,
|
||||||
>(ptr);
|
>(ptr);
|
||||||
|
|
||||||
let mut _next = args as *const u128;
|
let mut _next = args as *const u128;
|
||||||
$(let $args = $args::load(&mut _next);)*
|
$( let $args = $args::load_from_args(&mut _next); )*
|
||||||
let ret = ptr(callee_vmctx, caller_vmctx, $($args),*);
|
let ret = ptr(callee_vmctx, caller_vmctx, $( $args ),*);
|
||||||
R::store(ret, args);
|
R::store_to_args(ret, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut _args = Vec::new();
|
let mut _args = Vec::new();
|
||||||
@@ -1204,13 +1410,14 @@ macro_rules! impl_into_func {
|
|||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
R::push(&mut ret);
|
R::push(&mut ret);
|
||||||
let ty = FuncType::new(_args.into(), ret.into());
|
let ty = FuncType::new(_args.into(), ret.into());
|
||||||
|
|
||||||
let store_weak = store.weak();
|
let store_weak = store.weak();
|
||||||
let trampoline = trampoline::<$($args,)* R>;
|
let trampoline = host_trampoline::<$($args,)* R>;
|
||||||
let (instance, export) = unsafe {
|
let (instance, export) = unsafe {
|
||||||
crate::trampoline::generate_raw_func_export(
|
crate::trampoline::generate_raw_func_export(
|
||||||
&ty,
|
&ty,
|
||||||
std::slice::from_raw_parts_mut(
|
std::slice::from_raw_parts_mut(
|
||||||
shim::<F, $($args,)* R> as *mut _,
|
wasm_to_host_shim::<F, $($args,)* R> as *mut _,
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
trampoline,
|
trampoline,
|
||||||
@@ -1219,6 +1426,7 @@ macro_rules! impl_into_func {
|
|||||||
)
|
)
|
||||||
.expect("failed to generate export")
|
.expect("failed to generate export")
|
||||||
};
|
};
|
||||||
|
|
||||||
Func {
|
Func {
|
||||||
instance,
|
instance,
|
||||||
export,
|
export,
|
||||||
|
|||||||
Reference in New Issue
Block a user