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    _cx: *mut u8,
265    anyref: Option<&wasmtime_anyref_t>,
266    out: &mut MaybeUninit<wasmtime_anyref_t>,
267) {
268    let anyref = anyref.and_then(|a| a.as_wasmtime());
269    crate::initialize(out, anyref.into());
270}
271
272#[unsafe(no_mangle)]
273pub unsafe extern "C" fn wasmtime_anyref_unroot(
274    _cx: *mut u8,
275    val: Option<&mut ManuallyDrop<wasmtime_anyref_t>>,
276) {
277    if let Some(val) = val {
278        unsafe {
279            ManuallyDrop::drop(val);
280        }
281    }
282}
283
284#[unsafe(no_mangle)]
285pub unsafe extern "C" fn wasmtime_anyref_to_raw(
286    cx: WasmtimeStoreContextMut<'_>,
287    val: Option<&wasmtime_anyref_t>,
288) -> u32 {
289    val.and_then(|v| v.as_wasmtime())
290        .and_then(|e| e.to_raw(cx).ok())
291        .unwrap_or_default()
292}
293
294#[unsafe(no_mangle)]
295pub unsafe extern "C" fn wasmtime_anyref_from_raw(
296    cx: WasmtimeStoreContextMut<'_>,
297    raw: u32,
298    val: &mut MaybeUninit<wasmtime_anyref_t>,
299) {
300    let mut scope = RootScope::new(cx);
301    let anyref =
302        AnyRef::from_raw(&mut scope, raw).map(|a| a.to_owned_rooted(&mut scope).expect("in scope"));
303    crate::initialize(val, anyref.into());
304}
305
306#[unsafe(no_mangle)]
307pub extern "C" fn wasmtime_anyref_from_i31(
308    cx: WasmtimeStoreContextMut<'_>,
309    val: u32,
310    out: &mut MaybeUninit<wasmtime_anyref_t>,
311) {
312    let mut scope = RootScope::new(cx);
313    let anyref = AnyRef::from_i31(&mut scope, I31::wrapping_u32(val));
314    let anyref = anyref.to_owned_rooted(&mut scope).expect("in scope");
315    crate::initialize(out, Some(anyref).into())
316}
317
318#[unsafe(no_mangle)]
319pub unsafe extern "C" fn wasmtime_anyref_i31_get_u(
320    cx: WasmtimeStoreContextMut<'_>,
321    anyref: Option<&wasmtime_anyref_t>,
322    dst: &mut MaybeUninit<u32>,
323) -> bool {
324    match anyref.and_then(|a| a.as_wasmtime()) {
325        Some(anyref) if anyref.is_i31(&cx).expect("OwnedRooted always in scope") => {
326            let val = anyref
327                .unwrap_i31(&cx)
328                .expect("OwnedRooted always in scope")
329                .get_u32();
330            crate::initialize(dst, val);
331            true
332        }
333        _ => false,
334    }
335}
336
337#[unsafe(no_mangle)]
338pub unsafe extern "C" fn wasmtime_anyref_i31_get_s(
339    cx: WasmtimeStoreContextMut<'_>,
340    anyref: Option<&wasmtime_anyref_t>,
341    dst: &mut MaybeUninit<i32>,
342) -> bool {
343    match anyref.and_then(|a| a.as_wasmtime()) {
344        Some(anyref) if anyref.is_i31(&cx).expect("OwnedRooted always in scope") => {
345            let val = anyref
346                .unwrap_i31(&cx)
347                .expect("OwnedRooted always in scope")
348                .get_i32();
349            crate::initialize(dst, val);
350            true
351        }
352        _ => false,
353    }
354}
355
356#[unsafe(no_mangle)]
357pub extern "C" fn wasmtime_externref_new(
358    cx: WasmtimeStoreContextMut<'_>,
359    data: *mut c_void,
360    finalizer: Option<extern "C" fn(*mut c_void)>,
361    out: &mut MaybeUninit<wasmtime_externref_t>,
362) -> bool {
363    let mut scope = RootScope::new(cx);
364    let e = match ExternRef::new(&mut scope, crate::ForeignData { data, finalizer }) {
365        Ok(e) => e,
366        Err(_) => return false,
367    };
368    let e = e.to_owned_rooted(&mut scope).expect("in scope");
369    crate::initialize(out, Some(e).into());
370    true
371}
372
373#[unsafe(no_mangle)]
374pub unsafe extern "C" fn wasmtime_externref_data(
375    cx: WasmtimeStoreContextMut<'_>,
376    externref: Option<&wasmtime_externref_t>,
377) -> *mut c_void {
378    externref
379        .and_then(|e| e.as_wasmtime())
380        .and_then(|e| {
381            let data = e.data(cx).ok()??;
382            Some(data.downcast_ref::<crate::ForeignData>().unwrap().data)
383        })
384        .unwrap_or(ptr::null_mut())
385}
386
387#[unsafe(no_mangle)]
388pub unsafe extern "C" fn wasmtime_externref_clone(
389    _cx: *mut u8,
390    externref: Option<&wasmtime_externref_t>,
391    out: &mut MaybeUninit<wasmtime_externref_t>,
392) {
393    let externref = externref.and_then(|e| e.as_wasmtime());
394    crate::initialize(out, externref.into());
395}
396
397#[unsafe(no_mangle)]
398pub unsafe extern "C" fn wasmtime_externref_unroot(
399    _cx: *mut u8,
400    val: Option<&mut ManuallyDrop<wasmtime_externref_t>>,
401) {
402    if let Some(val) = val {
403        unsafe {
404            ManuallyDrop::drop(val);
405        }
406    }
407}
408
409#[unsafe(no_mangle)]
410pub unsafe extern "C" fn wasmtime_externref_to_raw(
411    cx: WasmtimeStoreContextMut<'_>,
412    val: Option<&wasmtime_externref_t>,
413) -> u32 {
414    val.and_then(|e| e.as_wasmtime())
415        .and_then(|e| e.to_raw(cx).ok())
416        .unwrap_or_default()
417}
418
419#[unsafe(no_mangle)]
420pub unsafe extern "C" fn wasmtime_externref_from_raw(
421    cx: WasmtimeStoreContextMut<'_>,
422    raw: u32,
423    val: &mut MaybeUninit<wasmtime_externref_t>,
424) {
425    let mut scope = RootScope::new(cx);
426    let rooted = ExternRef::from_raw(&mut scope, raw)
427        .map(|e| e.to_owned_rooted(&mut scope).expect("in scope"));
428    crate::initialize(val, rooted.into());
429}