1#[cfg(feature = "gc")]
2use crate::r#ref::ref_to_val;
3#[cfg(feature = "gc")]
4use crate::{
5 WASM_EXTERNREF, WASM_FUNCREF, wasm_ref_t, wasmtime_anyref_t, wasmtime_exnref_t,
6 wasmtime_externref_t,
7};
8use crate::{WASM_F32, WASM_F64, WASM_I32, WASM_I64, wasm_valkind_t};
9use std::mem::{ManuallyDrop, MaybeUninit};
10use std::ptr;
11use wasmtime::{AsContextMut, Func, Val};
12#[cfg(feature = "gc")]
13use wasmtime::{Ref, RootScope};
14
15#[repr(C)]
16pub struct wasm_val_t {
17 pub kind: wasm_valkind_t,
18 pub of: wasm_val_union,
19}
20
21#[repr(C)]
22#[derive(Copy, Clone)]
23pub union wasm_val_union {
24 pub i32: i32,
25 pub i64: i64,
26 pub u32: u32,
27 pub u64: u64,
28 pub f32: f32,
29 pub f64: f64,
30 #[cfg(feature = "gc")]
31 pub ref_: *mut wasm_ref_t,
32}
33
34#[cfg(feature = "gc")]
35impl Drop for wasm_val_t {
36 fn drop(&mut self) {
37 match self.kind {
38 WASM_FUNCREF | WASM_EXTERNREF => unsafe {
39 if !self.of.ref_.is_null() {
40 drop(Box::from_raw(self.of.ref_));
41 }
42 },
43 _ => {}
44 }
45 }
46}
47
48impl Clone for wasm_val_t {
49 fn clone(&self) -> Self {
50 #[allow(
51 unused_mut,
52 reason = "needed for conditional mutation under cfg(feature = \"gc\")"
53 )]
54 let mut ret = wasm_val_t {
55 kind: self.kind,
56 of: self.of,
57 };
58
59 #[cfg(feature = "gc")]
60 unsafe {
61 match self.kind {
62 WASM_FUNCREF | WASM_EXTERNREF if !self.of.ref_.is_null() => {
63 ret.of.ref_ = Box::into_raw(Box::new((*self.of.ref_).clone()));
64 }
65 _ => {}
66 }
67 }
68
69 return ret;
70 }
71}
72
73impl Default for wasm_val_t {
74 fn default() -> Self {
75 wasm_val_t {
76 kind: WASM_I32,
77 of: wasm_val_union { i32: 0 },
78 }
79 }
80}
81
82impl wasm_val_t {
83 pub fn from_val(val: Val) -> wasm_val_t {
84 match val {
85 Val::I32(i) => wasm_val_t {
86 kind: WASM_I32,
87 of: wasm_val_union { i32: i },
88 },
89 Val::I64(i) => wasm_val_t {
90 kind: WASM_I64,
91 of: wasm_val_union { i64: i },
92 },
93 Val::F32(f) => wasm_val_t {
94 kind: WASM_F32,
95 of: wasm_val_union { u32: f },
96 },
97 Val::F64(f) => wasm_val_t {
98 kind: WASM_F64,
99 of: wasm_val_union { u64: f },
100 },
101 #[cfg(feature = "gc")]
102 Val::FuncRef(f) => wasm_val_t {
103 kind: WASM_FUNCREF,
104 of: wasm_val_union {
105 ref_: f.map_or(ptr::null_mut(), |f| {
106 Box::into_raw(Box::new(wasm_ref_t {
107 r: Ref::Func(Some(f)),
108 }))
109 }),
110 },
111 },
112 #[cfg(not(feature = "gc"))]
113 Val::FuncRef(_) => crate::abort("creating a wasm_val_t from a funcref"),
114 Val::AnyRef(_) => crate::abort("creating a wasm_val_t from an anyref"),
115 Val::ExternRef(_) => crate::abort("creating a wasm_val_t from an externref"),
116 Val::ExnRef(_) => crate::abort("creating a wasm_val_t from an exnref"),
117 Val::V128(_) => crate::abort("creating a wasm_val_t from a v128"),
118 Val::ContRef(_) => crate::abort("creating a wasm_val_t from a contref"),
119 }
120 }
121
122 pub fn val(&self) -> Val {
123 match self.kind {
124 WASM_I32 => Val::from(unsafe { self.of.i32 }),
125 WASM_I64 => Val::from(unsafe { self.of.i64 }),
126 WASM_F32 => Val::from(unsafe { self.of.f32 }),
127 WASM_F64 => Val::from(unsafe { self.of.f64 }),
128 #[cfg(feature = "gc")]
129 WASM_FUNCREF => unsafe {
130 if self.of.ref_.is_null() {
131 Val::FuncRef(None)
132 } else {
133 ref_to_val(&*self.of.ref_)
134 }
135 },
136 _ => crate::abort("unsupported val discriminant"),
137 }
138 }
139}
140
141#[unsafe(no_mangle)]
142pub unsafe extern "C" fn wasm_val_copy(out: &mut MaybeUninit<wasm_val_t>, source: &wasm_val_t) {
143 crate::initialize(out, source.clone());
144}
145
146#[unsafe(no_mangle)]
147pub unsafe extern "C" fn wasm_val_delete(val: *mut wasm_val_t) {
148 ptr::drop_in_place(val);
149}
150
151#[repr(C)]
152pub struct wasmtime_val_t {
153 pub kind: wasmtime_valkind_t,
154 pub of: wasmtime_val_union,
155}
156
157pub type wasmtime_valkind_t = u8;
158pub const WASMTIME_I32: wasmtime_valkind_t = 0;
159pub const WASMTIME_I64: wasmtime_valkind_t = 1;
160pub const WASMTIME_F32: wasmtime_valkind_t = 2;
161pub const WASMTIME_F64: wasmtime_valkind_t = 3;
162pub const WASMTIME_V128: wasmtime_valkind_t = 4;
163pub const WASMTIME_FUNCREF: wasmtime_valkind_t = 5;
164pub const WASMTIME_EXTERNREF: wasmtime_valkind_t = 6;
165pub const WASMTIME_ANYREF: wasmtime_valkind_t = 7;
166pub const WASMTIME_EXNREF: wasmtime_valkind_t = 8;
167
168#[repr(C)]
169pub union wasmtime_val_union {
170 pub i32: i32,
171 pub i64: i64,
172 pub f32: u32,
173 pub f64: u64,
174 #[cfg(feature = "gc")]
175 pub anyref: ManuallyDrop<wasmtime_anyref_t>,
176 #[cfg(feature = "gc")]
177 pub externref: ManuallyDrop<wasmtime_externref_t>,
178 #[cfg(feature = "gc")]
179 pub exnref: ManuallyDrop<wasmtime_exnref_t>,
180 #[cfg(feature = "gc")]
181 pub funcref: wasmtime_func_t,
182 pub v128: [u8; 16],
183}
184
185const _: () = {
186 assert!(std::mem::size_of::<wasmtime_val_union>() <= 24);
188 assert!(std::mem::align_of::<wasmtime_val_union>() == std::mem::align_of::<u64>());
189};
190
191#[cfg(feature = "gc")]
192impl Drop for wasmtime_val_t {
193 fn drop(&mut self) {
194 unsafe {
195 match self.kind {
196 crate::WASMTIME_ANYREF => {
197 let _ = ManuallyDrop::take(&mut self.of.anyref);
198 }
199 crate::WASMTIME_EXTERNREF => {
200 let _ = ManuallyDrop::take(&mut self.of.externref);
201 }
202 crate::WASMTIME_EXNREF => {
203 let _ = ManuallyDrop::take(&mut self.of.exnref);
204 }
205 _ => {}
206 }
207 }
208 }
209}
210
211#[cfg(feature = "gc")]
213unsafe impl Send for wasmtime_val_union
214where
215 Option<Box<wasmtime_anyref_t>>: Send,
216 Option<Box<wasmtime_externref_t>>: Send,
217 Option<Box<wasmtime_exnref_t>>: Send,
218{
219}
220#[cfg(feature = "gc")]
221unsafe impl Sync for wasmtime_val_union
222where
223 Option<Box<wasmtime_anyref_t>>: Sync,
224 Option<Box<wasmtime_externref_t>>: Sync,
225 Option<Box<wasmtime_exnref_t>>: Sync,
226{
227}
228
229#[repr(C)]
230#[derive(Clone, Copy)]
231pub union wasmtime_func_t {
232 store_id: u64,
233 func: Func,
234}
235
236impl wasmtime_func_t {
237 #[cfg(feature = "gc")]
238 unsafe fn as_wasmtime(&self) -> Option<Func> {
239 if self.store_id == 0 {
240 None
241 } else {
242 Some(self.func)
243 }
244 }
245}
246
247impl From<Option<Func>> for wasmtime_func_t {
248 fn from(func: Option<Func>) -> wasmtime_func_t {
249 match func {
250 Some(func) => wasmtime_func_t { func },
251 None => wasmtime_func_t { store_id: 0 },
252 }
253 }
254}
255
256impl wasmtime_val_t {
257 #[cfg(feature = "gc")]
264 pub fn from_val(cx: &mut RootScope<impl AsContextMut>, val: Val) -> wasmtime_val_t {
265 Self::from_val_unscoped(cx, val)
266 }
267
268 #[cfg(not(feature = "gc"))]
272 pub fn from_val(cx: impl AsContextMut, val: Val) -> wasmtime_val_t {
273 Self::from_val_unscoped(cx, val)
274 }
275
276 pub fn from_val_unscoped(cx: impl AsContextMut, val: Val) -> wasmtime_val_t {
284 #[cfg(not(feature = "gc"))]
285 let _ = cx;
286 match val {
287 Val::I32(i) => wasmtime_val_t {
288 kind: crate::WASMTIME_I32,
289 of: wasmtime_val_union { i32: i },
290 },
291 Val::I64(i) => wasmtime_val_t {
292 kind: crate::WASMTIME_I64,
293 of: wasmtime_val_union { i64: i },
294 },
295 Val::F32(i) => wasmtime_val_t {
296 kind: crate::WASMTIME_F32,
297 of: wasmtime_val_union { f32: i },
298 },
299 Val::F64(i) => wasmtime_val_t {
300 kind: crate::WASMTIME_F64,
301 of: wasmtime_val_union { f64: i },
302 },
303 #[cfg(feature = "gc")]
304 Val::AnyRef(a) => wasmtime_val_t {
305 kind: crate::WASMTIME_ANYREF,
306 of: wasmtime_val_union {
307 anyref: ManuallyDrop::new(a.and_then(|a| a.to_owned_rooted(cx).ok()).into()),
308 },
309 },
310 #[cfg(feature = "gc")]
311 Val::ExternRef(e) => wasmtime_val_t {
312 kind: crate::WASMTIME_EXTERNREF,
313 of: wasmtime_val_union {
314 externref: ManuallyDrop::new(e.and_then(|e| e.to_owned_rooted(cx).ok()).into()),
315 },
316 },
317 #[cfg(feature = "gc")]
318 Val::FuncRef(func) => wasmtime_val_t {
319 kind: crate::WASMTIME_FUNCREF,
320 of: wasmtime_val_union {
321 funcref: func.into(),
322 },
323 },
324 #[cfg(feature = "gc")]
325 Val::ExnRef(e) => wasmtime_val_t {
326 kind: crate::WASMTIME_EXNREF,
327 of: wasmtime_val_union {
328 exnref: ManuallyDrop::new(e.and_then(|e| e.to_owned_rooted(cx).ok()).into()),
329 },
330 },
331 #[cfg(not(feature = "gc"))]
332 Val::AnyRef(_) | Val::ExternRef(_) | Val::FuncRef(_) | Val::ExnRef(_) => {
333 crate::abort("reference types require gc feature")
334 }
335 Val::V128(val) => wasmtime_val_t {
336 kind: crate::WASMTIME_V128,
337 of: wasmtime_val_union {
338 v128: val.as_u128().to_le_bytes(),
339 },
340 },
341 Val::ContRef(_) => crate::abort("contrefs not yet supported in C API (#10248)"),
342 }
343 }
344
345 #[cfg(feature = "gc")]
353 pub unsafe fn to_val(&self, cx: &mut RootScope<impl AsContextMut>) -> Val {
354 self.to_val_unscoped(cx)
355 }
356
357 #[cfg(not(feature = "gc"))]
361 pub unsafe fn to_val(&self, cx: impl AsContextMut) -> Val {
362 self.to_val_unscoped(cx)
363 }
364
365 pub unsafe fn to_val_unscoped(&self, cx: impl AsContextMut) -> Val {
370 #[cfg(not(feature = "gc"))]
371 let _ = cx;
372 match self.kind {
373 crate::WASMTIME_I32 => Val::I32(self.of.i32),
374 crate::WASMTIME_I64 => Val::I64(self.of.i64),
375 crate::WASMTIME_F32 => Val::F32(self.of.f32),
376 crate::WASMTIME_F64 => Val::F64(self.of.f64),
377 crate::WASMTIME_V128 => Val::V128(u128::from_le_bytes(self.of.v128).into()),
378 #[cfg(feature = "gc")]
379 crate::WASMTIME_ANYREF => {
380 Val::AnyRef(self.of.anyref.as_wasmtime().map(|a| a.to_rooted(cx)))
381 }
382 #[cfg(feature = "gc")]
383 crate::WASMTIME_EXTERNREF => {
384 Val::ExternRef(self.of.externref.as_wasmtime().map(|e| e.to_rooted(cx)))
385 }
386 #[cfg(feature = "gc")]
387 crate::WASMTIME_FUNCREF => Val::FuncRef(self.of.funcref.as_wasmtime()),
388 #[cfg(feature = "gc")]
389 crate::WASMTIME_EXNREF => {
390 Val::ExnRef(self.of.exnref.as_wasmtime().map(|e| e.to_rooted(cx)))
391 }
392 other => panic!("unknown wasmtime_valkind_t: {other}"),
393 }
394 }
395}
396
397#[unsafe(no_mangle)]
398pub unsafe extern "C" fn wasmtime_val_unroot(val: &mut ManuallyDrop<wasmtime_val_t>) {
399 ManuallyDrop::drop(val);
400}
401
402#[unsafe(no_mangle)]
403pub unsafe extern "C" fn wasmtime_val_clone(
404 src: &wasmtime_val_t,
405 dst: &mut MaybeUninit<wasmtime_val_t>,
406) {
407 let of = match src.kind {
408 #[cfg(feature = "gc")]
409 crate::WASMTIME_ANYREF => wasmtime_val_union {
410 anyref: ManuallyDrop::new(src.of.anyref.as_wasmtime().into()),
411 },
412 #[cfg(feature = "gc")]
413 crate::WASMTIME_EXTERNREF => wasmtime_val_union {
414 externref: ManuallyDrop::new(src.of.externref.as_wasmtime().into()),
415 },
416 #[cfg(feature = "gc")]
417 crate::WASMTIME_EXNREF => wasmtime_val_union {
418 exnref: ManuallyDrop::new(src.of.exnref.as_wasmtime().into()),
419 },
420 crate::WASMTIME_I32 => wasmtime_val_union { i32: src.of.i32 },
421 crate::WASMTIME_I64 => wasmtime_val_union { i64: src.of.i64 },
422 crate::WASMTIME_F32 => wasmtime_val_union { f32: src.of.f32 },
423 crate::WASMTIME_F64 => wasmtime_val_union { f64: src.of.f64 },
424 crate::WASMTIME_V128 => wasmtime_val_union { v128: src.of.v128 },
425 #[cfg(feature = "gc")]
426 crate::WASMTIME_FUNCREF => wasmtime_val_union {
427 funcref: src.of.funcref,
428 },
429 _ => unreachable!(),
430 };
431 dst.write(wasmtime_val_t { kind: src.kind, of });
432}