diff --git a/crates/c-api/include/wasmtime.h b/crates/c-api/include/wasmtime.h index 351b15433e..972dfb2f8e 100644 --- a/crates/c-api/include/wasmtime.h +++ b/crates/c-api/include/wasmtime.h @@ -515,8 +515,7 @@ typedef own wasm_trap_t* (*wasmtime_func_callback_t)(const wasmtime_caller_t* ca * * This function is the same as #wasm_func_callback_with_env_t except that its * first argument is a #wasmtime_caller_t which allows learning information - * about the - * caller. + * about the caller. */ typedef own wasm_trap_t* (*wasmtime_func_callback_with_env_t)(const wasmtime_caller_t* caller, void* env, const wasm_val_t args[], wasm_val_t results[]); @@ -544,6 +543,28 @@ WASM_API_EXTERN own wasm_func_t* wasmtime_func_new_with_env( void (*finalizer)(void*) ); +/** + * \brief Creates a new `funcref` value referencing `func`. + * + * Create a `funcref` value that references `func` and writes it to `funcrefp`. + * + * Gives ownership fo the `funcref` value written to `funcrefp`. + * + * Both `func` and `funcrefp` must not be NULL. + */ +WASM_API_EXTERN void wasmtime_func_as_funcref(const wasm_func_t* func, wasm_val_t* funcrefp); + +/** + * \brief Get the `wasm_func_t*` referenced by the given `funcref` value. + * + * Gets an owning handle to the `wasm_func_t*` that the given `funcref` value is + * referencing. Returns NULL if the value is not a `funcref`, or if the value is + * a null function reference. + * + * The `val` pointer must not be NULL. + */ +WASM_API_EXTERN own wasm_func_t* wasmtime_funcref_as_func(const wasm_val_t* val); + /** * \brief Loads a #wasm_extern_t from the caller's context * @@ -845,8 +866,10 @@ WASM_API_EXTERN wasmtime_error_t *wasmtime_funcref_table_grow( * 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. + * + * Gives ownership of the newly created `externref` value. */ -WASM_API_EXTERN void wasmtime_externref_new(void *data, wasm_val_t *valp); +WASM_API_EXTERN void wasmtime_externref_new(own void *data, wasm_val_t *valp); /** * \brief A finalizer for an `externref`'s wrapped data. @@ -866,9 +889,11 @@ typedef void (*wasmtime_externref_finalizer_t)(void*); * 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. + * + * Gives ownership of the newly created `externref` value. */ WASM_API_EXTERN void wasmtime_externref_new_with_finalizer( - void *data, + own void *data, wasmtime_externref_finalizer_t finalizer, wasm_val_t *valp ); @@ -887,7 +912,8 @@ WASM_API_EXTERN void wasmtime_externref_new_with_finalizer( * If the given value is not an `externref`, returns `false` and leaves `datap` * unmodified. * - * Does not take ownership of `val`. + * Does not take ownership of `val`. Does not give up ownership of the `void*` + * data written to `datap`. * * Both `val` and `datap` must not be `NULL`. */ diff --git a/crates/c-api/src/func.rs b/crates/c-api/src/func.rs index fe494dbbcb..5c63e9782f 100644 --- a/crates/c-api/src/func.rs +++ b/crates/c-api/src/func.rs @@ -6,7 +6,7 @@ use std::mem::MaybeUninit; use std::panic::{self, AssertUnwindSafe}; use std::ptr; use std::str; -use wasmtime::{Caller, Extern, Func, Trap}; +use wasmtime::{Caller, Extern, Func, Trap, Val}; #[derive(Clone)] #[repr(transparent)] @@ -275,3 +275,21 @@ pub extern "C" fn wasmtime_caller_export_get( let which = caller.caller.get_export(name)?; Some(Box::new(wasm_extern_t { which })) } + +#[no_mangle] +pub extern "C" fn wasmtime_func_as_funcref( + func: &wasm_func_t, + funcrefp: &mut MaybeUninit, +) { + let funcref = wasm_val_t::from_val(Val::FuncRef(Some(func.func().clone()))); + crate::initialize(funcrefp, funcref); +} + +#[no_mangle] +pub extern "C" fn wasmtime_funcref_as_func(val: &wasm_val_t) -> Option> { + if let Val::FuncRef(Some(f)) = val.val() { + Some(Box::new(f.into())) + } else { + None + } +} diff --git a/crates/c-api/src/table.rs b/crates/c-api/src/table.rs index c88620da85..6438f4976f 100644 --- a/crates/c-api/src/table.rs +++ b/crates/c-api/src/table.rs @@ -91,7 +91,7 @@ pub extern "C" fn wasm_table_get( index: wasm_table_size_t, ) -> Option> { let val = t.table().get(index)?; - Some(val_into_ref(val).unwrap()) + val_into_ref(val) } #[no_mangle] diff --git a/crates/c-api/src/val.rs b/crates/c-api/src/val.rs index 25754d4ed0..243df313f3 100644 --- a/crates/c-api/src/val.rs +++ b/crates/c-api/src/val.rs @@ -26,7 +26,9 @@ impl Drop for wasm_val_t { fn drop(&mut self) { match into_valtype(self.kind) { ValType::ExternRef => unsafe { - drop(Box::from_raw(self.of.ref_)); + if !self.of.ref_.is_null() { + drop(Box::from_raw(self.of.ref_)); + } }, _ => {} } @@ -116,7 +118,20 @@ impl wasm_val_t { ValType::I64 => Val::from(unsafe { self.of.i64 }), ValType::F32 => Val::from(unsafe { self.of.f32 }), ValType::F64 => Val::from(unsafe { self.of.f64 }), - ValType::ExternRef | ValType::FuncRef => ref_to_val(unsafe { &*self.of.ref_ }), + ValType::ExternRef => unsafe { + if self.of.ref_.is_null() { + Val::ExternRef(None) + } else { + ref_to_val(&*self.of.ref_) + } + }, + ValType::FuncRef => unsafe { + if self.of.ref_.is_null() { + Val::FuncRef(None) + } else { + ref_to_val(&*self.of.ref_) + } + }, _ => unimplemented!("wasm_val_t::val {:?}", self.kind), } }