xref: /wasmtime-44.0.1/crates/c-api/src/ref.rs (revision cccc4e64)
1 use crate::{abort, WasmtimeStoreContextMut};
2 use std::{mem::MaybeUninit, num::NonZeroU64, os::raw::c_void, ptr};
3 use wasmtime::{AnyRef, ExternRef, ManuallyRooted, Ref, RootScope, Val, I31};
4 
5 /// `*mut wasm_ref_t` is a reference type (`externref` or `funcref`), as seen by
6 /// the C API. Because we do not have a uniform representation for `funcref`s
7 /// and `externref`s, a `*mut wasm_ref_t` is morally a
8 /// `Option<Box<Either<ExternRef, Func>>>`.
9 ///
10 /// A null `*mut wasm_ref_t` is either a null `funcref` or a null `externref`
11 /// depending on context (e.g. the table's element type that it is going into or
12 /// coming out of).
13 ///
14 /// Note: this is not `#[repr(C)]` because it is an opaque type in the header,
15 /// and only ever referenced as `*mut wasm_ref_t`. This also lets us use a
16 /// regular, non-`repr(C)` `enum` to define `WasmRefInner`.
17 #[derive(Clone)]
18 pub struct wasm_ref_t {
19     pub(crate) r: Ref,
20 }
21 
22 wasmtime_c_api_macros::declare_own!(wasm_ref_t);
23 
24 impl wasm_ref_t {
25     pub(crate) fn new(r: Ref) -> Option<Box<wasm_ref_t>> {
26         if r.is_null() || !r.is_func() {
27             None
28         } else {
29             Some(Box::new(wasm_ref_t { r }))
30         }
31     }
32 }
33 
34 pub(crate) fn ref_to_val(r: &wasm_ref_t) -> Val {
35     Val::from(r.r.clone())
36 }
37 
38 #[unsafe(no_mangle)]
39 pub extern "C" fn wasm_ref_copy(r: Option<&wasm_ref_t>) -> Option<Box<wasm_ref_t>> {
40     r.map(|r| Box::new(r.clone()))
41 }
42 
43 #[unsafe(no_mangle)]
44 pub extern "C" fn wasm_ref_same(_a: Option<&wasm_ref_t>, _b: Option<&wasm_ref_t>) -> bool {
45     // We need a store to determine whether these are the same reference or not.
46     abort("wasm_ref_same")
47 }
48 
49 #[unsafe(no_mangle)]
50 pub extern "C" fn wasm_ref_get_host_info(_ref: Option<&wasm_ref_t>) -> *mut c_void {
51     std::ptr::null_mut()
52 }
53 
54 #[unsafe(no_mangle)]
55 pub extern "C" fn wasm_ref_set_host_info(_ref: Option<&wasm_ref_t>, _info: *mut c_void) {
56     abort("wasm_ref_set_host_info")
57 }
58 
59 #[unsafe(no_mangle)]
60 pub extern "C" fn wasm_ref_set_host_info_with_finalizer(
61     _ref: Option<&wasm_ref_t>,
62     _info: *mut c_void,
63     _finalizer: Option<extern "C" fn(*mut c_void)>,
64 ) {
65     abort("wasm_ref_set_host_info_with_finalizer")
66 }
67 
68 #[unsafe(no_mangle)]
69 pub extern "C" fn wasm_ref_as_extern(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_extern_t> {
70     abort("wasm_ref_as_extern")
71 }
72 
73 #[unsafe(no_mangle)]
74 pub extern "C" fn wasm_ref_as_extern_const(
75     _ref: Option<&wasm_ref_t>,
76 ) -> Option<&crate::wasm_extern_t> {
77     abort("wasm_ref_as_extern_const")
78 }
79 
80 #[unsafe(no_mangle)]
81 pub extern "C" fn wasm_ref_as_foreign(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_foreign_t> {
82     abort("wasm_ref_as_foreign")
83 }
84 
85 #[unsafe(no_mangle)]
86 pub extern "C" fn wasm_ref_as_foreign_const(
87     _ref: Option<&wasm_ref_t>,
88 ) -> Option<&crate::wasm_foreign_t> {
89     abort("wasm_ref_as_foreign_const")
90 }
91 
92 #[unsafe(no_mangle)]
93 pub extern "C" fn wasm_ref_as_func(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_func_t> {
94     abort("wasm_ref_as_func")
95 }
96 
97 #[unsafe(no_mangle)]
98 pub extern "C" fn wasm_ref_as_func_const(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_func_t> {
99     abort("wasm_ref_as_func_const")
100 }
101 
102 #[unsafe(no_mangle)]
103 pub extern "C" fn wasm_ref_as_global(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_global_t> {
104     abort("wasm_ref_as_global")
105 }
106 
107 #[unsafe(no_mangle)]
108 pub extern "C" fn wasm_ref_as_global_const(
109     _ref: Option<&wasm_ref_t>,
110 ) -> Option<&crate::wasm_global_t> {
111     abort("wasm_ref_as_global_const")
112 }
113 
114 #[unsafe(no_mangle)]
115 pub extern "C" fn wasm_ref_as_instance(
116     _ref: Option<&wasm_ref_t>,
117 ) -> Option<&crate::wasm_instance_t> {
118     abort("wasm_ref_as_instance")
119 }
120 
121 #[unsafe(no_mangle)]
122 pub extern "C" fn wasm_ref_as_instance_const(
123     _ref: Option<&wasm_ref_t>,
124 ) -> Option<&crate::wasm_instance_t> {
125     abort("wasm_ref_as_instance_const")
126 }
127 
128 #[unsafe(no_mangle)]
129 pub extern "C" fn wasm_ref_as_memory(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_memory_t> {
130     abort("wasm_ref_as_memory")
131 }
132 
133 #[unsafe(no_mangle)]
134 pub extern "C" fn wasm_ref_as_memory_const(
135     _ref: Option<&wasm_ref_t>,
136 ) -> Option<&crate::wasm_memory_t> {
137     abort("wasm_ref_as_memory_const")
138 }
139 
140 #[unsafe(no_mangle)]
141 pub extern "C" fn wasm_ref_as_module(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_module_t> {
142     abort("wasm_ref_as_module")
143 }
144 
145 #[unsafe(no_mangle)]
146 pub extern "C" fn wasm_ref_as_module_const(
147     _ref: Option<&wasm_ref_t>,
148 ) -> Option<&crate::wasm_module_t> {
149     abort("wasm_ref_as_module_const")
150 }
151 
152 #[unsafe(no_mangle)]
153 pub extern "C" fn wasm_ref_as_table(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_table_t> {
154     abort("wasm_ref_as_table")
155 }
156 
157 #[unsafe(no_mangle)]
158 pub extern "C" fn wasm_ref_as_table_const(
159     _ref: Option<&wasm_ref_t>,
160 ) -> Option<&crate::wasm_table_t> {
161     abort("wasm_ref_as_table_const")
162 }
163 
164 #[unsafe(no_mangle)]
165 pub extern "C" fn wasm_ref_as_trap(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_trap_t> {
166     abort("wasm_ref_as_trap")
167 }
168 
169 #[unsafe(no_mangle)]
170 pub extern "C" fn wasm_ref_as_trap_const(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_trap_t> {
171     abort("wasm_ref_as_trap_const")
172 }
173 
174 #[derive(Clone)]
175 #[repr(C)]
176 pub struct wasm_foreign_t {}
177 
178 wasmtime_c_api_macros::declare_ref!(wasm_foreign_t);
179 
180 #[unsafe(no_mangle)]
181 pub extern "C" fn wasm_foreign_new(_store: &crate::wasm_store_t) -> Box<wasm_foreign_t> {
182     abort("wasm_foreign_new")
183 }
184 
185 /// C-API representation of `anyref`.
186 ///
187 /// This represented differently in the C API from the header to handle how
188 /// this is dispatched internally. Null anyref values are represented with a
189 /// `store_id` of zero, and otherwise the `rooted` field is valid.
190 ///
191 /// Note that this relies on the Wasmtime definition of `ManuallyRooted` to have
192 /// a 64-bit store_id first.
193 macro_rules! ref_wrapper {
194     ($wasmtime:ident => $c:ident) => {
195         pub struct $c {
196             store_id: u64,
197             a: u32,
198             b: u32,
199         }
200 
201         impl $c {
202             pub unsafe fn as_wasmtime(&self) -> Option<ManuallyRooted<$wasmtime>> {
203                 let store_id = NonZeroU64::new(self.store_id)?;
204                 Some(ManuallyRooted::from_raw_parts_for_c_api(
205                     store_id, self.a, self.b,
206                 ))
207             }
208         }
209 
210         impl From<Option<ManuallyRooted<$wasmtime>>> for $c {
211             fn from(rooted: Option<ManuallyRooted<$wasmtime>>) -> $c {
212                 let mut ret = $c {
213                     store_id: 0,
214                     a: 0,
215                     b: 0,
216                 };
217                 if let Some(rooted) = rooted {
218                     let (store_id, a, b) = rooted.into_parts_for_c_api();
219                     ret.store_id = store_id.get();
220                     ret.a = a;
221                     ret.b = b;
222                 }
223                 ret
224             }
225         }
226     };
227 }
228 
229 ref_wrapper!(AnyRef => wasmtime_anyref_t);
230 ref_wrapper!(ExternRef => wasmtime_externref_t);
231 
232 #[unsafe(no_mangle)]
233 pub unsafe extern "C" fn wasmtime_anyref_clone(
234     cx: WasmtimeStoreContextMut<'_>,
235     anyref: Option<&wasmtime_anyref_t>,
236     out: &mut MaybeUninit<wasmtime_anyref_t>,
237 ) {
238     let anyref = anyref.and_then(|a| a.as_wasmtime()).map(|a| a.clone(cx));
239     crate::initialize(out, anyref.into());
240 }
241 
242 #[unsafe(no_mangle)]
243 pub unsafe extern "C" fn wasmtime_anyref_unroot(
244     cx: WasmtimeStoreContextMut<'_>,
245     val: Option<&mut MaybeUninit<wasmtime_anyref_t>>,
246 ) {
247     if let Some(val) = val.and_then(|v| v.assume_init_read().as_wasmtime()) {
248         val.unroot(cx);
249     }
250 }
251 
252 #[unsafe(no_mangle)]
253 pub unsafe extern "C" fn wasmtime_anyref_to_raw(
254     cx: WasmtimeStoreContextMut<'_>,
255     val: Option<&wasmtime_anyref_t>,
256 ) -> u32 {
257     val.and_then(|v| v.as_wasmtime())
258         .and_then(|e| e.to_raw(cx).ok())
259         .unwrap_or_default()
260 }
261 
262 #[unsafe(no_mangle)]
263 pub unsafe extern "C" fn wasmtime_anyref_from_raw(
264     cx: WasmtimeStoreContextMut<'_>,
265     raw: u32,
266     val: &mut MaybeUninit<wasmtime_anyref_t>,
267 ) {
268     let mut scope = RootScope::new(cx);
269     let anyref = AnyRef::from_raw(&mut scope, raw)
270         .map(|a| a.to_manually_rooted(&mut scope).expect("in scope"));
271     crate::initialize(val, anyref.into());
272 }
273 
274 #[unsafe(no_mangle)]
275 pub extern "C" fn wasmtime_anyref_from_i31(
276     cx: WasmtimeStoreContextMut<'_>,
277     val: u32,
278     out: &mut MaybeUninit<wasmtime_anyref_t>,
279 ) {
280     let mut scope = RootScope::new(cx);
281     let anyref = AnyRef::from_i31(&mut scope, I31::wrapping_u32(val));
282     let anyref = anyref.to_manually_rooted(&mut scope).expect("in scope");
283     crate::initialize(out, Some(anyref).into())
284 }
285 
286 #[unsafe(no_mangle)]
287 pub unsafe extern "C" fn wasmtime_anyref_i31_get_u(
288     cx: WasmtimeStoreContextMut<'_>,
289     anyref: Option<&wasmtime_anyref_t>,
290     dst: &mut MaybeUninit<u32>,
291 ) -> bool {
292     match anyref.and_then(|a| a.as_wasmtime()) {
293         Some(anyref) if anyref.is_i31(&cx).expect("ManuallyRooted always in scope") => {
294             let val = anyref
295                 .unwrap_i31(&cx)
296                 .expect("ManuallyRooted always in scope")
297                 .get_u32();
298             crate::initialize(dst, val);
299             true
300         }
301         _ => false,
302     }
303 }
304 
305 #[unsafe(no_mangle)]
306 pub unsafe extern "C" fn wasmtime_anyref_i31_get_s(
307     cx: WasmtimeStoreContextMut<'_>,
308     anyref: Option<&wasmtime_anyref_t>,
309     dst: &mut MaybeUninit<i32>,
310 ) -> bool {
311     match anyref.and_then(|a| a.as_wasmtime()) {
312         Some(anyref) if anyref.is_i31(&cx).expect("ManuallyRooted always in scope") => {
313             let val = anyref
314                 .unwrap_i31(&cx)
315                 .expect("ManuallyRooted always in scope")
316                 .get_i32();
317             crate::initialize(dst, val);
318             true
319         }
320         _ => false,
321     }
322 }
323 
324 #[unsafe(no_mangle)]
325 pub extern "C" fn wasmtime_externref_new(
326     cx: WasmtimeStoreContextMut<'_>,
327     data: *mut c_void,
328     finalizer: Option<extern "C" fn(*mut c_void)>,
329     out: &mut MaybeUninit<wasmtime_externref_t>,
330 ) -> bool {
331     let mut scope = RootScope::new(cx);
332     let e = match ExternRef::new(&mut scope, crate::ForeignData { data, finalizer }) {
333         Ok(e) => e,
334         Err(_) => return false,
335     };
336     let e = e.to_manually_rooted(&mut scope).expect("in scope");
337     crate::initialize(out, Some(e).into());
338     true
339 }
340 
341 #[unsafe(no_mangle)]
342 pub unsafe extern "C" fn wasmtime_externref_data(
343     cx: WasmtimeStoreContextMut<'_>,
344     externref: Option<&wasmtime_externref_t>,
345 ) -> *mut c_void {
346     externref
347         .and_then(|e| e.as_wasmtime())
348         .and_then(|e| {
349             let data = e.data(cx).ok()??;
350             Some(data.downcast_ref::<crate::ForeignData>().unwrap().data)
351         })
352         .unwrap_or(ptr::null_mut())
353 }
354 
355 #[unsafe(no_mangle)]
356 pub unsafe extern "C" fn wasmtime_externref_clone(
357     cx: WasmtimeStoreContextMut<'_>,
358     externref: Option<&wasmtime_externref_t>,
359     out: &mut MaybeUninit<wasmtime_externref_t>,
360 ) {
361     let externref = externref.and_then(|e| e.as_wasmtime()).map(|e| e.clone(cx));
362     crate::initialize(out, externref.into());
363 }
364 
365 #[unsafe(no_mangle)]
366 pub unsafe extern "C" fn wasmtime_externref_unroot(
367     cx: WasmtimeStoreContextMut<'_>,
368     val: Option<&mut MaybeUninit<wasmtime_externref_t>>,
369 ) {
370     if let Some(val) = val.and_then(|v| v.assume_init_read().as_wasmtime()) {
371         val.unroot(cx);
372     }
373 }
374 
375 #[unsafe(no_mangle)]
376 pub unsafe extern "C" fn wasmtime_externref_to_raw(
377     cx: WasmtimeStoreContextMut<'_>,
378     val: Option<&wasmtime_externref_t>,
379 ) -> u32 {
380     val.and_then(|e| e.as_wasmtime())
381         .and_then(|e| e.to_raw(cx).ok())
382         .unwrap_or_default()
383 }
384 
385 #[unsafe(no_mangle)]
386 pub unsafe extern "C" fn wasmtime_externref_from_raw(
387     cx: WasmtimeStoreContextMut<'_>,
388     raw: u32,
389     val: &mut MaybeUninit<wasmtime_externref_t>,
390 ) {
391     let mut scope = RootScope::new(cx);
392     let rooted = ExternRef::from_raw(&mut scope, raw)
393         .map(|e| e.to_manually_rooted(&mut scope).expect("in scope"));
394     crate::initialize(val, rooted.into());
395 }
396