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