152 lines
4.3 KiB
Rust
152 lines
4.3 KiB
Rust
use crate::wasm_val_t;
|
|
use std::any::Any;
|
|
use std::os::raw::c_void;
|
|
use std::ptr;
|
|
use wasmtime::{ExternRef, Func, Val};
|
|
|
|
/// `*mut wasm_ref_t` is a reference type (`externref` or `funcref`), as seen by
|
|
/// the C API. Because we do not have a uniform representation for `funcref`s
|
|
/// and `externref`s, a `*mut wasm_ref_t` is morally a
|
|
/// `Option<Box<Either<Option<ExternRef>, Option<Func>>>>`.
|
|
///
|
|
/// A null `*mut wasm_ref_t` is either a null `funcref` or a null `externref`
|
|
/// depending on context (e.g. the table's element type that it is going into or
|
|
/// coming out of).
|
|
///
|
|
/// Note: this is not `#[repr(C)]` because it is an opaque type in the header,
|
|
/// and only ever referenced as `*mut wasm_ref_t`. This also lets us use a
|
|
/// regular, non-`repr(C)` `enum` to define `WasmRefInner`.
|
|
#[derive(Clone)]
|
|
pub struct wasm_ref_t {
|
|
pub(crate) r: WasmRefInner,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub(crate) enum WasmRefInner {
|
|
ExternRef(Option<ExternRef>),
|
|
FuncRef(Option<Func>),
|
|
}
|
|
|
|
wasmtime_c_api_macros::declare_own!(wasm_ref_t);
|
|
|
|
pub(crate) fn ref_into_val(r: Option<Box<wasm_ref_t>>) -> Option<Val> {
|
|
// Let callers decide whether to treat this as a null `funcref` or a
|
|
// null `externref`.
|
|
let r = r?;
|
|
|
|
Some(match r.r {
|
|
WasmRefInner::ExternRef(x) => Val::ExternRef(x),
|
|
WasmRefInner::FuncRef(x) => Val::FuncRef(x),
|
|
})
|
|
}
|
|
|
|
pub(crate) fn ref_to_val(r: &wasm_ref_t) -> Val {
|
|
match &r.r {
|
|
WasmRefInner::ExternRef(x) => Val::ExternRef(x.clone()),
|
|
WasmRefInner::FuncRef(x) => Val::FuncRef(x.clone()),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn val_into_ref(val: Val) -> Option<Box<wasm_ref_t>> {
|
|
match val {
|
|
Val::ExternRef(x) => Some(Box::new(wasm_ref_t {
|
|
r: WasmRefInner::ExternRef(x),
|
|
})),
|
|
Val::FuncRef(x) => Some(Box::new(wasm_ref_t {
|
|
r: WasmRefInner::FuncRef(x),
|
|
})),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_ref_copy(r: &wasm_ref_t) -> Box<wasm_ref_t> {
|
|
Box::new(r.clone())
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_ref_same(a: &wasm_ref_t, b: &wasm_ref_t) -> bool {
|
|
match (&a.r, &b.r) {
|
|
(WasmRefInner::ExternRef(Some(a)), WasmRefInner::ExternRef(Some(b))) => a.ptr_eq(b),
|
|
(WasmRefInner::ExternRef(None), WasmRefInner::ExternRef(None)) => true,
|
|
// Note: we don't support equality for `Func`, so we always return
|
|
// `false` for `funcref`s.
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_ref_get_host_info(_ref: &wasm_ref_t) -> *mut c_void {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_ref_set_host_info(_ref: &wasm_ref_t, _info: *mut c_void) {
|
|
eprintln!("`wasm_ref_set_host_info` is not implemented");
|
|
std::process::abort();
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasm_ref_set_host_info_with_finalizer(
|
|
_ref: &wasm_ref_t,
|
|
_info: *mut c_void,
|
|
_finalizer: Option<extern "C" fn(*mut c_void)>,
|
|
) {
|
|
eprintln!("`wasm_ref_set_host_info_with_finalizer` is not implemented");
|
|
std::process::abort();
|
|
}
|
|
|
|
type wasmtime_externref_finalizer_t = extern "C" fn(*mut c_void);
|
|
|
|
struct CExternRef {
|
|
data: *mut c_void,
|
|
finalizer: Option<wasmtime_externref_finalizer_t>,
|
|
}
|
|
|
|
impl Drop for CExternRef {
|
|
fn drop(&mut self) {
|
|
if let Some(f) = self.finalizer {
|
|
f(self.data);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasmtime_externref_new(data: *mut c_void) -> wasm_val_t {
|
|
wasmtime_externref_new_with_finalizer(data, None)
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasmtime_externref_new_with_finalizer(
|
|
data: *mut c_void,
|
|
finalizer: Option<wasmtime_externref_finalizer_t>,
|
|
) -> wasm_val_t {
|
|
wasm_val_t::from_val(Val::ExternRef(Some(ExternRef::new(CExternRef {
|
|
data,
|
|
finalizer,
|
|
}))))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn wasmtime_externref_data(val: &wasm_val_t, datap: *mut *mut c_void) -> bool {
|
|
match val.val() {
|
|
Val::ExternRef(None) => {
|
|
unsafe {
|
|
ptr::write(datap, ptr::null_mut());
|
|
}
|
|
true
|
|
}
|
|
Val::ExternRef(Some(x)) => {
|
|
let data = match x.data().downcast_ref::<CExternRef>() {
|
|
Some(r) => r.data,
|
|
None => x.data() as *const dyn Any as *mut c_void,
|
|
};
|
|
unsafe {
|
|
ptr::write(datap, data);
|
|
}
|
|
true
|
|
}
|
|
_ => false,
|
|
}
|
|
}
|