use super::ref_types_module;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering::SeqCst};
use wasmtime::*;
#[test]
#[cfg_attr(miri, ignore)]
fn pass_funcref_in_and_out_of_wasm() -> anyhow::Result<()> {
let (mut store, module) = ref_types_module(
false,
r#"
(module
(func (export "func") (param funcref) (result funcref)
local.get 0
)
)
"#,
)?;
let instance = Instance::new(&mut store, &module, &[])?;
let func = instance.get_func(&mut store, "func").unwrap();
{
let mut results = [Val::I32(0)];
func.call(&mut store, &[Val::FuncRef(Some(func))], &mut results)?;
let result_func = results[0].unwrap_funcref().unwrap();
assert!(FuncType::eq(&func.ty(&store), &result_func.ty(&store)));
}
{
let mut results = [Val::I32(0)];
func.call(&mut store, &[Val::FuncRef(None)], &mut results)?;
let result_func = results[0].unwrap_funcref();
assert!(result_func.is_none());
}
{
let other_instance = Instance::new(&mut store, &module, &[])?;
let other_instance_func = other_instance.get_func(&mut store, "func").unwrap();
let mut results = [Val::I32(0)];
func.call(
&mut store,
&[Val::FuncRef(Some(other_instance_func))],
&mut results,
)?;
assert_eq!(results.len(), 1);
let result_func = results[0].unwrap_funcref().unwrap();
assert!(FuncType::eq(
&other_instance_func.ty(&store),
&result_func.ty(&store),
));
}
{
let (mut other_store, other_module) =
ref_types_module(false, r#"(module (func (export "f")))"#)?;
let other_store_instance = Instance::new(&mut other_store, &other_module, &[])?;
let f = other_store_instance
.get_func(&mut other_store, "f")
.unwrap();
assert!(
func.call(&mut store, &[Val::FuncRef(Some(f))], &mut [Val::I32(0)])
.is_err()
);
}
Ok(())
}
#[test]
#[cfg_attr(miri, ignore)]
fn receive_null_funcref_from_wasm() -> anyhow::Result<()> {
let (mut store, module) = ref_types_module(
false,
r#"
(module
(func (export "get-null") (result funcref)
ref.null func
)
)
"#,
)?;
let instance = Instance::new(&mut store, &module, &[])?;
let get_null = instance.get_func(&mut store, "get-null").unwrap();
let mut results = [Val::I32(0)];
get_null.call(&mut store, &[], &mut results)?;
let result_func = results[0].unwrap_funcref();
assert!(result_func.is_none());
Ok(())
}
#[test]
fn wrong_store() -> anyhow::Result<()> {
let dropped = Arc::new(AtomicBool::new(false));
{
let mut store1 = Store::<()>::default();
let mut store2 = Store::<()>::default();
let set = SetOnDrop(dropped.clone());
let f1 = Func::wrap(&mut store1, move || {
let _ = &set;
});
let f2 = Func::wrap(&mut store2, move || Some(f1));
assert!(f2.call(&mut store2, &[], &mut []).is_err());
}
assert!(dropped.load(SeqCst));
return Ok(());
struct SetOnDrop(Arc<AtomicBool>);
impl Drop for SetOnDrop {
fn drop(&mut self) {
self.0.store(true, SeqCst);
}
}
}
#[test]
#[cfg_attr(miri, ignore)]
fn func_new_returns_wrong_store() -> anyhow::Result<()> {
let dropped = Arc::new(AtomicBool::new(false));
{
let mut store1 = Store::<()>::default();
let mut store2 = Store::<()>::default();
let set = SetOnDrop(dropped.clone());
let f1 = Func::wrap(&mut store1, move || {
let _ = &set;
});
let func_ty = FuncType::new(store2.engine(), None, Some(ValType::FUNCREF));
let f2 = Func::new(&mut store2, func_ty, move |_, _, results| {
results[0] = f1.into();
Ok(())
});
assert!(f2.call(&mut store2, &[], &mut [Val::I32(0)]).is_err());
}
assert!(dropped.load(SeqCst));
return Ok(());
struct SetOnDrop(Arc<AtomicBool>);
impl Drop for SetOnDrop {
fn drop(&mut self) {
self.0.store(true, SeqCst);
}
}
}