Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/c-api/src/ref.rs
1692 views
1
use crate::{WasmtimeStoreContextMut, abort};
2
use std::{mem::MaybeUninit, num::NonZeroU64, os::raw::c_void, ptr};
3
use wasmtime::{AnyRef, ExternRef, I31, OwnedRooted, Ref, RootScope, Val};
4
5
/// `*mut wasm_ref_t` is a reference type (`externref` or `funcref`), as seen by
6
/// the C API. Because we do not have a uniform representation for `funcref`s
7
/// and `externref`s, a `*mut wasm_ref_t` is morally a
8
/// `Option<Box<Either<ExternRef, Func>>>`.
9
///
10
/// A null `*mut wasm_ref_t` is either a null `funcref` or a null `externref`
11
/// depending on context (e.g. the table's element type that it is going into or
12
/// coming out of).
13
///
14
/// Note: this is not `#[repr(C)]` because it is an opaque type in the header,
15
/// and only ever referenced as `*mut wasm_ref_t`. This also lets us use a
16
/// regular, non-`repr(C)` `enum` to define `WasmRefInner`.
17
#[derive(Clone)]
18
pub struct wasm_ref_t {
19
pub(crate) r: Ref,
20
}
21
22
wasmtime_c_api_macros::declare_own!(wasm_ref_t);
23
24
impl wasm_ref_t {
25
pub(crate) fn new(r: Ref) -> Option<Box<wasm_ref_t>> {
26
if r.is_null() || !r.is_func() {
27
None
28
} else {
29
Some(Box::new(wasm_ref_t { r }))
30
}
31
}
32
}
33
34
pub(crate) fn ref_to_val(r: &wasm_ref_t) -> Val {
35
Val::from(r.r.clone())
36
}
37
38
#[unsafe(no_mangle)]
39
pub extern "C" fn wasm_ref_copy(r: Option<&wasm_ref_t>) -> Option<Box<wasm_ref_t>> {
40
r.map(|r| Box::new(r.clone()))
41
}
42
43
#[unsafe(no_mangle)]
44
pub extern "C" fn wasm_ref_same(_a: Option<&wasm_ref_t>, _b: Option<&wasm_ref_t>) -> bool {
45
// We need a store to determine whether these are the same reference or not.
46
abort("wasm_ref_same")
47
}
48
49
#[unsafe(no_mangle)]
50
pub extern "C" fn wasm_ref_get_host_info(_ref: Option<&wasm_ref_t>) -> *mut c_void {
51
std::ptr::null_mut()
52
}
53
54
#[unsafe(no_mangle)]
55
pub extern "C" fn wasm_ref_set_host_info(_ref: Option<&wasm_ref_t>, _info: *mut c_void) {
56
abort("wasm_ref_set_host_info")
57
}
58
59
#[unsafe(no_mangle)]
60
pub extern "C" fn wasm_ref_set_host_info_with_finalizer(
61
_ref: Option<&wasm_ref_t>,
62
_info: *mut c_void,
63
_finalizer: Option<extern "C" fn(*mut c_void)>,
64
) {
65
abort("wasm_ref_set_host_info_with_finalizer")
66
}
67
68
#[unsafe(no_mangle)]
69
pub extern "C" fn wasm_ref_as_extern(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_extern_t> {
70
abort("wasm_ref_as_extern")
71
}
72
73
#[unsafe(no_mangle)]
74
pub extern "C" fn wasm_ref_as_extern_const(
75
_ref: Option<&wasm_ref_t>,
76
) -> Option<&crate::wasm_extern_t> {
77
abort("wasm_ref_as_extern_const")
78
}
79
80
#[unsafe(no_mangle)]
81
pub extern "C" fn wasm_ref_as_foreign(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_foreign_t> {
82
abort("wasm_ref_as_foreign")
83
}
84
85
#[unsafe(no_mangle)]
86
pub extern "C" fn wasm_ref_as_foreign_const(
87
_ref: Option<&wasm_ref_t>,
88
) -> Option<&crate::wasm_foreign_t> {
89
abort("wasm_ref_as_foreign_const")
90
}
91
92
#[unsafe(no_mangle)]
93
pub extern "C" fn wasm_ref_as_func(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_func_t> {
94
abort("wasm_ref_as_func")
95
}
96
97
#[unsafe(no_mangle)]
98
pub extern "C" fn wasm_ref_as_func_const(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_func_t> {
99
abort("wasm_ref_as_func_const")
100
}
101
102
#[unsafe(no_mangle)]
103
pub extern "C" fn wasm_ref_as_global(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_global_t> {
104
abort("wasm_ref_as_global")
105
}
106
107
#[unsafe(no_mangle)]
108
pub extern "C" fn wasm_ref_as_global_const(
109
_ref: Option<&wasm_ref_t>,
110
) -> Option<&crate::wasm_global_t> {
111
abort("wasm_ref_as_global_const")
112
}
113
114
#[unsafe(no_mangle)]
115
pub extern "C" fn wasm_ref_as_instance(
116
_ref: Option<&wasm_ref_t>,
117
) -> Option<&crate::wasm_instance_t> {
118
abort("wasm_ref_as_instance")
119
}
120
121
#[unsafe(no_mangle)]
122
pub extern "C" fn wasm_ref_as_instance_const(
123
_ref: Option<&wasm_ref_t>,
124
) -> Option<&crate::wasm_instance_t> {
125
abort("wasm_ref_as_instance_const")
126
}
127
128
#[unsafe(no_mangle)]
129
pub extern "C" fn wasm_ref_as_memory(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_memory_t> {
130
abort("wasm_ref_as_memory")
131
}
132
133
#[unsafe(no_mangle)]
134
pub extern "C" fn wasm_ref_as_memory_const(
135
_ref: Option<&wasm_ref_t>,
136
) -> Option<&crate::wasm_memory_t> {
137
abort("wasm_ref_as_memory_const")
138
}
139
140
#[unsafe(no_mangle)]
141
pub extern "C" fn wasm_ref_as_module(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_module_t> {
142
abort("wasm_ref_as_module")
143
}
144
145
#[unsafe(no_mangle)]
146
pub extern "C" fn wasm_ref_as_module_const(
147
_ref: Option<&wasm_ref_t>,
148
) -> Option<&crate::wasm_module_t> {
149
abort("wasm_ref_as_module_const")
150
}
151
152
#[unsafe(no_mangle)]
153
pub extern "C" fn wasm_ref_as_table(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_table_t> {
154
abort("wasm_ref_as_table")
155
}
156
157
#[unsafe(no_mangle)]
158
pub extern "C" fn wasm_ref_as_table_const(
159
_ref: Option<&wasm_ref_t>,
160
) -> Option<&crate::wasm_table_t> {
161
abort("wasm_ref_as_table_const")
162
}
163
164
#[unsafe(no_mangle)]
165
pub extern "C" fn wasm_ref_as_trap(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_trap_t> {
166
abort("wasm_ref_as_trap")
167
}
168
169
#[unsafe(no_mangle)]
170
pub extern "C" fn wasm_ref_as_trap_const(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_trap_t> {
171
abort("wasm_ref_as_trap_const")
172
}
173
174
#[derive(Clone)]
175
#[repr(C)]
176
pub struct wasm_foreign_t {}
177
178
wasmtime_c_api_macros::declare_ref!(wasm_foreign_t);
179
180
#[unsafe(no_mangle)]
181
pub extern "C" fn wasm_foreign_new(_store: &crate::wasm_store_t) -> Box<wasm_foreign_t> {
182
abort("wasm_foreign_new")
183
}
184
185
/// C-API representation of `anyref`.
186
///
187
/// This represented differently in the C API from the header to handle how
188
/// this is dispatched internally. Null anyref values are represented with a
189
/// `store_id` of zero, and otherwise the `rooted` field is valid.
190
///
191
/// Note that this relies on the Wasmtime definition of `OwnedRooted` to have
192
/// a 64-bit store_id first.
193
macro_rules! ref_wrapper {
194
($wasmtime:ident => $c:ident) => {
195
pub struct $c {
196
store_id: u64,
197
a: u32,
198
b: u32,
199
c: *const (),
200
}
201
202
impl $c {
203
pub unsafe fn as_wasmtime(&self) -> Option<OwnedRooted<$wasmtime>> {
204
let store_id = NonZeroU64::new(self.store_id)?;
205
Some(OwnedRooted::from_borrowed_raw_parts_for_c_api(
206
store_id, self.a, self.b, self.c,
207
))
208
}
209
210
pub unsafe fn from_wasmtime(self) -> Option<OwnedRooted<$wasmtime>> {
211
let store_id = NonZeroU64::new(self.store_id)?;
212
Some(OwnedRooted::from_owned_raw_parts_for_c_api(
213
store_id, self.a, self.b, self.c,
214
))
215
}
216
}
217
218
impl From<Option<OwnedRooted<$wasmtime>>> for $c {
219
fn from(rooted: Option<OwnedRooted<$wasmtime>>) -> $c {
220
let mut ret = $c {
221
store_id: 0,
222
a: 0,
223
b: 0,
224
c: core::ptr::null(),
225
};
226
if let Some(rooted) = rooted {
227
let (store_id, a, b, c) = rooted.into_parts_for_c_api();
228
ret.store_id = store_id.get();
229
ret.a = a;
230
ret.b = b;
231
ret.c = c;
232
}
233
ret
234
}
235
}
236
237
// SAFETY: The `*const ()` comes from (and is converted back
238
// into) an `Arc<()>`, and is only accessed as such, so this
239
// type is both Send and Sync. These constraints are necessary
240
// in the async machinery in this crate.
241
unsafe impl Send for $c {}
242
unsafe impl Sync for $c {}
243
};
244
}
245
246
ref_wrapper!(AnyRef => wasmtime_anyref_t);
247
ref_wrapper!(ExternRef => wasmtime_externref_t);
248
249
#[unsafe(no_mangle)]
250
pub unsafe extern "C" fn wasmtime_anyref_clone(
251
_cx: WasmtimeStoreContextMut<'_>,
252
anyref: Option<&wasmtime_anyref_t>,
253
out: &mut MaybeUninit<wasmtime_anyref_t>,
254
) {
255
let anyref = anyref.and_then(|a| a.as_wasmtime());
256
crate::initialize(out, anyref.into());
257
}
258
259
#[unsafe(no_mangle)]
260
pub unsafe extern "C" fn wasmtime_anyref_unroot(
261
_cx: WasmtimeStoreContextMut<'_>,
262
val: Option<&mut MaybeUninit<wasmtime_anyref_t>>,
263
) {
264
if let Some(val) = val.and_then(|v| v.assume_init_read().from_wasmtime()) {
265
drop(val);
266
}
267
}
268
269
#[unsafe(no_mangle)]
270
pub unsafe extern "C" fn wasmtime_anyref_to_raw(
271
cx: WasmtimeStoreContextMut<'_>,
272
val: Option<&wasmtime_anyref_t>,
273
) -> u32 {
274
val.and_then(|v| v.as_wasmtime())
275
.and_then(|e| e.to_raw(cx).ok())
276
.unwrap_or_default()
277
}
278
279
#[unsafe(no_mangle)]
280
pub unsafe extern "C" fn wasmtime_anyref_from_raw(
281
cx: WasmtimeStoreContextMut<'_>,
282
raw: u32,
283
val: &mut MaybeUninit<wasmtime_anyref_t>,
284
) {
285
let mut scope = RootScope::new(cx);
286
let anyref =
287
AnyRef::from_raw(&mut scope, raw).map(|a| a.to_owned_rooted(&mut scope).expect("in scope"));
288
crate::initialize(val, anyref.into());
289
}
290
291
#[unsafe(no_mangle)]
292
pub extern "C" fn wasmtime_anyref_from_i31(
293
cx: WasmtimeStoreContextMut<'_>,
294
val: u32,
295
out: &mut MaybeUninit<wasmtime_anyref_t>,
296
) {
297
let mut scope = RootScope::new(cx);
298
let anyref = AnyRef::from_i31(&mut scope, I31::wrapping_u32(val));
299
let anyref = anyref.to_owned_rooted(&mut scope).expect("in scope");
300
crate::initialize(out, Some(anyref).into())
301
}
302
303
#[unsafe(no_mangle)]
304
pub unsafe extern "C" fn wasmtime_anyref_i31_get_u(
305
cx: WasmtimeStoreContextMut<'_>,
306
anyref: Option<&wasmtime_anyref_t>,
307
dst: &mut MaybeUninit<u32>,
308
) -> bool {
309
match anyref.and_then(|a| a.as_wasmtime()) {
310
Some(anyref) if anyref.is_i31(&cx).expect("OwnedRooted always in scope") => {
311
let val = anyref
312
.unwrap_i31(&cx)
313
.expect("OwnedRooted always in scope")
314
.get_u32();
315
crate::initialize(dst, val);
316
true
317
}
318
_ => false,
319
}
320
}
321
322
#[unsafe(no_mangle)]
323
pub unsafe extern "C" fn wasmtime_anyref_i31_get_s(
324
cx: WasmtimeStoreContextMut<'_>,
325
anyref: Option<&wasmtime_anyref_t>,
326
dst: &mut MaybeUninit<i32>,
327
) -> bool {
328
match anyref.and_then(|a| a.as_wasmtime()) {
329
Some(anyref) if anyref.is_i31(&cx).expect("OwnedRooted always in scope") => {
330
let val = anyref
331
.unwrap_i31(&cx)
332
.expect("OwnedRooted always in scope")
333
.get_i32();
334
crate::initialize(dst, val);
335
true
336
}
337
_ => false,
338
}
339
}
340
341
#[unsafe(no_mangle)]
342
pub extern "C" fn wasmtime_externref_new(
343
cx: WasmtimeStoreContextMut<'_>,
344
data: *mut c_void,
345
finalizer: Option<extern "C" fn(*mut c_void)>,
346
out: &mut MaybeUninit<wasmtime_externref_t>,
347
) -> bool {
348
let mut scope = RootScope::new(cx);
349
let e = match ExternRef::new(&mut scope, crate::ForeignData { data, finalizer }) {
350
Ok(e) => e,
351
Err(_) => return false,
352
};
353
let e = e.to_owned_rooted(&mut scope).expect("in scope");
354
crate::initialize(out, Some(e).into());
355
true
356
}
357
358
#[unsafe(no_mangle)]
359
pub unsafe extern "C" fn wasmtime_externref_data(
360
cx: WasmtimeStoreContextMut<'_>,
361
externref: Option<&wasmtime_externref_t>,
362
) -> *mut c_void {
363
externref
364
.and_then(|e| e.as_wasmtime())
365
.and_then(|e| {
366
let data = e.data(cx).ok()??;
367
Some(data.downcast_ref::<crate::ForeignData>().unwrap().data)
368
})
369
.unwrap_or(ptr::null_mut())
370
}
371
372
#[unsafe(no_mangle)]
373
pub unsafe extern "C" fn wasmtime_externref_clone(
374
_cx: WasmtimeStoreContextMut<'_>,
375
externref: Option<&wasmtime_externref_t>,
376
out: &mut MaybeUninit<wasmtime_externref_t>,
377
) {
378
let externref = externref.and_then(|e| e.as_wasmtime());
379
crate::initialize(out, externref.into());
380
}
381
382
#[unsafe(no_mangle)]
383
pub unsafe extern "C" fn wasmtime_externref_unroot(
384
_cx: WasmtimeStoreContextMut<'_>,
385
val: Option<&mut MaybeUninit<wasmtime_externref_t>>,
386
) {
387
if let Some(val) = val.and_then(|v| v.assume_init_read().from_wasmtime()) {
388
drop(val);
389
}
390
}
391
392
#[unsafe(no_mangle)]
393
pub unsafe extern "C" fn wasmtime_externref_to_raw(
394
cx: WasmtimeStoreContextMut<'_>,
395
val: Option<&wasmtime_externref_t>,
396
) -> u32 {
397
val.and_then(|e| e.as_wasmtime())
398
.and_then(|e| e.to_raw(cx).ok())
399
.unwrap_or_default()
400
}
401
402
#[unsafe(no_mangle)]
403
pub unsafe extern "C" fn wasmtime_externref_from_raw(
404
cx: WasmtimeStoreContextMut<'_>,
405
raw: u32,
406
val: &mut MaybeUninit<wasmtime_externref_t>,
407
) {
408
let mut scope = RootScope::new(cx);
409
let rooted = ExternRef::from_raw(&mut scope, raw)
410
.map(|e| e.to_owned_rooted(&mut scope).expect("in scope"));
411
crate::initialize(val, rooted.into());
412
}
413
414