xref: /wasmtime-44.0.1/crates/c-api/src/ref.rs (revision 2fd0c7bf)
1 use crate::{WasmtimeStoreContextMut, abort};
2 use std::{mem::MaybeUninit, num::NonZeroU64, os::raw::c_void, ptr};
3 use wasmtime::{AnyRef, ExternRef, I31, OwnedRooted, Ref, RootScope, Val};
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 `OwnedRooted` 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             c: *const (),
200         }
201 
202         impl $c {
203             pub unsafe fn as_wasmtime(&self) -> Option<OwnedRooted<$wasmtime>> {
204                 let store_id = NonZeroU64::new(self.store_id)?;
205                 Some(OwnedRooted::from_borrowed_raw_parts_for_c_api(
206                     store_id, self.a, self.b, self.c,
207                 ))
208             }
209 
210             pub unsafe fn from_wasmtime(self) -> Option<OwnedRooted<$wasmtime>> {
211                 let store_id = NonZeroU64::new(self.store_id)?;
212                 Some(OwnedRooted::from_owned_raw_parts_for_c_api(
213                     store_id, self.a, self.b, self.c,
214                 ))
215             }
216         }
217 
218         impl From<Option<OwnedRooted<$wasmtime>>> for $c {
219             fn from(rooted: Option<OwnedRooted<$wasmtime>>) -> $c {
220                 let mut ret = $c {
221                     store_id: 0,
222                     a: 0,
223                     b: 0,
224                     c: core::ptr::null(),
225                 };
226                 if let Some(rooted) = rooted {
227                     let (store_id, a, b, c) = rooted.into_parts_for_c_api();
228                     ret.store_id = store_id.get();
229                     ret.a = a;
230                     ret.b = b;
231                     ret.c = c;
232                 }
233                 ret
234             }
235         }
236 
237         // SAFETY: The `*const ()` comes from (and is converted back
238         // into) an `Arc<()>`, and is only accessed as such, so this
239         // type is both Send and Sync. These constraints are necessary
240         // in the async machinery in this crate.
241         unsafe impl Send for $c {}
242         unsafe impl Sync for $c {}
243     };
244 }
245 
246 ref_wrapper!(AnyRef => wasmtime_anyref_t);
247 ref_wrapper!(ExternRef => wasmtime_externref_t);
248 
249 #[unsafe(no_mangle)]
250 pub unsafe extern "C" fn wasmtime_anyref_clone(
251     _cx: WasmtimeStoreContextMut<'_>,
252     anyref: Option<&wasmtime_anyref_t>,
253     out: &mut MaybeUninit<wasmtime_anyref_t>,
254 ) {
255     let anyref = anyref.and_then(|a| a.as_wasmtime());
256     crate::initialize(out, anyref.into());
257 }
258 
259 #[unsafe(no_mangle)]
260 pub unsafe extern "C" fn wasmtime_anyref_unroot(
261     _cx: WasmtimeStoreContextMut<'_>,
262     val: Option<&mut MaybeUninit<wasmtime_anyref_t>>,
263 ) {
264     if let Some(val) = val.and_then(|v| v.assume_init_read().from_wasmtime()) {
265         drop(val);
266     }
267 }
268 
269 #[unsafe(no_mangle)]
270 pub unsafe extern "C" fn wasmtime_anyref_to_raw(
271     cx: WasmtimeStoreContextMut<'_>,
272     val: Option<&wasmtime_anyref_t>,
273 ) -> u32 {
274     val.and_then(|v| v.as_wasmtime())
275         .and_then(|e| e.to_raw(cx).ok())
276         .unwrap_or_default()
277 }
278 
279 #[unsafe(no_mangle)]
280 pub unsafe extern "C" fn wasmtime_anyref_from_raw(
281     cx: WasmtimeStoreContextMut<'_>,
282     raw: u32,
283     val: &mut MaybeUninit<wasmtime_anyref_t>,
284 ) {
285     let mut scope = RootScope::new(cx);
286     let anyref =
287         AnyRef::from_raw(&mut scope, raw).map(|a| a.to_owned_rooted(&mut scope).expect("in scope"));
288     crate::initialize(val, anyref.into());
289 }
290 
291 #[unsafe(no_mangle)]
292 pub extern "C" fn wasmtime_anyref_from_i31(
293     cx: WasmtimeStoreContextMut<'_>,
294     val: u32,
295     out: &mut MaybeUninit<wasmtime_anyref_t>,
296 ) {
297     let mut scope = RootScope::new(cx);
298     let anyref = AnyRef::from_i31(&mut scope, I31::wrapping_u32(val));
299     let anyref = anyref.to_owned_rooted(&mut scope).expect("in scope");
300     crate::initialize(out, Some(anyref).into())
301 }
302 
303 #[unsafe(no_mangle)]
304 pub unsafe extern "C" fn wasmtime_anyref_i31_get_u(
305     cx: WasmtimeStoreContextMut<'_>,
306     anyref: Option<&wasmtime_anyref_t>,
307     dst: &mut MaybeUninit<u32>,
308 ) -> bool {
309     match anyref.and_then(|a| a.as_wasmtime()) {
310         Some(anyref) if anyref.is_i31(&cx).expect("OwnedRooted always in scope") => {
311             let val = anyref
312                 .unwrap_i31(&cx)
313                 .expect("OwnedRooted always in scope")
314                 .get_u32();
315             crate::initialize(dst, val);
316             true
317         }
318         _ => false,
319     }
320 }
321 
322 #[unsafe(no_mangle)]
323 pub unsafe extern "C" fn wasmtime_anyref_i31_get_s(
324     cx: WasmtimeStoreContextMut<'_>,
325     anyref: Option<&wasmtime_anyref_t>,
326     dst: &mut MaybeUninit<i32>,
327 ) -> bool {
328     match anyref.and_then(|a| a.as_wasmtime()) {
329         Some(anyref) if anyref.is_i31(&cx).expect("OwnedRooted always in scope") => {
330             let val = anyref
331                 .unwrap_i31(&cx)
332                 .expect("OwnedRooted always in scope")
333                 .get_i32();
334             crate::initialize(dst, val);
335             true
336         }
337         _ => false,
338     }
339 }
340 
341 #[unsafe(no_mangle)]
342 pub extern "C" fn wasmtime_externref_new(
343     cx: WasmtimeStoreContextMut<'_>,
344     data: *mut c_void,
345     finalizer: Option<extern "C" fn(*mut c_void)>,
346     out: &mut MaybeUninit<wasmtime_externref_t>,
347 ) -> bool {
348     let mut scope = RootScope::new(cx);
349     let e = match ExternRef::new(&mut scope, crate::ForeignData { data, finalizer }) {
350         Ok(e) => e,
351         Err(_) => return false,
352     };
353     let e = e.to_owned_rooted(&mut scope).expect("in scope");
354     crate::initialize(out, Some(e).into());
355     true
356 }
357 
358 #[unsafe(no_mangle)]
359 pub unsafe extern "C" fn wasmtime_externref_data(
360     cx: WasmtimeStoreContextMut<'_>,
361     externref: Option<&wasmtime_externref_t>,
362 ) -> *mut c_void {
363     externref
364         .and_then(|e| e.as_wasmtime())
365         .and_then(|e| {
366             let data = e.data(cx).ok()??;
367             Some(data.downcast_ref::<crate::ForeignData>().unwrap().data)
368         })
369         .unwrap_or(ptr::null_mut())
370 }
371 
372 #[unsafe(no_mangle)]
373 pub unsafe extern "C" fn wasmtime_externref_clone(
374     _cx: WasmtimeStoreContextMut<'_>,
375     externref: Option<&wasmtime_externref_t>,
376     out: &mut MaybeUninit<wasmtime_externref_t>,
377 ) {
378     let externref = externref.and_then(|e| e.as_wasmtime());
379     crate::initialize(out, externref.into());
380 }
381 
382 #[unsafe(no_mangle)]
383 pub unsafe extern "C" fn wasmtime_externref_unroot(
384     _cx: WasmtimeStoreContextMut<'_>,
385     val: Option<&mut MaybeUninit<wasmtime_externref_t>>,
386 ) {
387     if let Some(val) = val.and_then(|v| v.assume_init_read().from_wasmtime()) {
388         drop(val);
389     }
390 }
391 
392 #[unsafe(no_mangle)]
393 pub unsafe extern "C" fn wasmtime_externref_to_raw(
394     cx: WasmtimeStoreContextMut<'_>,
395     val: Option<&wasmtime_externref_t>,
396 ) -> u32 {
397     val.and_then(|e| e.as_wasmtime())
398         .and_then(|e| e.to_raw(cx).ok())
399         .unwrap_or_default()
400 }
401 
402 #[unsafe(no_mangle)]
403 pub unsafe extern "C" fn wasmtime_externref_from_raw(
404     cx: WasmtimeStoreContextMut<'_>,
405     raw: u32,
406     val: &mut MaybeUninit<wasmtime_externref_t>,
407 ) {
408     let mut scope = RootScope::new(cx);
409     let rooted = ExternRef::from_raw(&mut scope, raw)
410         .map(|e| e.to_owned_rooted(&mut scope).expect("in scope"));
411     crate::initialize(val, rooted.into());
412 }
413