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