wasmtime_c_api/
ref.rs

1use crate::{WasmtimeStoreContextMut, abort};
2use std::mem::{ManuallyDrop, MaybeUninit};
3use std::{num::NonZeroU64, os::raw::c_void, ptr};
4use 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)]
19pub struct wasm_ref_t {
20    pub(crate) r: Ref,
21}
22
23wasmtime_c_api_macros::declare_own!(wasm_ref_t);
24
25impl 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
35pub(crate) fn ref_to_val(r: &wasm_ref_t) -> Val {
36    Val::from(r.r.clone())
37}
38
39#[unsafe(no_mangle)]
40pub 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)]
45pub 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)]
51pub 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)]
56pub 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)]
61pub 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)]
70pub 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)]
75pub 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)]
82pub 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)]
87pub 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)]
94pub 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)]
99pub 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)]
104pub 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)]
109pub 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)]
116pub 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)]
123pub 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)]
130pub 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)]
135pub 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)]
142pub 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)]
147pub 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)]
154pub 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)]
159pub 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)]
166pub 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)]
171pub 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)]
177pub struct wasm_foreign_t {}
178
179wasmtime_c_api_macros::declare_ref!(wasm_foreign_t);
180
181#[unsafe(no_mangle)]
182pub 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.
194macro_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
259ref_wrapper!(AnyRef => wasmtime_anyref_t);
260ref_wrapper!(ExternRef => wasmtime_externref_t);
261
262#[unsafe(no_mangle)]
263pub 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)]
272pub 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)]
281pub 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)]
291pub 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)]
303pub 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)]
315pub 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)]
334pub 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)]
353pub 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)]
370pub 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)]
384pub 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)]
393pub 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)]
404pub 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)]
414pub 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}