diff --git a/crates/c-api/include/wasmtime.h b/crates/c-api/include/wasmtime.h index b37fbf81393d..ec8ba8897719 100644 --- a/crates/c-api/include/wasmtime.h +++ b/crates/c-api/include/wasmtime.h @@ -254,6 +254,32 @@ WASM_API_EXTERN own wasmtime_error_t *wasmtime_module_validate( const wasm_byte_vec_t *binary ); + +// Similar to `wasm_table_*`, except these explicitly operate on funcref tables +// and work with `wasm_func_t` values instead of `wasm_ref_t`. +WASM_API_EXTERN own wasmtime_error_t *wasmtime_funcref_table_new( + wasm_store_t *store, + const wasm_tabletype_t *element_ty, + wasm_func_t *init, + own wasm_table_t **table +); +WASM_API_EXTERN bool wasmtime_funcref_table_get( + const wasm_table_t *table, + wasm_table_size_t index, + own wasm_func_t **func +); +WASM_API_EXTERN own wasmtime_error_t *wasmtime_funcref_table_set( + wasm_table_t *table, + wasm_table_size_t index, + const wasm_func_t *value +); +WASM_API_EXTERN wasmtime_error_t *wasmtime_funcref_table_grow( + wasm_table_t *table, + wasm_table_size_t delta, + const wasm_func_t *init, + wasm_table_size_t *prev_size +); + #undef own #ifdef __cplusplus diff --git a/crates/c-api/src/func.rs b/crates/c-api/src/func.rs index 3c58d1ca46a3..879248b23bd5 100644 --- a/crates/c-api/src/func.rs +++ b/crates/c-api/src/func.rs @@ -63,7 +63,7 @@ impl wasm_func_t { } } - fn func(&self) -> &HostRef { + pub(crate) fn func(&self) -> &HostRef { match &self.ext.which { ExternHost::Func(f) => f, _ => unsafe { std::hint::unreachable_unchecked() }, @@ -75,6 +75,16 @@ impl wasm_func_t { } } +impl From> for wasm_func_t { + fn from(func: HostRef) -> wasm_func_t { + wasm_func_t { + ext: wasm_extern_t { + which: ExternHost::Func(func), + }, + } + } +} + fn create_function( store: &wasm_store_t, ty: &wasm_functype_t, @@ -97,11 +107,7 @@ fn create_function( } Ok(()) }); - Box::new(wasm_func_t { - ext: wasm_extern_t { - which: ExternHost::Func(HostRef::new(func)), - }, - }) + Box::new(HostRef::new(func).into()) } #[no_mangle] diff --git a/crates/c-api/src/table.rs b/crates/c-api/src/table.rs index a52b79048b53..21fe1a7aedf5 100644 --- a/crates/c-api/src/table.rs +++ b/crates/c-api/src/table.rs @@ -1,4 +1,4 @@ -use crate::wasm_ref_t; +use crate::{handle_result, wasm_func_t, wasm_ref_t, wasmtime_error_t}; use crate::{wasm_extern_t, wasm_store_t, wasm_tabletype_t, ExternHost}; use std::ptr; use wasmtime::{AnyRef, HostRef, Table, Val}; @@ -34,15 +34,14 @@ impl wasm_table_t { } #[no_mangle] -pub unsafe extern "C" fn wasm_table_new( +pub extern "C" fn wasm_table_new( store: &wasm_store_t, tt: &wasm_tabletype_t, - init: *mut wasm_ref_t, + init: Option>, ) -> Option> { - let init: Val = if !init.is_null() { - Box::from_raw(init).r.into() - } else { - Val::AnyRef(AnyRef::Null) + let init: Val = match init { + Some(init) => init.r.into(), + None => Val::AnyRef(AnyRef::Null), }; let table = Table::new(&store.store.borrow(), tt.ty().ty.clone(), init).ok()?; Some(Box::new(wasm_table_t { @@ -52,6 +51,30 @@ pub unsafe extern "C" fn wasm_table_new( })) } +#[no_mangle] +pub extern "C" fn wasmtime_funcref_table_new( + store: &wasm_store_t, + tt: &wasm_tabletype_t, + init: Option<&wasm_func_t>, + out: &mut *mut wasm_table_t, +) -> Option> { + let init: Val = match init { + Some(val) => Val::FuncRef(val.func().borrow().clone()), + None => Val::AnyRef(AnyRef::Null), + }; + handle_result( + Table::new(&store.store.borrow(), tt.ty().ty.clone(), init), + |table| { + *out = Box::into_raw(Box::new(wasm_table_t { + ext: wasm_extern_t { + which: ExternHost::Table(HostRef::new(table)), + }, + })); + println!("ret at {:?}", *out); + }, + ) +} + #[no_mangle] pub extern "C" fn wasm_table_type(t: &wasm_table_t) -> Box { let ty = t.table().borrow().ty(); @@ -59,16 +82,35 @@ pub extern "C" fn wasm_table_type(t: &wasm_table_t) -> Box { } #[no_mangle] -pub unsafe extern "C" fn wasm_table_get( - t: &wasm_table_t, - index: wasm_table_size_t, -) -> *mut wasm_ref_t { +pub extern "C" fn wasm_table_get(t: &wasm_table_t, index: wasm_table_size_t) -> *mut wasm_ref_t { match t.table().borrow().get(index) { Some(val) => into_funcref(val), None => into_funcref(Val::AnyRef(AnyRef::Null)), } } +#[no_mangle] +pub extern "C" fn wasmtime_funcref_table_get( + t: &wasm_table_t, + index: wasm_table_size_t, + ptr: &mut *mut wasm_func_t, +) -> bool { + println!("get {:p} at {}", t, index); + match t.table().borrow().get(index) { + Some(val) => { + *ptr = match val { + // TODO: what do do about creating new `HostRef` handles here? + Val::FuncRef(f) => Box::into_raw(Box::new(HostRef::new(f).into())), + Val::AnyRef(AnyRef::Null) => ptr::null_mut(), + _ => return false, + }; + } + + _ => return false, + } + true +} + #[no_mangle] pub unsafe extern "C" fn wasm_table_set( t: &wasm_table_t, @@ -79,7 +121,20 @@ pub unsafe extern "C" fn wasm_table_set( t.table().borrow().set(index, val).is_ok() } -unsafe fn into_funcref(val: Val) -> *mut wasm_ref_t { +#[no_mangle] +pub extern "C" fn wasmtime_funcref_table_set( + t: &wasm_table_t, + index: wasm_table_size_t, + val: Option<&wasm_func_t>, +) -> Option> { + let val = match val { + Some(val) => Val::FuncRef(val.func().borrow().clone()), + None => Val::AnyRef(AnyRef::Null), + }; + handle_result(t.table().borrow().set(index, val), |()| {}) +} + +fn into_funcref(val: Val) -> *mut wasm_ref_t { if let Val::AnyRef(AnyRef::Null) = val { return ptr::null_mut(); } @@ -114,6 +169,24 @@ pub unsafe extern "C" fn wasm_table_grow( t.table().borrow().grow(delta, init).is_ok() } +#[no_mangle] +pub extern "C" fn wasmtime_funcref_table_grow( + t: &wasm_table_t, + delta: wasm_table_size_t, + init: Option<&wasm_func_t>, + prev_size: Option<&mut wasm_table_size_t>, +) -> Option> { + let val = match init { + Some(val) => Val::FuncRef(val.func().borrow().clone()), + None => Val::AnyRef(AnyRef::Null), + }; + handle_result(t.table().borrow().grow(delta, val), |prev| { + if let Some(ptr) = prev_size { + *ptr = prev; + } + }) +} + #[no_mangle] pub extern "C" fn wasm_table_as_extern(t: &wasm_table_t) -> &wasm_extern_t { &t.ext