xref: /wasmtime-44.0.1/tests/all/funcref.rs (revision 7fa89c4a)
1 use super::ref_types_module;
2 use std::sync::atomic::{AtomicBool, Ordering::SeqCst};
3 use std::sync::Arc;
4 use wasmtime::*;
5 
6 #[test]
7 fn pass_funcref_in_and_out_of_wasm() -> anyhow::Result<()> {
8     let (mut store, module) = ref_types_module(
9         false,
10         r#"
11             (module
12                 (func (export "func") (param funcref) (result funcref)
13                     local.get 0
14                 )
15             )
16         "#,
17     )?;
18 
19     let instance = Instance::new(&mut store, &module, &[])?;
20     let func = instance.get_func(&mut store, "func").unwrap();
21 
22     // Pass in a non-null funcref.
23     {
24         let mut results = [Val::I32(0)];
25         func.call(
26             &mut store,
27             &[Val::FuncRef(Some(func.clone()))],
28             &mut results,
29         )?;
30 
31         // Can't compare `Func` for equality, so this is the best we can do here.
32         let result_func = results[0].unwrap_funcref().unwrap();
33         assert_eq!(func.ty(&store), result_func.ty(&store));
34     }
35 
36     // Pass in a null funcref.
37     {
38         let mut results = [Val::I32(0)];
39         func.call(&mut store, &[Val::FuncRef(None)], &mut results)?;
40         let result_func = results[0].unwrap_funcref();
41         assert!(result_func.is_none());
42     }
43 
44     // Pass in a `funcref` from another instance.
45     {
46         let other_instance = Instance::new(&mut store, &module, &[])?;
47         let other_instance_func = other_instance.get_func(&mut store, "func").unwrap();
48 
49         let mut results = [Val::I32(0)];
50         func.call(
51             &mut store,
52             &[Val::FuncRef(Some(other_instance_func.clone()))],
53             &mut results,
54         )?;
55         assert_eq!(results.len(), 1);
56 
57         // Can't compare `Func` for equality, so this is the best we can do here.
58         let result_func = results[0].unwrap_funcref().unwrap();
59         assert_eq!(other_instance_func.ty(&store), result_func.ty(&store));
60     }
61 
62     // Passing in a `funcref` from another store fails.
63     {
64         let (mut other_store, other_module) =
65             ref_types_module(false, r#"(module (func (export "f")))"#)?;
66         let other_store_instance = Instance::new(&mut other_store, &other_module, &[])?;
67         let f = other_store_instance
68             .get_func(&mut other_store, "f")
69             .unwrap();
70 
71         assert!(func
72             .call(&mut store, &[Val::FuncRef(Some(f))], &mut [Val::I32(0)])
73             .is_err());
74     }
75 
76     Ok(())
77 }
78 
79 #[test]
80 fn receive_null_funcref_from_wasm() -> anyhow::Result<()> {
81     let (mut store, module) = ref_types_module(
82         false,
83         r#"
84             (module
85                 (func (export "get-null") (result funcref)
86                     ref.null func
87                 )
88             )
89         "#,
90     )?;
91 
92     let instance = Instance::new(&mut store, &module, &[])?;
93     let get_null = instance.get_func(&mut store, "get-null").unwrap();
94 
95     let mut results = [Val::I32(0)];
96     get_null.call(&mut store, &[], &mut results)?;
97     let result_func = results[0].unwrap_funcref();
98     assert!(result_func.is_none());
99 
100     Ok(())
101 }
102 
103 #[test]
104 fn wrong_store() -> anyhow::Result<()> {
105     let dropped = Arc::new(AtomicBool::new(false));
106     {
107         let mut store1 = Store::<()>::default();
108         let mut store2 = Store::<()>::default();
109 
110         let set = SetOnDrop(dropped.clone());
111         let f1 = Func::wrap(&mut store1, move || drop(&set));
112         let f2 = Func::wrap(&mut store2, move || Some(f1.clone()));
113         assert!(f2.call(&mut store2, &[], &mut []).is_err());
114     }
115     assert!(dropped.load(SeqCst));
116 
117     return Ok(());
118 
119     struct SetOnDrop(Arc<AtomicBool>);
120 
121     impl Drop for SetOnDrop {
122         fn drop(&mut self) {
123             self.0.store(true, SeqCst);
124         }
125     }
126 }
127 
128 #[test]
129 fn func_new_returns_wrong_store() -> anyhow::Result<()> {
130     let dropped = Arc::new(AtomicBool::new(false));
131     {
132         let mut store1 = Store::<()>::default();
133         let mut store2 = Store::<()>::default();
134 
135         let set = SetOnDrop(dropped.clone());
136         let f1 = Func::wrap(&mut store1, move || drop(&set));
137         let f2 = Func::new(
138             &mut store2,
139             FuncType::new(None, Some(ValType::FuncRef)),
140             move |_, _, results| {
141                 results[0] = f1.clone().into();
142                 Ok(())
143             },
144         );
145         assert!(f2.call(&mut store2, &[], &mut [Val::I32(0)]).is_err());
146     }
147     assert!(dropped.load(SeqCst));
148 
149     return Ok(());
150 
151     struct SetOnDrop(Arc<AtomicBool>);
152 
153     impl Drop for SetOnDrop {
154         fn drop(&mut self) {
155             self.0.store(true, SeqCst);
156         }
157     }
158 }
159