1 use crate::r#ref::ref_to_val;
2 use crate::{
3 WASM_I32, from_valtype, into_valtype, wasm_ref_t, wasm_valkind_t, wasmtime_anyref_t,
4 wasmtime_exnref_t, wasmtime_externref_t, wasmtime_valkind_t,
5 };
6 use std::mem::{ManuallyDrop, MaybeUninit};
7 use std::ptr;
8 use wasmtime::{AsContextMut, Func, HeapType, Ref, RootScope, Val, ValType};
9
10 #[repr(C)]
11 pub 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)]
18 pub 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
28 impl Drop for wasm_val_t {
drop(&mut self)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
41 impl Clone for wasm_val_t {
clone(&self) -> Self42 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
59 impl Default for wasm_val_t {
default() -> Self60 fn default() -> Self {
61 wasm_val_t {
62 kind: WASM_I32,
63 of: wasm_val_union { i32: 0 },
64 }
65 }
66 }
67
68 impl wasm_val_t {
from_val(val: Val) -> wasm_val_t69 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
val(&self) -> Val105 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)]
wasm_val_copy(out: &mut MaybeUninit<wasm_val_t>, source: &wasm_val_t)128 pub 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)]
wasm_val_delete(val: *mut wasm_val_t)133 pub unsafe extern "C" fn wasm_val_delete(val: *mut wasm_val_t) {
134 ptr::drop_in_place(val);
135 }
136
137 #[repr(C)]
138 pub struct wasmtime_val_t {
139 pub kind: wasmtime_valkind_t,
140 pub of: wasmtime_val_union,
141 }
142
143 #[repr(C)]
144 pub 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 exnref: ManuallyDrop<wasmtime_exnref_t>,
152 pub funcref: wasmtime_func_t,
153 pub v128: [u8; 16],
154 }
155
156 const _: () = {
157 // This is forced to 24 or 20 bytes by `anyref` and `externref`.
158 assert!(std::mem::size_of::<wasmtime_val_union>() <= 24);
159 assert!(std::mem::align_of::<wasmtime_val_union>() == std::mem::align_of::<u64>());
160 };
161
162 impl Drop for wasmtime_val_t {
drop(&mut self)163 fn drop(&mut self) {
164 unsafe {
165 match self.kind {
166 crate::WASMTIME_ANYREF => {
167 let _ = ManuallyDrop::take(&mut self.of.anyref);
168 }
169 crate::WASMTIME_EXTERNREF => {
170 let _ = ManuallyDrop::take(&mut self.of.externref);
171 }
172 crate::WASMTIME_EXNREF => {
173 let _ = ManuallyDrop::take(&mut self.of.exnref);
174 }
175 _ => {}
176 }
177 }
178 }
179 }
180
181 // The raw pointers are actually optional boxes.
182 unsafe impl Send for wasmtime_val_union
183 where
184 Option<Box<wasmtime_anyref_t>>: Send,
185 Option<Box<wasmtime_externref_t>>: Send,
186 Option<Box<wasmtime_exnref_t>>: Send,
187 {
188 }
189 unsafe impl Sync for wasmtime_val_union
190 where
191 Option<Box<wasmtime_anyref_t>>: Sync,
192 Option<Box<wasmtime_externref_t>>: Sync,
193 Option<Box<wasmtime_exnref_t>>: Sync,
194 {
195 }
196
197 #[repr(C)]
198 #[derive(Clone, Copy)]
199 pub union wasmtime_func_t {
200 store_id: u64,
201 func: Func,
202 }
203
204 impl wasmtime_func_t {
as_wasmtime(&self) -> Option<Func>205 unsafe fn as_wasmtime(&self) -> Option<Func> {
206 if self.store_id == 0 {
207 None
208 } else {
209 Some(self.func)
210 }
211 }
212 }
213
214 impl From<Option<Func>> for wasmtime_func_t {
from(func: Option<Func>) -> wasmtime_func_t215 fn from(func: Option<Func>) -> wasmtime_func_t {
216 match func {
217 Some(func) => wasmtime_func_t { func },
218 None => wasmtime_func_t { store_id: 0 },
219 }
220 }
221 }
222
223 impl wasmtime_val_t {
224 /// Creates a new `wasmtime_val_t` from a `wasmtime::Val`.
225 ///
226 /// Note that this requires a `RootScope` to be present to serve as proof
227 /// that `val` is not require to be rooted in the store itself which would
228 /// prevent GC. Callers should prefer this API where possible, creating a
229 /// temporary `RootScope` when needed.
from_val(cx: &mut RootScope<impl AsContextMut>, val: Val) -> wasmtime_val_t230 pub fn from_val(cx: &mut RootScope<impl AsContextMut>, val: Val) -> wasmtime_val_t {
231 Self::from_val_unscoped(cx, val)
232 }
233
234 /// Equivalent of [`wasmtime_val_t::from_val`] except that a `RootScope`
235 /// is not required.
236 ///
237 /// This method should only be used when a `RootScope` is known to be
238 /// elsewhere on the stack. For example this is used when we call back out
239 /// to the embedder. In such a situation we know we previously entered with
240 /// some other call so the root scope is on the stack there.
from_val_unscoped(cx: impl AsContextMut, val: Val) -> wasmtime_val_t241 pub fn from_val_unscoped(cx: impl AsContextMut, val: Val) -> wasmtime_val_t {
242 match val {
243 Val::I32(i) => wasmtime_val_t {
244 kind: crate::WASMTIME_I32,
245 of: wasmtime_val_union { i32: i },
246 },
247 Val::I64(i) => wasmtime_val_t {
248 kind: crate::WASMTIME_I64,
249 of: wasmtime_val_union { i64: i },
250 },
251 Val::F32(i) => wasmtime_val_t {
252 kind: crate::WASMTIME_F32,
253 of: wasmtime_val_union { f32: i },
254 },
255 Val::F64(i) => wasmtime_val_t {
256 kind: crate::WASMTIME_F64,
257 of: wasmtime_val_union { f64: i },
258 },
259 Val::AnyRef(a) => wasmtime_val_t {
260 kind: crate::WASMTIME_ANYREF,
261 of: wasmtime_val_union {
262 anyref: ManuallyDrop::new(a.and_then(|a| a.to_owned_rooted(cx).ok()).into()),
263 },
264 },
265 Val::ExternRef(e) => wasmtime_val_t {
266 kind: crate::WASMTIME_EXTERNREF,
267 of: wasmtime_val_union {
268 externref: ManuallyDrop::new(e.and_then(|e| e.to_owned_rooted(cx).ok()).into()),
269 },
270 },
271 Val::FuncRef(func) => wasmtime_val_t {
272 kind: crate::WASMTIME_FUNCREF,
273 of: wasmtime_val_union {
274 funcref: func.into(),
275 },
276 },
277 Val::ExnRef(e) => wasmtime_val_t {
278 kind: crate::WASMTIME_EXNREF,
279 of: wasmtime_val_union {
280 exnref: ManuallyDrop::new(e.and_then(|e| e.to_owned_rooted(cx).ok()).into()),
281 },
282 },
283 Val::V128(val) => wasmtime_val_t {
284 kind: crate::WASMTIME_V128,
285 of: wasmtime_val_union {
286 v128: val.as_u128().to_le_bytes(),
287 },
288 },
289 Val::ContRef(_) => crate::abort("contrefs not yet supported in C API (#10248)"),
290 }
291 }
292
293 /// Convert this `wasmtime_val_t` into a `wasmtime::Val`.
294 ///
295 /// See [`wasmtime_val_t::from_val`] for notes on the `RootScope`
296 /// requirement here. Note that this is particularly meaningful for this
297 /// API as the `Val` returned may contain a `Rooted<T>` which requires a
298 /// `RootScope` if we don't want the value to live for the entire lifetime
299 /// of the `Store`.
to_val(&self, cx: &mut RootScope<impl AsContextMut>) -> Val300 pub unsafe fn to_val(&self, cx: &mut RootScope<impl AsContextMut>) -> Val {
301 self.to_val_unscoped(cx)
302 }
303
304 /// Equivalent of `to_val` except doesn't require a `RootScope`.
305 ///
306 /// See notes on [`wasmtime_val_t::from_val_unscoped`] for notes on when to
307 /// use this.
to_val_unscoped(&self, cx: impl AsContextMut) -> Val308 pub unsafe fn to_val_unscoped(&self, cx: impl AsContextMut) -> Val {
309 match self.kind {
310 crate::WASMTIME_I32 => Val::I32(self.of.i32),
311 crate::WASMTIME_I64 => Val::I64(self.of.i64),
312 crate::WASMTIME_F32 => Val::F32(self.of.f32),
313 crate::WASMTIME_F64 => Val::F64(self.of.f64),
314 crate::WASMTIME_V128 => Val::V128(u128::from_le_bytes(self.of.v128).into()),
315 crate::WASMTIME_ANYREF => {
316 Val::AnyRef(self.of.anyref.as_wasmtime().map(|a| a.to_rooted(cx)))
317 }
318 crate::WASMTIME_EXTERNREF => {
319 Val::ExternRef(self.of.externref.as_wasmtime().map(|e| e.to_rooted(cx)))
320 }
321 crate::WASMTIME_FUNCREF => Val::FuncRef(self.of.funcref.as_wasmtime()),
322 crate::WASMTIME_EXNREF => {
323 Val::ExnRef(self.of.exnref.as_wasmtime().map(|e| e.to_rooted(cx)))
324 }
325 other => panic!("unknown wasmtime_valkind_t: {other}"),
326 }
327 }
328 }
329
330 #[unsafe(no_mangle)]
wasmtime_val_unroot(val: &mut ManuallyDrop<wasmtime_val_t>)331 pub unsafe extern "C" fn wasmtime_val_unroot(val: &mut ManuallyDrop<wasmtime_val_t>) {
332 ManuallyDrop::drop(val);
333 }
334
335 #[unsafe(no_mangle)]
wasmtime_val_clone( src: &wasmtime_val_t, dst: &mut MaybeUninit<wasmtime_val_t>, )336 pub unsafe extern "C" fn wasmtime_val_clone(
337 src: &wasmtime_val_t,
338 dst: &mut MaybeUninit<wasmtime_val_t>,
339 ) {
340 let of = match src.kind {
341 crate::WASMTIME_ANYREF => wasmtime_val_union {
342 anyref: ManuallyDrop::new(src.of.anyref.as_wasmtime().into()),
343 },
344 crate::WASMTIME_EXTERNREF => wasmtime_val_union {
345 externref: ManuallyDrop::new(src.of.externref.as_wasmtime().into()),
346 },
347 crate::WASMTIME_EXNREF => wasmtime_val_union {
348 exnref: ManuallyDrop::new(src.of.exnref.as_wasmtime().into()),
349 },
350 crate::WASMTIME_I32 => wasmtime_val_union { i32: src.of.i32 },
351 crate::WASMTIME_I64 => wasmtime_val_union { i64: src.of.i64 },
352 crate::WASMTIME_F32 => wasmtime_val_union { f32: src.of.f32 },
353 crate::WASMTIME_F64 => wasmtime_val_union { f64: src.of.f64 },
354 crate::WASMTIME_V128 => wasmtime_val_union { v128: src.of.v128 },
355 crate::WASMTIME_FUNCREF => wasmtime_val_union {
356 funcref: src.of.funcref,
357 },
358 _ => unreachable!(),
359 };
360 dst.write(wasmtime_val_t { kind: src.kind, of });
361 }
362