1use crate::r#ref::ref_to_val;
2use crate::{
3 WASM_I32, WasmtimeStoreContextMut, from_valtype, into_valtype, wasm_ref_t, wasm_valkind_t,
4 wasmtime_anyref_t, 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 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
161unsafe impl Send for wasmtime_val_union
163where
164 Option<Box<wasmtime_anyref_t>>: Send,
165 Option<Box<wasmtime_externref_t>>: Send,
166{
167}
168unsafe impl Sync for wasmtime_val_union
169where
170 Option<Box<wasmtime_anyref_t>>: Sync,
171 Option<Box<wasmtime_externref_t>>: Sync,
172{
173}
174
175#[repr(C)]
176#[derive(Clone, Copy)]
177pub union wasmtime_func_t {
178 store_id: u64,
179 func: Func,
180}
181
182impl wasmtime_func_t {
183 unsafe fn as_wasmtime(&self) -> Option<Func> {
184 if self.store_id == 0 {
185 None
186 } else {
187 Some(self.func)
188 }
189 }
190}
191
192impl From<Option<Func>> for wasmtime_func_t {
193 fn from(func: Option<Func>) -> wasmtime_func_t {
194 match func {
195 Some(func) => wasmtime_func_t { func },
196 None => wasmtime_func_t { store_id: 0 },
197 }
198 }
199}
200
201impl wasmtime_val_t {
202 pub fn from_val(cx: &mut RootScope<impl AsContextMut>, val: Val) -> wasmtime_val_t {
209 Self::from_val_unscoped(cx, val)
210 }
211
212 pub fn from_val_unscoped(cx: impl AsContextMut, val: Val) -> wasmtime_val_t {
220 match val {
221 Val::I32(i) => wasmtime_val_t {
222 kind: crate::WASMTIME_I32,
223 of: wasmtime_val_union { i32: i },
224 },
225 Val::I64(i) => wasmtime_val_t {
226 kind: crate::WASMTIME_I64,
227 of: wasmtime_val_union { i64: i },
228 },
229 Val::F32(i) => wasmtime_val_t {
230 kind: crate::WASMTIME_F32,
231 of: wasmtime_val_union { f32: i },
232 },
233 Val::F64(i) => wasmtime_val_t {
234 kind: crate::WASMTIME_F64,
235 of: wasmtime_val_union { f64: i },
236 },
237 Val::AnyRef(a) => wasmtime_val_t {
238 kind: crate::WASMTIME_ANYREF,
239 of: wasmtime_val_union {
240 anyref: ManuallyDrop::new(a.and_then(|a| a.to_owned_rooted(cx).ok()).into()),
241 },
242 },
243 Val::ExternRef(e) => wasmtime_val_t {
244 kind: crate::WASMTIME_EXTERNREF,
245 of: wasmtime_val_union {
246 externref: ManuallyDrop::new(e.and_then(|e| e.to_owned_rooted(cx).ok()).into()),
247 },
248 },
249 Val::FuncRef(func) => wasmtime_val_t {
250 kind: crate::WASMTIME_FUNCREF,
251 of: wasmtime_val_union {
252 funcref: func.into(),
253 },
254 },
255 Val::ExnRef(_) => crate::abort("exnrefs not yet supported in C API"),
256 Val::V128(val) => wasmtime_val_t {
257 kind: crate::WASMTIME_V128,
258 of: wasmtime_val_union {
259 v128: val.as_u128().to_le_bytes(),
260 },
261 },
262 Val::ContRef(_) => crate::abort("contrefs not yet supported in C API (#10248)"),
263 }
264 }
265
266 pub unsafe fn to_val(&self, cx: &mut RootScope<impl AsContextMut>) -> Val {
274 self.to_val_unscoped(cx)
275 }
276
277 pub unsafe fn to_val_unscoped(&self, cx: impl AsContextMut) -> Val {
282 match self.kind {
283 crate::WASMTIME_I32 => Val::I32(self.of.i32),
284 crate::WASMTIME_I64 => Val::I64(self.of.i64),
285 crate::WASMTIME_F32 => Val::F32(self.of.f32),
286 crate::WASMTIME_F64 => Val::F64(self.of.f64),
287 crate::WASMTIME_V128 => Val::V128(u128::from_le_bytes(self.of.v128).into()),
288 crate::WASMTIME_ANYREF => {
289 Val::AnyRef(self.of.anyref.as_wasmtime().map(|a| a.to_rooted(cx)))
290 }
291 crate::WASMTIME_EXTERNREF => {
292 Val::ExternRef(self.of.externref.as_wasmtime().map(|e| e.to_rooted(cx)))
293 }
294 crate::WASMTIME_FUNCREF => Val::FuncRef(self.of.funcref.as_wasmtime()),
295 other => panic!("unknown wasmtime_valkind_t: {other}"),
296 }
297 }
298}
299
300#[unsafe(no_mangle)]
301pub unsafe extern "C" fn wasmtime_val_unroot(
302 _cx: WasmtimeStoreContextMut<'_>,
303 val: &mut MaybeUninit<wasmtime_val_t>,
304) {
305 let val = val.assume_init_read();
306 match val.kind {
307 crate::WASMTIME_ANYREF => {
308 if let Some(val) = ManuallyDrop::into_inner(val.of.anyref).as_wasmtime() {
309 drop(val);
310 }
311 }
312 crate::WASMTIME_EXTERNREF => {
313 if let Some(val) = ManuallyDrop::into_inner(val.of.externref).as_wasmtime() {
314 drop(val);
315 }
316 }
317 _ => {}
318 }
319}
320
321#[unsafe(no_mangle)]
322pub unsafe extern "C" fn wasmtime_val_clone(
323 cx: WasmtimeStoreContextMut<'_>,
324 src: &wasmtime_val_t,
325 dst: &mut MaybeUninit<wasmtime_val_t>,
326) {
327 let mut scope = RootScope::new(cx);
328 let val = src.to_val(&mut scope);
329 crate::initialize(dst, wasmtime_val_t::from_val(&mut scope, val))
330}