mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-12 13:28:49 +00:00
Add basic API tests with reference types with dynamic functions
This commit is contained in:
66
lib/api/src/extern_ref.rs
Normal file
66
lib/api/src/extern_ref.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
use crate::FromToNativeWasmType;
|
||||
use std::any::Any;
|
||||
use std::marker::PhantomData;
|
||||
use wasmer_vm::VMExternRef;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
/// An opaque reference to some data. This reference can be passed through Wasm.
|
||||
pub struct ExternRef<T: Any + Send + Sync + 'static + Sized> {
|
||||
inner: VMExternRef,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> ExternRef<T>
|
||||
where
|
||||
T: Any + Send + Sync + 'static + Sized,
|
||||
{
|
||||
/// Checks if the given ExternRef is null.
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.inner.is_null()
|
||||
}
|
||||
|
||||
/// New null extern ref
|
||||
pub fn null() -> Self {
|
||||
Self {
|
||||
inner: VMExternRef::null(),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Make a new extern reference
|
||||
pub fn new(value: T) -> Self {
|
||||
Self {
|
||||
inner: VMExternRef::new(value),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to downcast to the given value
|
||||
pub fn downcast(&self) -> Option<&T> {
|
||||
self.inner.downcast::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
unsafe impl<T> FromToNativeWasmType for ExternRef<T>
|
||||
where
|
||||
T: Any + Send + Sync + 'static + Sized,
|
||||
{
|
||||
type Native = usize;
|
||||
|
||||
#[inline]
|
||||
fn from_native(native: Self::Native) -> Self {
|
||||
let inner = VMExternRef::from_ne_bytes(Self::Native::to_ne_bytes(native));
|
||||
Self {
|
||||
inner,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_native(self) -> Self::Native {
|
||||
Self::Native::from_ne_bytes(VMExternRef::to_ne_bytes(self.inner))
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -255,6 +255,7 @@
|
||||
|
||||
mod env;
|
||||
mod exports;
|
||||
mod extern_ref;
|
||||
mod externals;
|
||||
mod import_object;
|
||||
mod instance;
|
||||
@@ -285,6 +286,7 @@ pub mod internals {
|
||||
|
||||
pub use crate::env::{HostEnvInitError, LazyInit, WasmerEnv};
|
||||
pub use crate::exports::{ExportError, Exportable, Exports, ExportsIterator};
|
||||
pub use crate::extern_ref::ExternRef;
|
||||
pub use crate::externals::{
|
||||
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, Table, WasmTypeList,
|
||||
};
|
||||
|
||||
83
lib/api/tests/reference_types.rs
Normal file
83
lib/api/tests/reference_types.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
use anyhow::Result;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use wasmer::*;
|
||||
|
||||
#[test]
|
||||
fn func_ref_passed_and_returned() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let wat = r#"(module
|
||||
(import "env" "func_ref_identity" (func (param funcref) (result funcref)))
|
||||
(type $ret_i32_ty (func (result i32)))
|
||||
(table $table (export "table") 2 2 funcref)
|
||||
|
||||
(func (export "run") (param) (result funcref)
|
||||
(call 0 (ref.null func)))
|
||||
(func (export "call_set_value") (param $fr funcref) (result i32)
|
||||
(table.set $table (i32.const 0) (local.get $fr))
|
||||
(call_indirect $table (type $ret_i32_ty) (i32.const 0)))
|
||||
)"#;
|
||||
let module = Module::new(&store, wat)?;
|
||||
let imports = imports! {
|
||||
"env" => {
|
||||
"func_ref_identity" => Function::new(&store, FunctionType::new([Type::FuncRef], [Type::FuncRef]), |values| -> Result<Vec<_>, _> {
|
||||
Ok(vec![values[0].clone()])
|
||||
})
|
||||
},
|
||||
};
|
||||
|
||||
let instance = Instance::new(&module, &imports)?;
|
||||
|
||||
let f: &Function = instance.exports.get_function("run")?;
|
||||
let results = f.call(&[]).unwrap();
|
||||
if let Value::FuncRef(fr) = &results[0] {
|
||||
assert!(fr.is_none());
|
||||
} else {
|
||||
panic!("funcref not found!");
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, WasmerEnv)]
|
||||
pub struct Env(Arc<AtomicBool>);
|
||||
let env = Env(Arc::new(AtomicBool::new(false)));
|
||||
|
||||
let func_to_call = Function::new_native_with_env(&store, env.clone(), |env: &Env| -> i32 {
|
||||
env.0.store(true, Ordering::SeqCst);
|
||||
343
|
||||
});
|
||||
let call_set_value: &Function = instance.exports.get_function("call_set_value")?;
|
||||
let results: Box<[Value]> = call_set_value.call(&[Value::FuncRef(Some(func_to_call))])?;
|
||||
assert!(env.0.load(Ordering::SeqCst));
|
||||
assert_eq!(&*results, &[Value::I32(343)]);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extern_ref_passed_and_returned() -> Result<()> {
|
||||
let store = Store::default();
|
||||
let wat = r#"(module
|
||||
(import "env" "extern_ref_identity" (func (param externref) (result externref)))
|
||||
|
||||
(func (export "run") (param) (result externref)
|
||||
(call 0 (ref.null extern)))
|
||||
)"#;
|
||||
let module = Module::new(&store, wat)?;
|
||||
let imports = imports! {
|
||||
"env" => {
|
||||
"extern_ref_identity" => Function::new(&store, FunctionType::new([Type::ExternRef], [Type::ExternRef]), |values| -> Result<Vec<_>, _> {
|
||||
Ok(vec![values[0].clone()])
|
||||
})
|
||||
},
|
||||
};
|
||||
|
||||
let instance = Instance::new(&module, &imports)?;
|
||||
let f: &Function = instance.exports.get_function("run")?;
|
||||
let results = f.call(&[]).unwrap();
|
||||
if let Value::ExternRef(er) = results[0] {
|
||||
assert!(er.is_null());
|
||||
} else {
|
||||
panic!("result is not an extern ref!");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -30,6 +30,32 @@ impl VMExternRef {
|
||||
Self(Box::into_raw(Box::new(VMExternRefInner::new::<T>(value))))
|
||||
}
|
||||
|
||||
/// Try to downcast to the given value
|
||||
pub fn downcast<T>(&self) -> Option<&T>
|
||||
where
|
||||
T: Any + Send + Sync + 'static + Sized,
|
||||
{
|
||||
if self.is_null() {
|
||||
return None;
|
||||
}
|
||||
unsafe {
|
||||
let inner = &*self.0;
|
||||
|
||||
inner.data.downcast_ref::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the memory representation of this extern ref as a byte array in
|
||||
/// native byte order.
|
||||
pub fn to_ne_bytes(&self) -> [u8; 8] {
|
||||
usize::to_ne_bytes(self.0 as usize)
|
||||
}
|
||||
/// Convert native endian bytes to an extern ref.
|
||||
// TODO: this should be unsafe!!
|
||||
pub fn from_ne_bytes(bytes: [u8; 8]) -> Self {
|
||||
Self(usize::from_ne_bytes(bytes) as *const _)
|
||||
}
|
||||
|
||||
/// A deep copy of the reference, increments the strong count.
|
||||
pub fn ref_clone(&self) -> Self {
|
||||
if self.0.is_null() {
|
||||
|
||||
Reference in New Issue
Block a user