wasmtime_c_api/
val.rs

1use crate::r#ref::ref_to_val;
2use crate::{
3    WASM_I32, from_valtype, into_valtype, wasm_ref_t, wasm_valkind_t, wasmtime_anyref_t,
4    wasmtime_externref_t, wasmtime_valkind_t,
5};
6use std::mem::{ManuallyDrop, MaybeUninit};
7use std::ptr;
8use wasmtime::{AsContextMut, Func, HeapType, Ref, RootScope, Val, ValType};
9
10#[repr(C)]
11pub struct wasm_val_t {
12    pub kind: wasm_valkind_t,
13    pub of: wasm_val_union,
14}
15
16#[repr(C)]
17#[derive(Copy, Clone)]
18pub union wasm_val_union {
19    pub i32: i32,
20    pub i64: i64,
21    pub u32: u32,
22    pub u64: u64,
23    pub f32: f32,
24    pub f64: f64,
25    pub ref_: *mut wasm_ref_t,
26}
27
28impl Drop for wasm_val_t {
29    fn drop(&mut self) {
30        match into_valtype(self.kind) {
31            ValType::Ref(_) => unsafe {
32                if !self.of.ref_.is_null() {
33                    drop(Box::from_raw(self.of.ref_));
34                }
35            },
36            _ => {}
37        }
38    }
39}
40
41impl Clone for wasm_val_t {
42    fn clone(&self) -> Self {
43        let mut ret = wasm_val_t {
44            kind: self.kind,
45            of: self.of,
46        };
47        unsafe {
48            match into_valtype(self.kind) {
49                ValType::Ref(_) if !self.of.ref_.is_null() => {
50                    ret.of.ref_ = Box::into_raw(Box::new((*self.of.ref_).clone()));
51                }
52                _ => {}
53            }
54        }
55        return ret;
56    }
57}
58
59impl Default for wasm_val_t {
60    fn default() -> Self {
61        wasm_val_t {
62            kind: WASM_I32,
63            of: wasm_val_union { i32: 0 },
64        }
65    }
66}
67
68impl wasm_val_t {
69    pub fn from_val(val: Val) -> wasm_val_t {
70        match val {
71            Val::I32(i) => wasm_val_t {
72                kind: from_valtype(&ValType::I32),
73                of: wasm_val_union { i32: i },
74            },
75            Val::I64(i) => wasm_val_t {
76                kind: from_valtype(&ValType::I64),
77                of: wasm_val_union { i64: i },
78            },
79            Val::F32(f) => wasm_val_t {
80                kind: from_valtype(&ValType::F32),
81                of: wasm_val_union { u32: f },
82            },
83            Val::F64(f) => wasm_val_t {
84                kind: from_valtype(&ValType::F64),
85                of: wasm_val_union { u64: f },
86            },
87            Val::FuncRef(f) => wasm_val_t {
88                kind: from_valtype(&ValType::FUNCREF),
89                of: wasm_val_union {
90                    ref_: f.map_or(ptr::null_mut(), |f| {
91                        Box::into_raw(Box::new(wasm_ref_t {
92                            r: Ref::Func(Some(f)),
93                        }))
94                    }),
95                },
96            },
97            Val::AnyRef(_) => crate::abort("creating a wasm_val_t from an anyref"),
98            Val::ExternRef(_) => crate::abort("creating a wasm_val_t from an externref"),
99            Val::ExnRef(_) => crate::abort("creating a wasm_val_t from  an exnref"),
100            Val::V128(_) => crate::abort("creating a wasm_val_t from a v128"),
101            Val::ContRef(_) => crate::abort("creating a wasm_val_t from a contref"),
102        }
103    }
104
105    pub fn val(&self) -> Val {
106        match into_valtype(self.kind) {
107            ValType::I32 => Val::from(unsafe { self.of.i32 }),
108            ValType::I64 => Val::from(unsafe { self.of.i64 }),
109            ValType::F32 => Val::from(unsafe { self.of.f32 }),
110            ValType::F64 => Val::from(unsafe { self.of.f64 }),
111            ValType::Ref(r) => match r.heap_type() {
112                HeapType::Func => unsafe {
113                    if self.of.ref_.is_null() {
114                        assert!(r.is_nullable());
115                        Val::FuncRef(None)
116                    } else {
117                        ref_to_val(&*self.of.ref_)
118                    }
119                },
120                _ => unreachable!("wasm_val_t cannot contain non-function reference values"),
121            },
122            ValType::V128 => unimplemented!("wasm_val_t: v128"),
123        }
124    }
125}
126
127#[unsafe(no_mangle)]
128pub unsafe extern "C" fn wasm_val_copy(out: &mut MaybeUninit<wasm_val_t>, source: &wasm_val_t) {
129    crate::initialize(out, source.clone());
130}
131
132#[unsafe(no_mangle)]
133pub unsafe extern "C" fn wasm_val_delete(val: *mut wasm_val_t) {
134    ptr::drop_in_place(val);
135}
136
137#[repr(C)]
138pub struct wasmtime_val_t {
139    pub kind: wasmtime_valkind_t,
140    pub of: wasmtime_val_union,
141}
142
143#[repr(C)]
144pub union wasmtime_val_union {
145    pub i32: i32,
146    pub i64: i64,
147    pub f32: u32,
148    pub f64: u64,
149    pub anyref: ManuallyDrop<wasmtime_anyref_t>,
150    pub externref: ManuallyDrop<wasmtime_externref_t>,
151    pub funcref: wasmtime_func_t,
152    pub v128: [u8; 16],
153}
154
155const _: () = {
156    // This is forced to 24 or 20 bytes by `anyref` and `externref`.
157    assert!(std::mem::size_of::<wasmtime_val_union>() <= 24);
158    assert!(std::mem::align_of::<wasmtime_val_union>() == std::mem::align_of::<u64>());
159};
160
161impl Drop for wasmtime_val_t {
162    fn drop(&mut self) {
163        unsafe {
164            match self.kind {
165                crate::WASMTIME_ANYREF => {
166                    let _ = ManuallyDrop::take(&mut self.of.anyref);
167                }
168                crate::WASMTIME_EXTERNREF => {
169                    let _ = ManuallyDrop::take(&mut self.of.externref);
170                }
171                _ => {}
172            }
173        }
174    }
175}
176
177// The raw pointers are actually optional boxes.
178unsafe impl Send for wasmtime_val_union
179where
180    Option<Box<wasmtime_anyref_t>>: Send,
181    Option<Box<wasmtime_externref_t>>: Send,
182{
183}
184unsafe impl Sync for wasmtime_val_union
185where
186    Option<Box<wasmtime_anyref_t>>: Sync,
187    Option<Box<wasmtime_externref_t>>: Sync,
188{
189}
190
191#[repr(C)]
192#[derive(Clone, Copy)]
193pub union wasmtime_func_t {
194    store_id: u64,
195    func: Func,
196}
197
198impl wasmtime_func_t {
199    unsafe fn as_wasmtime(&self) -> Option<Func> {
200        if self.store_id == 0 {
201            None
202        } else {
203            Some(self.func)
204        }
205    }
206}
207
208impl From<Option<Func>> for wasmtime_func_t {
209    fn from(func: Option<Func>) -> wasmtime_func_t {
210        match func {
211            Some(func) => wasmtime_func_t { func },
212            None => wasmtime_func_t { store_id: 0 },
213        }
214    }
215}
216
217impl wasmtime_val_t {
218    /// Creates a new `wasmtime_val_t` from a `wasmtime::Val`.
219    ///
220    /// Note that this requires a `RootScope` to be present to serve as proof
221    /// that `val` is not require to be rooted in the store itself which would
222    /// prevent GC. Callers should prefer this API where possible, creating a
223    /// temporary `RootScope` when needed.
224    pub fn from_val(cx: &mut RootScope<impl AsContextMut>, val: Val) -> wasmtime_val_t {
225        Self::from_val_unscoped(cx, val)
226    }
227
228    /// Equivalent of [`wasmtime_val_t::from_val`] except that a `RootScope`
229    /// is not required.
230    ///
231    /// This method should only be used when a `RootScope` is known to be
232    /// elsewhere on the stack. For example this is used when we call back out
233    /// to the embedder. In such a situation we know we previously entered with
234    /// some other call so the root scope is on the stack there.
235    pub fn from_val_unscoped(cx: impl AsContextMut, val: Val) -> wasmtime_val_t {
236        match val {
237            Val::I32(i) => wasmtime_val_t {
238                kind: crate::WASMTIME_I32,
239                of: wasmtime_val_union { i32: i },
240            },
241            Val::I64(i) => wasmtime_val_t {
242                kind: crate::WASMTIME_I64,
243                of: wasmtime_val_union { i64: i },
244            },
245            Val::F32(i) => wasmtime_val_t {
246                kind: crate::WASMTIME_F32,
247                of: wasmtime_val_union { f32: i },
248            },
249            Val::F64(i) => wasmtime_val_t {
250                kind: crate::WASMTIME_F64,
251                of: wasmtime_val_union { f64: i },
252            },
253            Val::AnyRef(a) => wasmtime_val_t {
254                kind: crate::WASMTIME_ANYREF,
255                of: wasmtime_val_union {
256                    anyref: ManuallyDrop::new(a.and_then(|a| a.to_owned_rooted(cx).ok()).into()),
257                },
258            },
259            Val::ExternRef(e) => wasmtime_val_t {
260                kind: crate::WASMTIME_EXTERNREF,
261                of: wasmtime_val_union {
262                    externref: ManuallyDrop::new(e.and_then(|e| e.to_owned_rooted(cx).ok()).into()),
263                },
264            },
265            Val::FuncRef(func) => wasmtime_val_t {
266                kind: crate::WASMTIME_FUNCREF,
267                of: wasmtime_val_union {
268                    funcref: func.into(),
269                },
270            },
271            Val::ExnRef(_) => crate::abort("exnrefs not yet supported in C API"),
272            Val::V128(val) => wasmtime_val_t {
273                kind: crate::WASMTIME_V128,
274                of: wasmtime_val_union {
275                    v128: val.as_u128().to_le_bytes(),
276                },
277            },
278            Val::ContRef(_) => crate::abort("contrefs not yet supported in C API (#10248)"),
279        }
280    }
281
282    /// Convert this `wasmtime_val_t` into a `wasmtime::Val`.
283    ///
284    /// See [`wasmtime_val_t::from_val`] for notes on the `RootScope`
285    /// requirement here. Note that this is particularly meaningful for this
286    /// API as the `Val` returned may contain a `Rooted<T>` which requires a
287    /// `RootScope` if we don't want the value to live for the entire lifetime
288    /// of the `Store`.
289    pub unsafe fn to_val(&self, cx: &mut RootScope<impl AsContextMut>) -> Val {
290        self.to_val_unscoped(cx)
291    }
292
293    /// Equivalent of `to_val` except doesn't require a `RootScope`.
294    ///
295    /// See notes on [`wasmtime_val_t::from_val_unscoped`] for notes on when to
296    /// use this.
297    pub unsafe fn to_val_unscoped(&self, cx: impl AsContextMut) -> Val {
298        match self.kind {
299            crate::WASMTIME_I32 => Val::I32(self.of.i32),
300            crate::WASMTIME_I64 => Val::I64(self.of.i64),
301            crate::WASMTIME_F32 => Val::F32(self.of.f32),
302            crate::WASMTIME_F64 => Val::F64(self.of.f64),
303            crate::WASMTIME_V128 => Val::V128(u128::from_le_bytes(self.of.v128).into()),
304            crate::WASMTIME_ANYREF => {
305                Val::AnyRef(self.of.anyref.as_wasmtime().map(|a| a.to_rooted(cx)))
306            }
307            crate::WASMTIME_EXTERNREF => {
308                Val::ExternRef(self.of.externref.as_wasmtime().map(|e| e.to_rooted(cx)))
309            }
310            crate::WASMTIME_FUNCREF => Val::FuncRef(self.of.funcref.as_wasmtime()),
311            other => panic!("unknown wasmtime_valkind_t: {other}"),
312        }
313    }
314}
315
316#[unsafe(no_mangle)]
317pub unsafe extern "C" fn wasmtime_val_unroot(_cx: *mut u8, val: &mut ManuallyDrop<wasmtime_val_t>) {
318    ManuallyDrop::drop(val);
319}
320
321#[unsafe(no_mangle)]
322pub unsafe extern "C" fn wasmtime_val_clone(
323    _cx: *mut u8,
324    src: &wasmtime_val_t,
325    dst: &mut MaybeUninit<wasmtime_val_t>,
326) {
327    let of = match src.kind {
328        crate::WASMTIME_ANYREF => wasmtime_val_union {
329            anyref: ManuallyDrop::new(src.of.anyref.as_wasmtime().into()),
330        },
331        crate::WASMTIME_EXTERNREF => wasmtime_val_union {
332            externref: ManuallyDrop::new(src.of.externref.as_wasmtime().into()),
333        },
334        crate::WASMTIME_I32 => wasmtime_val_union { i32: src.of.i32 },
335        crate::WASMTIME_I64 => wasmtime_val_union { i64: src.of.i64 },
336        crate::WASMTIME_F32 => wasmtime_val_union { f32: src.of.f32 },
337        crate::WASMTIME_F64 => wasmtime_val_union { f64: src.of.f64 },
338        crate::WASMTIME_V128 => wasmtime_val_union { v128: src.of.v128 },
339        crate::WASMTIME_FUNCREF => wasmtime_val_union {
340            funcref: src.of.funcref,
341        },
342        _ => unreachable!(),
343    };
344    dst.write(wasmtime_val_t { kind: src.kind, of });
345}