From 65378422bff127caed970eadb7bc9ac113d51335 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 27 Jul 2021 18:56:52 -0500 Subject: [PATCH] Add a `wasmtime_linker_define_func` C API function (#3122) This exposes the functionality of the `Linker` type where a store-independent function can be created and inserted, allowing a linker's functions to be used across many stores (instead of requiring one linker-per-store). Closes #3110 --- crates/c-api/include/wasmtime/linker.h | 35 ++++++++++++++++++++++++ crates/c-api/src/func.rs | 37 +++++++++++++++++--------- crates/c-api/src/linker.rs | 25 +++++++++++++++-- 3 files changed, 82 insertions(+), 15 deletions(-) diff --git a/crates/c-api/include/wasmtime/linker.h b/crates/c-api/include/wasmtime/linker.h index b8793a7878ac..09bc0bb10a24 100644 --- a/crates/c-api/include/wasmtime/linker.h +++ b/crates/c-api/include/wasmtime/linker.h @@ -80,6 +80,41 @@ WASM_API_EXTERN wasmtime_error_t* wasmtime_linker_define( const wasmtime_extern_t *item ); +/** + * \brief Defines a new function in this linker. + * + * \param linker the linker the name is being defined in. + * \param module the module name the item is defined under. + * \param module_len the byte length of `module` + * \param name the field name the item is defined under + * \param name_len the byte length of `name` + * \param ty the type of the function that's being defined + * \param cb the host callback to invoke when the function is called + * \param data the host-provided data to provide as the first argument to the callback + * \param finalizer an optional finalizer for the `data` argument. + * + * \return On success `NULL` is returned, otherwise an error is returned which + * describes why the definition failed. + * + * For more information about name resolution consult the [Rust + * documentation](https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Linker.html#name-resolution). + * + * Note that this function does not create a #wasmtime_func_t. This creates a + * store-independent function within the linker, allowing this function + * definition to be used with multiple stores. + */ +WASM_API_EXTERN wasmtime_error_t* wasmtime_linker_define_func( + wasmtime_linker_t *linker, + const char *module, + size_t module_len, + const char *name, + size_t name_len, + const wasm_functype_t *ty, + wasmtime_func_callback_t cb, + void *data, + void (*finalizer)(void*) +); + /** * \brief Defines WASI functions in this linker. * diff --git a/crates/c-api/src/func.rs b/crates/c-api/src/func.rs index ae76c3739676..1bfdc07b8dbd 100644 --- a/crates/c-api/src/func.rs +++ b/crates/c-api/src/func.rs @@ -9,7 +9,7 @@ use std::mem::MaybeUninit; use std::panic::{self, AssertUnwindSafe}; use std::ptr; use std::str; -use wasmtime::{AsContextMut, Caller, Extern, Func, Trap}; +use wasmtime::{AsContextMut, Caller, Extern, Func, Trap, Val}; #[derive(Clone)] #[repr(transparent)] @@ -187,25 +187,37 @@ pub struct wasmtime_caller_t<'a> { caller: Caller<'a, crate::StoreData>, } +pub type wasmtime_func_callback_t = extern "C" fn( + *mut c_void, + *mut wasmtime_caller_t, + *const wasmtime_val_t, + usize, + *mut wasmtime_val_t, + usize, +) -> Option>; + #[no_mangle] pub unsafe extern "C" fn wasmtime_func_new( store: CStoreContextMut<'_>, ty: &wasm_functype_t, - callback: extern "C" fn( - *mut c_void, - *mut wasmtime_caller_t, - *const wasmtime_val_t, - usize, - *mut wasmtime_val_t, - usize, - ) -> Option>, + callback: wasmtime_func_callback_t, data: *mut c_void, finalizer: Option, func: &mut Func, ) { - let foreign = crate::ForeignData { data, finalizer }; let ty = ty.ty().ty.clone(); - let f = Func::new(store, ty, move |caller, params, results| { + let cb = c_callback_to_rust_fn(callback, data, finalizer); + let f = Func::new(store, ty, cb); + *func = f; +} + +pub(crate) unsafe fn c_callback_to_rust_fn( + callback: wasmtime_func_callback_t, + data: *mut c_void, + finalizer: Option, +) -> impl Fn(Caller<'_, crate::StoreData>, &[Val], &mut [Val]) -> Result<(), Trap> { + let foreign = crate::ForeignData { data, finalizer }; + move |caller, params, results| { let params = params .iter() .cloned() @@ -234,8 +246,7 @@ pub unsafe extern "C" fn wasmtime_func_new( results[i] = unsafe { result.to_val() }; } Ok(()) - }); - *func = f; + } } #[no_mangle] diff --git a/crates/c-api/src/linker.rs b/crates/c-api/src/linker.rs index 280b15475af3..1b582b50c7f1 100644 --- a/crates/c-api/src/linker.rs +++ b/crates/c-api/src/linker.rs @@ -1,7 +1,9 @@ +use crate::func::c_callback_to_rust_fn; use crate::{ - bad_utf8, handle_result, wasm_engine_t, wasm_trap_t, wasmtime_error_t, wasmtime_extern_t, - wasmtime_module_t, CStoreContextMut, + bad_utf8, handle_result, wasm_engine_t, wasm_functype_t, wasm_trap_t, wasmtime_error_t, + wasmtime_extern_t, wasmtime_func_callback_t, wasmtime_module_t, CStoreContextMut, }; +use std::ffi::c_void; use std::mem::MaybeUninit; use std::str; use wasmtime::{Func, Instance, Linker}; @@ -54,6 +56,25 @@ pub unsafe extern "C" fn wasmtime_linker_define( handle_result(linker.define(module, name, item), |_linker| ()) } +#[no_mangle] +pub unsafe extern "C" fn wasmtime_linker_define_func( + linker: &mut wasmtime_linker_t, + module: *const u8, + module_len: usize, + name: *const u8, + name_len: usize, + ty: &wasm_functype_t, + callback: wasmtime_func_callback_t, + data: *mut c_void, + finalizer: Option, +) -> Option> { + let ty = ty.ty().ty.clone(); + let module = to_str!(module, module_len); + let name = to_str!(name, name_len); + let cb = c_callback_to_rust_fn(callback, data, finalizer); + handle_result(linker.linker.func_new(module, name, ty, cb), |_linker| ()) +} + #[cfg(feature = "wasi")] #[no_mangle] pub extern "C" fn wasmtime_linker_define_wasi(