From ab11fda1cea499b69e69e687ea03c19785e0e5b7 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Wed, 15 Jul 2020 16:38:44 -0700 Subject: [PATCH 1/5] wasmtime-c-api: Only drop non-null `*mut wasm_ref_t`s --- crates/c-api/src/val.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/c-api/src/val.rs b/crates/c-api/src/val.rs index 25754d4ed006..ade400d0d373 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_)); + } }, _ => {} } From 70ed6c2fa84a4f6ba195ba0f443ad94952b5e284 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Wed, 15 Jul 2020 16:39:34 -0700 Subject: [PATCH 2/5] wasmtime-c-api: Handle null refs in `wasm_val_t` to `Val` conversion --- crates/c-api/src/val.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/c-api/src/val.rs b/crates/c-api/src/val.rs index ade400d0d373..243df313f39d 100644 --- a/crates/c-api/src/val.rs +++ b/crates/c-api/src/val.rs @@ -118,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), } } From 1b00af9f14184505b4c7135e28ddcdb1e08c3146 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Wed, 15 Jul 2020 16:44:49 -0700 Subject: [PATCH 3/5] wasmtime-c-api: Don't unwrap and rewrap `Option`s The `unwrap` can panic, and there isn't any point to this unwrap+rewrap. --- crates/c-api/src/table.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/c-api/src/table.rs b/crates/c-api/src/table.rs index c88620da8587..6438f4976f39 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] From d4d41113a8ae17418b9a04ffb7d6a7cbf66527e0 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Wed, 15 Jul 2020 16:46:00 -0700 Subject: [PATCH 4/5] wasmtime-c-api: Add conversions between `funcref` and `wasm_func_t` --- crates/c-api/include/wasmtime.h | 23 +++++++++++++++++++++-- crates/c-api/src/func.rs | 20 +++++++++++++++++++- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/crates/c-api/include/wasmtime.h b/crates/c-api/include/wasmtime.h index eb6253b72804..45df16b5e91d 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,26 @@ 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`. + * + * 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 * diff --git a/crates/c-api/src/func.rs b/crates/c-api/src/func.rs index fe494dbbcb18..5c63e9782f4d 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 + } +} From 087ca3e02c2254f218baef636658f4d2d8ef8fd7 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Wed, 15 Jul 2020 16:51:12 -0700 Subject: [PATCH 5/5] wasmtime-c-api: More ownership documentation for `wasmtime.h` --- crates/c-api/include/wasmtime.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/c-api/include/wasmtime.h b/crates/c-api/include/wasmtime.h index 45df16b5e91d..c8bcca2f012f 100644 --- a/crates/c-api/include/wasmtime.h +++ b/crates/c-api/include/wasmtime.h @@ -548,6 +548,8 @@ WASM_API_EXTERN own wasm_func_t* wasmtime_func_new_with_env( * * 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); @@ -864,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. @@ -885,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 ); @@ -906,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`. */