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(
|
||||
*mut VMContext,
|
||||
*mut VMContext,
|
||||
$($args,)*
|
||||
) -> R,
|
||||
$( $args::Abi, )*
|
||||
) -> R::Abi,
|
||||
>(anyfunc.as_ref().func_ptr.as_ptr());
|
||||
|
||||
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, || {
|
||||
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
|
||||
/// [`Func::wrap`] and friends.
|
||||
///
|
||||
@@ -791,160 +806,40 @@ pub(crate) fn invoke_wasm_and_catch_traps(
|
||||
/// stable over time.
|
||||
///
|
||||
/// 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)]
|
||||
fn push(dst: &mut Vec<ValType>);
|
||||
|
||||
// Does the next valtype(s) match this type?
|
||||
#[doc(hidden)]
|
||||
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()>;
|
||||
|
||||
// Load this type's raw ABI representation from an args array.
|
||||
#[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)]
|
||||
unsafe fn store(abi: Self, 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;
|
||||
}
|
||||
unsafe fn store_to_args(abi: Self::Abi, ptr: *mut u128);
|
||||
}
|
||||
|
||||
/// 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`]
|
||||
pub unsafe trait WasmRet {
|
||||
// Same as `WasmTy::Abi`.
|
||||
#[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)]
|
||||
fn push(dst: &mut Vec<ValType>);
|
||||
|
||||
// Same as `WasmTy::matches`.
|
||||
#[doc(hidden)]
|
||||
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()>;
|
||||
|
||||
// Same as `WasmTy::load_from_args`.
|
||||
#[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)]
|
||||
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 {
|
||||
type Abi = T;
|
||||
fn push(dst: &mut Vec<ValType>) {
|
||||
T::push(dst)
|
||||
}
|
||||
unsafe impl WasmTy for () {
|
||||
type Abi = Self;
|
||||
|
||||
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
||||
T::matches(tys)
|
||||
#[inline]
|
||||
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]
|
||||
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
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn store(abi: Self::Abi, ptr: *mut u128) {
|
||||
T::store(abi, ptr);
|
||||
unsafe fn from_abi<'a>(abi: Self::Abi, _store: WeakStore<'a>) -> Self {
|
||||
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> {
|
||||
type Abi = T;
|
||||
unsafe impl WasmTy for u32 {
|
||||
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>) {
|
||||
T::push(dst)
|
||||
<i32 as WasmTy>::push(dst)
|
||||
}
|
||||
|
||||
fn matches(tys: impl Iterator<Item = ValType>) -> anyhow::Result<()> {
|
||||
T::matches(tys)
|
||||
<i32 as WasmTy>::matches(tys)
|
||||
}
|
||||
|
||||
#[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 {
|
||||
Ok(val) => return T::into_abi(val),
|
||||
Ok(val) => return <T as WasmTy>::into_abi_for_arg(val, store),
|
||||
Err(trap) => handle_trap(trap),
|
||||
}
|
||||
|
||||
fn handle_trap(trap: Trap) -> ! {
|
||||
unsafe { raise_user_trap(trap.into()) }
|
||||
unsafe fn handle_trap(trap: Trap) -> ! {
|
||||
raise_user_trap(trap.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn store(abi: Self::Abi, ptr: *mut u128) {
|
||||
T::store(abi, ptr);
|
||||
unsafe fn from_abi<'a>(abi: Self::Abi, store: WeakStore<'a>) -> Self {
|
||||
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,
|
||||
{
|
||||
fn into_func(self, store: &Store) -> Func {
|
||||
// Note that this shim's ABI must match that expected by
|
||||
// cranelift, since cranelift is generating raw function calls
|
||||
// directly to this function.
|
||||
unsafe extern "C" fn shim<F, $($args,)* R>(
|
||||
/// This shim is called by Wasm code, constructs a `Caller`,
|
||||
/// calls the wrapped host function, and returns the translated
|
||||
/// result back to Wasm.
|
||||
///
|
||||
/// 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,
|
||||
caller_vmctx: *mut VMContext,
|
||||
$($args: $args,)*
|
||||
$( $args: $args::Abi, )*
|
||||
) -> R::Abi
|
||||
where
|
||||
F: Fn(Caller<'_>, $($args),*) -> R + 'static,
|
||||
$($args: WasmTy,)*
|
||||
F: Fn(Caller<'_>, $( $args ),*) -> R + 'static,
|
||||
$( $args: WasmTy, )*
|
||||
R: WasmRet,
|
||||
{
|
||||
let ret = {
|
||||
let state = (*vmctx).host_state();
|
||||
// Double-check ourselves in debug mode, but we control
|
||||
// the `Any` here so an unsafe downcast should also
|
||||
// work.
|
||||
debug_assert!(state.is::<(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(|| {
|
||||
func(
|
||||
Caller { store, caller_vmctx },
|
||||
$($args,)*
|
||||
$( $args::from_abi($args, weak_store), )*
|
||||
)
|
||||
}))
|
||||
};
|
||||
match ret {
|
||||
Ok(ret) => ret.into_abi(),
|
||||
Ok(ret) => ret.into_abi_for_ret(weak_store),
|
||||
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,
|
||||
caller_vmctx: *mut VMContext,
|
||||
ptr: *const VMFunctionBody,
|
||||
@@ -1189,14 +1395,14 @@ macro_rules! impl_into_func {
|
||||
unsafe extern "C" fn(
|
||||
*mut VMContext,
|
||||
*mut VMContext,
|
||||
$($args,)*
|
||||
$( $args::Abi, )*
|
||||
) -> R::Abi,
|
||||
>(ptr);
|
||||
|
||||
let mut _next = args as *const u128;
|
||||
$(let $args = $args::load(&mut _next);)*
|
||||
let ret = ptr(callee_vmctx, caller_vmctx, $($args),*);
|
||||
R::store(ret, args);
|
||||
$( let $args = $args::load_from_args(&mut _next); )*
|
||||
let ret = ptr(callee_vmctx, caller_vmctx, $( $args ),*);
|
||||
R::store_to_args(ret, args);
|
||||
}
|
||||
|
||||
let mut _args = Vec::new();
|
||||
@@ -1204,13 +1410,14 @@ macro_rules! impl_into_func {
|
||||
let mut ret = Vec::new();
|
||||
R::push(&mut ret);
|
||||
let ty = FuncType::new(_args.into(), ret.into());
|
||||
|
||||
let store_weak = store.weak();
|
||||
let trampoline = trampoline::<$($args,)* R>;
|
||||
let trampoline = host_trampoline::<$($args,)* R>;
|
||||
let (instance, export) = unsafe {
|
||||
crate::trampoline::generate_raw_func_export(
|
||||
&ty,
|
||||
std::slice::from_raw_parts_mut(
|
||||
shim::<F, $($args,)* R> as *mut _,
|
||||
wasm_to_host_shim::<F, $($args,)* R> as *mut _,
|
||||
0,
|
||||
),
|
||||
trampoline,
|
||||
@@ -1219,6 +1426,7 @@ macro_rules! impl_into_func {
|
||||
)
|
||||
.expect("failed to generate export")
|
||||
};
|
||||
|
||||
Func {
|
||||
instance,
|
||||
export,
|
||||
|
||||
Reference in New Issue
Block a user