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