Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/c-api/src/val.rs
3067 views
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_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 {
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 {
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
59
impl 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
68
impl 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)]
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)]
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 funcref: wasmtime_func_t,
152
pub v128: [u8; 16],
153
}
154
155
const _: () = {
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
161
impl 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.
178
unsafe impl Send for wasmtime_val_union
179
where
180
Option<Box<wasmtime_anyref_t>>: Send,
181
Option<Box<wasmtime_externref_t>>: Send,
182
{
183
}
184
unsafe impl Sync for wasmtime_val_union
185
where
186
Option<Box<wasmtime_anyref_t>>: Sync,
187
Option<Box<wasmtime_externref_t>>: Sync,
188
{
189
}
190
191
#[repr(C)]
192
#[derive(Clone, Copy)]
193
pub union wasmtime_func_t {
194
store_id: u64,
195
func: Func,
196
}
197
198
impl 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
208
impl 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
217
impl 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)]
317
pub unsafe extern "C" fn wasmtime_val_unroot(val: &mut ManuallyDrop<wasmtime_val_t>) {
318
ManuallyDrop::drop(val);
319
}
320
321
#[unsafe(no_mangle)]
322
pub unsafe extern "C" fn wasmtime_val_clone(
323
src: &wasmtime_val_t,
324
dst: &mut MaybeUninit<wasmtime_val_t>,
325
) {
326
let of = match src.kind {
327
crate::WASMTIME_ANYREF => wasmtime_val_union {
328
anyref: ManuallyDrop::new(src.of.anyref.as_wasmtime().into()),
329
},
330
crate::WASMTIME_EXTERNREF => wasmtime_val_union {
331
externref: ManuallyDrop::new(src.of.externref.as_wasmtime().into()),
332
},
333
crate::WASMTIME_I32 => wasmtime_val_union { i32: src.of.i32 },
334
crate::WASMTIME_I64 => wasmtime_val_union { i64: src.of.i64 },
335
crate::WASMTIME_F32 => wasmtime_val_union { f32: src.of.f32 },
336
crate::WASMTIME_F64 => wasmtime_val_union { f64: src.of.f64 },
337
crate::WASMTIME_V128 => wasmtime_val_union { v128: src.of.v128 },
338
crate::WASMTIME_FUNCREF => wasmtime_val_union {
339
funcref: src.of.funcref,
340
},
341
_ => unreachable!(),
342
};
343
dst.write(wasmtime_val_t { kind: src.kind, of });
344
}
345
346