wasmtime-c-api: Add Wasmtime-specific APIs for externrefs
This commit adds APIs to create new `externref` values (with and without finalizers) and to get an `externref`'s wrapped data.
This commit is contained in:
@@ -836,6 +836,60 @@ WASM_API_EXTERN wasmtime_error_t *wasmtime_funcref_table_grow(
|
|||||||
wasm_table_size_t *prev_size
|
wasm_table_size_t *prev_size
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Create a new `externref` value.
|
||||||
|
*
|
||||||
|
* Creates a new `externref` value wrapping the provided data.
|
||||||
|
*
|
||||||
|
* This function does not take an associated finalizer to clean up the data when
|
||||||
|
* the reference is reclaimed. If you need a finalizer to clean up the data,
|
||||||
|
* then use #wasmtime_externref_new_with_finalizer.
|
||||||
|
*/
|
||||||
|
WASM_API_EXTERN wasm_val_t wasmtime_externref_new(void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A finalizer for an `externref`'s wrapped data.
|
||||||
|
*
|
||||||
|
* A finalizer callback to clean up an `externref`'s wrapped data after the
|
||||||
|
* `externref` has been reclaimed. This is an opportunity to run destructors,
|
||||||
|
* free dynamically allocated memory, close file handles, etc.
|
||||||
|
*/
|
||||||
|
typedef void (*wasmtime_externref_finalizer_t)(void*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Create a new `externref` value with a finalizer.
|
||||||
|
*
|
||||||
|
* Creates a new `externref` value wrapping the provided data.
|
||||||
|
*
|
||||||
|
* When the reference is reclaimed, the wrapped data is cleaned up with the
|
||||||
|
* provided finalizer. If you do not need to clean up the wrapped data, then use
|
||||||
|
* #wasmtime_externref_new.
|
||||||
|
*/
|
||||||
|
WASM_API_EXTERN wasm_val_t wasmtime_externref_new_with_finalizer(
|
||||||
|
void *data,
|
||||||
|
wasmtime_externref_finalizer_t finalizer
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get an `externref`'s wrapped data
|
||||||
|
*
|
||||||
|
* If the given value is a reference to a non-null `externref`, writes the
|
||||||
|
* wrapped data that was passed into #wasmtime_externref_new or
|
||||||
|
* #wasmtime_externref_new_with_finalizer when creating the given `externref` to
|
||||||
|
* `datap`, and returns `true`.
|
||||||
|
*
|
||||||
|
* If the value is a reference to a null `externref`, writes `NULL` to `datap`
|
||||||
|
* and returns `true`.
|
||||||
|
*
|
||||||
|
* If the given value is not an `externref`, returns `false` and leaves `datap`
|
||||||
|
* unmodified.
|
||||||
|
*
|
||||||
|
* Does not take ownership of `val`.
|
||||||
|
*
|
||||||
|
* Both `val` and `datap` must not be `NULL`.
|
||||||
|
*/
|
||||||
|
WASM_API_EXTERN bool wasmtime_externref_data(wasm_val_t* val, void** datap);
|
||||||
|
|
||||||
#undef own
|
#undef own
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
use crate::wasm_val_t;
|
||||||
|
use std::any::Any;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
use std::ptr;
|
||||||
use wasmtime::{ExternRef, Func, Val};
|
use wasmtime::{ExternRef, Func, Val};
|
||||||
|
|
||||||
/// `*mut wasm_ref_t` is a reference type (`externref` or `funcref`), as seen by
|
/// `*mut wasm_ref_t` is a reference type (`externref` or `funcref`), as seen by
|
||||||
@@ -92,3 +95,60 @@ pub extern "C" fn wasm_ref_set_host_info_with_finalizer(
|
|||||||
eprintln!("`wasm_ref_set_host_info_with_finalizer` is not implemented");
|
eprintln!("`wasm_ref_set_host_info_with_finalizer` is not implemented");
|
||||||
std::process::abort();
|
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 {
|
||||||
|
wasm_val_t::from_val(Val::ExternRef(Some(ExternRef::new(CExternRef {
|
||||||
|
data,
|
||||||
|
finalizer: 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user